336 lines
12 KiB
Markdown
336 lines
12 KiB
Markdown
# 多语言 + 多布局 + 默认皮肤联动技术分析与架构方案
|
||
|
||
## 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. 先保证正确性与一致性,再优化联想词与并发策略。
|
||
|