Files
keyboard/docs/multi-language-keyboard-architecture.md
2026-03-02 09:19:06 +08:00

336 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 多语言 + 多布局 + 默认皮肤联动技术分析与架构方案
## 1. 需求摘要
你最终要的功能是:
1. 用户在主 App 切换国家/语言。
2. 如果该语言有多个键盘布局(如西班牙语 QWERTY / AZERTY / QWERTZ点击语言后进入布局选择页。
3. 选择布局时,页面展示该语言对应键盘布局预览。
4. 切换语言时,自动下发该国家默认皮肤(例如英文 -> 西班牙语,自动应用西班牙默认皮肤)。
## 2. 现有代码现状分析
### 2.1 多语言系统(已具备基础能力)
1. 语言管理集中在 `KBLocalizationManager`支持运行时切换、App 与扩展共享。
2. 当前默认支持语言只有 `en``zh-Hans`
3. 主 App 启动时会设置 `supportedLanguageCodes`
关键代码位置:
1. `/Users/mac/Desktop/项目/公司/KeyBoard/Shared/KBLocalizationManager.h`
2. `/Users/mac/Desktop/项目/公司/KeyBoard/Shared/KBLocalizationManager.m`
3. `/Users/mac/Desktop/项目/公司/KeyBoard/keyBoard/AppDelegate.m`
当前限制:
1. 语言常量只有 `KBLanguageCodeEnglish``KBLanguageCodeSimplifiedChinese`
2. `Localizable.strings` 目前只有 `en``zh-Hans` 两套。
3. 工程 `knownRegions` 仅包含 `en``zh-Hans``Base`
---
### 2.2 键盘布局系统(已具备 JSON 驱动,但尚未按“语言+变体”建模)
1. 扩展键盘布局配置由 `kb_keyboard_layout_config.json` 驱动。
2. `KBKeyboardView` 通过 `KBKeyboardLayoutConfig` 读取 `letters / numbers / symbolsMore` 布局并构建按键。
3. 当前布局名是固定三套,不带语言维度。
关键代码位置:
1. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/Model/KBKeyboardLayoutConfig.h`
2. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/Model/KBKeyboardLayoutConfig.m`
3. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/Resource/kb_keyboard_layout_config.json`
4. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/View/KBKeyboardView.m`
当前限制:
1. `KBKeyboardView` 当前布局选择逻辑只区分字母/数字/符号页,不区分输入语言。
2. `buildKeysForLettersLayout` 里仍保留了 QWERTY 兜底硬编码路径。
---
### 2.3 主 App 设置入口(可扩展)
1. `KBPersonInfoVC` 是现有“设置”页面,可作为语言入口的落点。
2. 该页面当前有三行:昵称、性别、用户 ID。
关键代码位置:
1. `/Users/mac/Desktop/项目/公司/KeyBoard/keyBoard/Class/Me/VC/KBPersonInfoVC.m`
2. `/Users/mac/Desktop/项目/公司/KeyBoard/keyBoard/Class/Me/V/KBPersonInfoItemCell.m`
结论:
1. 最小侵入方案是直接在 `KBPersonInfoVC` 增加“Language / Keyboard Layout”行和跳转逻辑不需要额外改主流程导航。
---
### 2.4 皮肤系统(已具备跨进程下发能力)
1. `KBSkinManager` 负责应用主题并通过 Darwin 通知同步到扩展。
2. `KBSkinInstallBridge` 负责发布“待安装皮肤请求”、扩展侧消费并应用。
3. 扩展 `KeyboardViewController+Theme` 已监听并消费皮肤安装通知,且有默认皮肤兜底逻辑。
关键代码位置:
1. `/Users/mac/Desktop/项目/公司/KeyBoard/Shared/KBSkinManager.m`
2. `/Users/mac/Desktop/项目/公司/KeyBoard/Shared/KBSkinInstallBridge.m`
3. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Theme.m`
当前限制:
1. `pendingRequest` 只有单槽位(同一时刻只能保留一条待消费皮肤请求)。
2. 默认皮肤逻辑目前由扩展按系统明暗自动判断,不包含“按语言自动默认皮肤”策略。
---
### 2.5 与新语言相关的隐含影响点
1. 联想词引擎与 trailing-word 提取仅识别 `a-z`,会影响西语/葡语重音字母。
2. 部分 locale 转换逻辑仍是二分(中文/英文),例如 `KBMyVM``fetchCancelAccountWarningWithCompletion`
3. 个别网络模块存在硬编码 `Accept-Language`
关键代码位置:
1. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/Manager/KBSuggestionEngine.m`
2. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Suggestions.m`
3. `/Users/mac/Desktop/项目/公司/KeyBoard/keyBoard/Class/Me/VM/KBMyVM.m`
4. `/Users/mac/Desktop/项目/公司/KeyBoard/CustomKeyboard/Network/NetworkStreamHandler.m`
## 3. 目标架构(核心原则)
## 3.1 核心原则
1. **展示语言****输入语言/布局** 解耦。
2. 语言切换是“偏好中心事件”,布局与皮肤都由该事件驱动。
3. 皮肤优先级明确,避免覆盖用户主动选择。
4. 保持现有 JSON 布局机制,不推翻 `KBKeyboardView` 主体。
## 3.2 模块划分
建议新增以下共享模块(放 `Shared`,主 App 与扩展都可用):
1. `KBInputLanguageProfileManager`
2. `KBKeyboardLayoutPreferenceManager`
3. `KBDefaultSkinPolicyManager`
### 3.2.1 KBInputLanguageProfileManager语言元数据中心
职责:
1. 维护每个语言的能力描述(是否多布局、默认布局、默认皮肤 ID、布局列表
2. 提供给主 App 设置页和扩展布局解析器统一读取。
建议数据模型JSON/Plist 均可):
1. `languageCode`
2. `displayNameKey`
3. `supportsMultipleLayouts`
4. `layoutVariants`
5. `defaultLayoutVariant`
6. `defaultSkinId`
7. `defaultSkinZipName`
示例(结构示意):
```json
{
"es": {
"supportsMultipleLayouts": true,
"layoutVariants": ["qwerty", "azerty", "qwertz"],
"defaultLayoutVariant": "qwerty",
"defaultSkinId": "lang_es_default",
"defaultSkinZipName": "lang_es_default"
},
"pt": {
"supportsMultipleLayouts": false,
"layoutVariants": ["qwerty"],
"defaultLayoutVariant": "qwerty",
"defaultSkinId": "lang_pt_default",
"defaultSkinZipName": "lang_pt_default"
}
}
```
### 3.2.2 KBKeyboardLayoutPreferenceManager语言/布局偏好持久化)
职责:
1. 存储用户当前输入语言与布局变体。
2. 提供“切换语言后自动决定下一步”的能力。
3. App 与扩展通过 App Group 共享。
建议存储键App Group
1. `KBPref_InputLanguageCode`
2. `KBPref_LayoutVariantByLanguage`(字典)
3. `KBPref_CurrentLayoutVariant`
4. `KBPref_UpdatedAt`
通知建议:
1. 进程内通知:`KBKeyboardPreferenceDidChangeNotification`
2. Darwin 通知:`com.loveKey.nyx.keyboard.preference.changed`
### 3.2.3 KBDefaultSkinPolicyManager默认皮肤策略
职责:
1. 在语言切换时决定是否自动套用默认皮肤。
2. 防止覆盖用户主动自定义皮肤。
建议策略:
1. 记录 `skinSource``language_default` / `user_selected` / `shop_downloaded` / `system_default`
2. 仅当当前皮肤来源是 `language_default``system_default` 时,语言切换可自动覆盖。
3. 若当前皮肤来源为 `user_selected`,默认不自动覆盖,除非产品要求强制覆盖。
## 4. 主流程设计
## 4.1 主 App语言切换流程
1. 用户在设置页选择语言(例如西班牙语)。
2. 写入 `KBLocalizationManager`UI 文案语言切换)。
3. 查询 `KBInputLanguageProfileManager`
4.`supportsMultipleLayouts = YES`,跳转布局选择页。
5.`supportsMultipleLayouts = NO`,直接写默认布局并结束。
6. 布局选择完成后,写 `KBKeyboardLayoutPreferenceManager`
7. 触发默认皮肤策略,必要时发布皮肤安装请求给扩展。
## 4.2 主 App布局选择页新页面
页面职责:
1. 展示该语言可选布局(西班牙语 3 选 1
2. 展示对应键盘预览(可复用 `kb_keyboard_layout_config.json` 生成静态预览,或使用简化绘制)。
3. 点击保存后写偏好并返回。
建议页面命名:
1. `KBKeyboardLayoutSelectVC`
## 4.3 键盘扩展:偏好生效流程
1. `viewWillAppear` 读取共享偏好(现有已读取语言,可在此处同时读取布局偏好)。
2. `KBKeyboardView` 通过 Resolver 决定当前要用的 `letters layout name`
3. 调用 `reloadKeys` 重建按键。
4. 若收到偏好变更通知(进程内/Darwin动态刷新当前键盘。
## 4.4 皮肤联动流程
1. 主 App 语言切换后,根据 profile 取 `defaultSkinId/defaultSkinZipName`
2. 调用 `KBSkinInstallBridge publishBundleSkinRequestWithId` 发布请求。
3. 扩展侧现有 Darwin observer 会消费请求并应用皮肤。
4. 键盘立即主题刷新(现有链路已具备)。
## 5. 键盘布局建模升级方案
## 5.1 JSON 扩展方式
不改 `KBKeyboardLayoutConfig` 的基础结构,只扩展 `layouts` 命名约定:
1. `letters_es_qwerty`
2. `letters_es_azerty`
3. `letters_es_qwertz`
4. `letters_pt_qwerty`
5. `letters_id_qwerty`
6. `letters_zh_hant_qwerty`(若繁体沿用 QWERTY
数字与符号可先复用:
1. `numbers`
2. `symbolsMore`
## 5.2 Resolver 规则
新增 `KBKeyboardLayoutResolver`
1. 输入参数:`languageCode + layoutVariant + panelType`
2. 输出布局名:
3. 字母面板:`letters_<lang>_<variant>`
4. 数字/符号:先复用现有 `numbers/symbolsMore`
回退链:
1. `letters_<lang>_<variant>`
2. `letters_<lang>_qwerty`
3. `letters`
4. legacy当前已存在
## 6. UI 与交互建议(结合现有代码)
## 6.1 设置入口落点
直接在 `KBPersonInfoVC` 的 section0 新增两行:
1. `Language`
2. `Keyboard Layout`(仅多布局语言显示,单布局语言可隐藏或置灰显示默认值)
优势:
1. 改动集中在已有设置页,不新增复杂入口链路。
2. 能快速验证需求闭环。
## 6.2 预览实现建议
1. 第一阶段:静态预览图(开发快,风险低)。
2. 第二阶段:用同一份 layout JSON 动态绘制预览(与真实键盘一致性最高)。
## 7. 风险与约束
1. `KBSkinInstallBridge` 的 pending request 是单槽位,语言切换与商城皮肤下载并发时可能互相覆盖。
2. 当前扩展默认皮肤逻辑会在某些时机自动执行,需要避免与你的“语言默认皮肤”策略冲突。
3. 联想词和字符识别是英文字母集合,西语/葡语输入体验会受影响。
4. locale 透传接口当前存在中文/英文二分逻辑,新增语言后需统一改造为映射表。
## 8. 分阶段实施计划
## 阶段 A基础设施
1. 扩展 `KBLocalizationManager` 支持 `es / pt / zh-Hant / id`
2. 增加 4 套本地化资源并加入工程 region。
3. 新建 `KBInputLanguageProfileManager` 与配置文件。
## 阶段 B设置页与偏好持久化
1. 新建 `KBKeyboardLayoutPreferenceManager`
2.`KBPersonInfoVC` 增加语言入口。
3. 新建布局选择页与预览页。
## 阶段 C扩展键盘接入
1. 新建 `KBKeyboardLayoutResolver`
2. `KBKeyboardView` 切换为按 Resolver 选布局名。
3. 为西班牙语补三套 `letters` 布局定义。
## 阶段 D默认皮肤联动
1. 新建 `KBDefaultSkinPolicyManager`
2. 语言切换后根据 profile 下发默认皮肤请求。
3. 引入 `skinSource` 防止覆盖用户自定义皮肤。
## 阶段 E体验完善
1. 联想词与字符集支持重音字符。
2. 统一 locale 映射(网络、订阅文案、接口参数)。
3. 并发请求队列化(解决 pending 单槽位冲突)。
## 9. 测试建议
1. 切换语言后 UI 文案是否全量生效(主 App + 扩展)。
2. 西班牙语三布局切换是否即时生效。
3. 语言切换时默认皮肤是否按策略生效。
4. 用户自定义皮肤是否不会被错误覆盖。
5. 扩展冷启动、前后台、键盘切换场景下偏好一致性。
6. App Group 不可用/完全访问关闭时的降级行为。
## 10. 我建议的落地架构结论
1. 保留现有三大基座:`KBLocalizationManager``KBKeyboardLayoutConfig``KBSkinInstallBridge`
2. 新增“语言 profile + 偏好管理 + 皮肤策略”三层,作为编排层。
3. 先打通“西班牙语多布局”闭环,再批量扩展到葡语/繁体/印尼语。
4. 先保证正确性与一致性,再优化联想词与并发策略。