mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-08-16 15:49:46 +00:00
* refactor: render chat rows from presentation state * Fix Meshtastic channel sync and add MeshCore CN preset * Add granular chat notification settings * Add SD settings backup and restore * Prepare 0.1.26-alpha release --------- Co-authored-by: vicliu624 <vicliu@outlook.com>
652 lines
22 KiB
Markdown
652 lines
22 KiB
Markdown
# Localization Specification
|
||
|
||
## 1. Why This Document Exists
|
||
|
||
本文件不是翻译指南,也不是打包教程。
|
||
|
||
本文件的目标是把 Trail Mate 的“本地化系统”定义成一个有边界的对象,防止后续开发再次把以下东西混在一起:
|
||
|
||
- 固件里的 i18n 运行时
|
||
- SD / Flash 上的 runtime pack 载荷
|
||
- 仓库中的 `packs/<bundle-id>/` 源包
|
||
- GitHub Pages 发布出来的 zip 分发包
|
||
- 远程 catalog 元数据
|
||
- 已安装索引 `installed.json`
|
||
- “换语言”这个用户动作
|
||
|
||
如果这些对象不被区分,系统就会退化成“改了几行英文字符串,再补几条 tsv”的低解释力状态。
|
||
|
||
---
|
||
|
||
## 2. Current Distinctions
|
||
|
||
### 2.1 当前必须切开的对象
|
||
|
||
Trail Mate 本地化系统至少由八类对象组成:
|
||
|
||
1. 固件本地化运行时
|
||
2. Runtime pack 载荷
|
||
3. 仓库源包
|
||
4. 分发包
|
||
5. 远程 catalog
|
||
6. 已安装索引
|
||
7. locale 质量状态
|
||
8. 输入法运行时后端
|
||
|
||
它们彼此相关,但不是同一个东西。
|
||
|
||
### 2.2 非法混淆
|
||
|
||
以下切法在本规格下视为非法:
|
||
|
||
1. 把 `strings.tsv` 直接当成“本地化系统本体”。
|
||
2. 把 zip 分发包当成运行时直接消费的对象。
|
||
3. 把“安装了某语言包”误认为“该字体已经加载进 RAM”。
|
||
4. 把固件版本和语言包版本绑成同一个版本号。
|
||
5. 把英文源串当成“只是文案”,而不是翻译查找 key。
|
||
6. 把页面私有字符串补丁当成合法的本地化实现。
|
||
7. 把 `docs/ui_localization_plan.md` 这种历史方案继续当成现行契约。
|
||
8. 把繁简转换当成繁中本地化。
|
||
9. 把 `zh-Hant` 当成一个不需要地区语境的抽象繁体中文。
|
||
10. 把拼音当成所有中文使用者的默认输入法。
|
||
11. 把“机器翻译已经填满 TSV”当成可发布质量。
|
||
12. 把英文 key 原样复制到翻译列,当成合法的缺省翻译。
|
||
|
||
---
|
||
|
||
## 3. Object Model
|
||
|
||
### 3.1 固件本地化运行时
|
||
|
||
固件运行时负责:
|
||
|
||
1. 持有内建英文基线。
|
||
2. 扫描、编目并解析可用的 locale / font / IME pack manifest。
|
||
3. 根据 `display_locale` 选择活动 locale。
|
||
4. 维护 UI font chain 与 content font chain。
|
||
5. 在需要时惰性加载外部 `font.bin`。
|
||
6. 提供 `tr()`、`format()`、`set_label_text()` 等统一入口。
|
||
7. 在外部 pack 缺失、不可用或超出设备能力时安全回退。
|
||
|
||
它不负责:
|
||
|
||
1. 读取 zip 分发包。
|
||
2. 直接理解网站 catalog。
|
||
3. 把“语言包安装”与“当前 locale 激活”混成同一动作。
|
||
|
||
### 3.2 Runtime Pack 载荷
|
||
|
||
Runtime pack 载荷是运行时真正扫描和消费的已解包目录树。
|
||
|
||
当前形态包括:
|
||
|
||
1. Flash 安装根
|
||
- ` /fs/trailmate/packs/... `,用于 Arduino/ESP32 上的安装器写入
|
||
2. SD 安装根
|
||
- ` /trailmate/packs/... `,用于手工拷贝或可移动介质安装
|
||
|
||
运行时理解的是“解包后的 manifest + strings/ranges/font.bin”,而不是 zip。
|
||
|
||
### 3.3 仓库源包
|
||
|
||
仓库中的 `packs/<bundle-id>/` 是源码形态,不是运行时形态。
|
||
|
||
它可以包含:
|
||
|
||
1. `package.ini`
|
||
2. `README.md`
|
||
3. `DESCRIPTION.txt`
|
||
4. runtime manifests
|
||
5. `strings.tsv`
|
||
6. `build.ini`
|
||
7. `charset.txt`
|
||
8. `ranges.txt`
|
||
9. 可选的本地 `font.bin`
|
||
|
||
其中 `build.ini`、`charset.txt` 这类文件属于构建期元数据,运行时不读取。
|
||
|
||
### 3.4 分发包
|
||
|
||
分发包是面向安装器与网站分发的 zip 产物,不是运行时直接扫描的对象。
|
||
|
||
它当前由 `scripts/build_pack_repository.py` 生成,并包含:
|
||
|
||
1. 顶层包元数据
|
||
2. `payload/fonts/...`
|
||
3. `payload/locales/...`
|
||
4. `payload/ime/...`
|
||
|
||
安装器的职责是下载 zip、校验 SHA-256、解出 `payload/`,再写入 runtime pack 根目录。
|
||
|
||
### 3.5 远程 Catalog
|
||
|
||
远程 catalog 是“可下载 bundle 的索引”,不是运行时 registry。
|
||
|
||
它负责提供:
|
||
|
||
1. package id
|
||
2. package version
|
||
3. `min_firmware_version`
|
||
4. `supported_memory_profiles`
|
||
5. 提供了哪些 locale/font/IME
|
||
6. archive 路径、大小、SHA-256
|
||
7. Extensions 页面所需的展示元数据
|
||
|
||
它不负责:
|
||
|
||
1. 字体加载
|
||
2. locale 激活
|
||
3. zip 内文件解析
|
||
|
||
### 3.6 已安装索引
|
||
|
||
已安装索引记录“安装过哪些分发包”,而不是“当前有哪些 locale 被激活”。
|
||
|
||
当前安装索引的职责是记录:
|
||
|
||
1. package id
|
||
2. package version
|
||
3. archive SHA-256
|
||
4. storage
|
||
5. install time
|
||
|
||
在当前 Arduino/ESP32 实现中,主安装索引默认写入 Flash 安装根下的 `installed.json`。
|
||
历史 SD 路径可以作为迁移兼容来源存在,但不应再被当成新的规范落点。
|
||
|
||
它不能替代 runtime registry,也不能替代 locale persistence。
|
||
|
||
### 3.7 Locale 质量状态
|
||
|
||
locale 质量状态描述的是“这个语言包现在能不能作为用户可选语言出现”,不是描述字体是否存在,也不是描述包是否可以被 catalog 发现。
|
||
|
||
当前状态值固定为:
|
||
|
||
1. `release`
|
||
- 可以出现在语言选择器中。
|
||
- 必须完成 native 或项目负责人认可的质量审查。
|
||
- 不得包含英文补偿项,除非该项是明确允许保留的技术名词、协议名、单位或格式占位串。
|
||
2. `review`
|
||
- 字符串表结构完整,通常已经被批量翻译或人工初审过。
|
||
- 仍然需要母语审校、地区用语审校、输入法语义审校。
|
||
- 运行时必须跳过,不得出现在普通用户语言选择器中。
|
||
3. `draft`
|
||
- 可以缺 key、混用语言、缺少地区用语审查。
|
||
- 运行时必须跳过。
|
||
|
||
为了兼容旧包,省略 `translation_status` 的历史 locale 视为 `release`。新包不应再省略该字段。
|
||
|
||
### 3.8 输入法运行时后端
|
||
|
||
IME pack manifest 只是输入法后端的声明,不是后端本身。
|
||
|
||
一个输入法要成为可启用输入法,必须同时满足:
|
||
|
||
1. 固件中存在真实后端。
|
||
2. 候选词、组合逻辑、提交行为与目标语言/地区习惯匹配。
|
||
3. UI widget 知道如何展示该输入模式。
|
||
4. locale manifest 显式依赖它,且该 locale 已经是可发布质量。
|
||
|
||
因此,不允许用 `backend=builtin-kana`、`backend=builtin-hangul`、`backend=builtin-arabic` 这类尚未实现的名字提前占位。未实现输入法可以写进规划文档,但不能作为 runtime IME pack 进入 payload。
|
||
|
||
---
|
||
|
||
## 4. Core Contracts
|
||
|
||
### 4.1 English Source String Is API
|
||
|
||
英文源串不是随手写的文案,它是翻译查找 key。
|
||
|
||
这意味着:
|
||
|
||
1. `ui::i18n::tr(const char* english)` 的输入是稳定 key,而不是“仅供显示的默认英文”。
|
||
2. 修改英文源串,会直接改变 key。
|
||
3. 一旦 key 改变,所有 locale pack 中对应条目都会失配并回退到英文。
|
||
4. `strings.tsv` 中同一 English key 不允许承载两套不同语义。
|
||
5. `strings.tsv` 的行顺序不构成语义;运行时按 English key 查找,而不是按文件顺序查找。
|
||
|
||
因此,下列操作都属于本地化契约变化:
|
||
|
||
1. 修改现有英文源串文本
|
||
2. 拆分一条英文源串为多条
|
||
3. 把一条英文源串合并为另一条
|
||
4. 改变 format string 结构,例如 `%s` / `%u` / 换行符位置
|
||
|
||
它们都不能被当成“只改 UI 文案”的低风险改动。
|
||
|
||
### 4.2 Locale / Font / IME Dependency Graph
|
||
|
||
依赖图固定为:
|
||
|
||
1. `Locale Pack -> UI Font Pack`
|
||
2. `Locale Pack -> Content Font Pack`
|
||
3. `Locale Pack -> Optional IME Pack`
|
||
4. `Content Text -> Optional Supplement Font Packs`
|
||
|
||
Settings 选择的是 locale,不是 font,不是 IME。
|
||
|
||
页面或设置页不允许绕过 locale 直接定义另一套“选字体/选输入法”主流程。
|
||
|
||
### 4.2.1 Locale ID 必须表达地区语境
|
||
|
||
locale id 必须按 BCP-47 思路表达语言、脚本与地区语境,而不是只表达字形。
|
||
|
||
推荐形态:
|
||
|
||
1. `zh-Hans-CN`
|
||
- 简体中文,中国大陆用语。
|
||
2. `zh-Hant-TW`
|
||
- 繁体中文,台湾地区用语。
|
||
3. `zh-Hant-HK`
|
||
- 繁体中文,香港地区用语。
|
||
4. `pt-PT`
|
||
- 葡萄牙语,葡萄牙地区用语。
|
||
5. `pt-BR`
|
||
- 葡萄牙语,巴西地区用语。
|
||
|
||
当前仓库中的 `zh-Hant` 是历史兼容 id,语义必须按 `zh-Hant-TW` 处理;后续如果引入香港、澳门或其他繁中地区包,必须新增独立 locale,而不是继续复用 `zh-Hant`。
|
||
|
||
禁止把 OpenCC 或其他繁简转换结果直接作为 `release` 级繁中包。转换最多用于生成初稿;发布前必须检查地区用词、标点、语气、技术名词和输入法习惯。
|
||
|
||
### 4.2.2 翻译质量闸门
|
||
|
||
运行时 locale catalog 必须执行质量闸门:
|
||
|
||
1. `translation_status=release`
|
||
- 允许进入运行时 locale 列表。
|
||
2. 缺省 `translation_status`
|
||
- 为兼容旧包,暂按 `release` 处理。
|
||
3. `translation_status=review`
|
||
- 可以被安装、索引、更新,但运行时必须跳过。
|
||
4. `translation_status=draft`
|
||
- 可以作为开发资料存在,但运行时必须跳过。
|
||
5. 其他未知状态
|
||
- 运行时必须按不可发布处理并跳过。
|
||
|
||
一个 release 语言包不得出现以下情况:
|
||
|
||
1. 空翻译。
|
||
2. 缺失当前 English key 集合中的 key。
|
||
3. `%s`、`%u`、`%ld`、`\\n` 等占位符或转义符不一致。
|
||
4. 大量英文 key 原样复制到翻译列。
|
||
5. 混入另一种语言的翻译文本,例如日文包中出现简体中文句子。
|
||
6. 地区用语明显不匹配,例如台湾繁中使用大陆软件术语作为主用语。
|
||
|
||
允许保持英文的项目只限于明确的专名、协议名、单位、测量标签、格式骨架,例如 `GPS`、`RSSI`、`dBm`、`RNode`、`LXMF`、`ID: !%08lX`。
|
||
|
||
### 4.2.3 输入法必须跟 locale 习惯绑定
|
||
|
||
输入法不是“有一个能打字的键盘”这么简单。它属于 locale 的语言、脚本和地区习惯。
|
||
|
||
当前可启用输入法只有:
|
||
|
||
1. `zh-Hans` / `zh-Hans-CN`
|
||
- `zh-hans-pinyin`
|
||
- 后端:`builtin-pinyin`
|
||
- 适用范围:简体中文拼音输入。
|
||
|
||
当前不得启用的输入法包括:
|
||
|
||
1. `zh-Hant` / `zh-Hant-TW`
|
||
- 不得默认拼音。
|
||
- 未来优先级应是注音(Bopomofo / Zhuyin)。
|
||
- 可选扩展可考虑仓颉、速成、台湾常见拼音输入,但必须明确标注,不得冒充默认习惯。
|
||
2. `ja`
|
||
- 需要假名/罗马字到假名与汉字候选的日文输入模型。
|
||
- 不得复用中文拼音候选器。
|
||
3. `ko`
|
||
- 需要韩文两벌式等韩文输入模型。
|
||
- 不得复用中文或日文输入模型。
|
||
4. `ar`
|
||
- 需要阿拉伯键盘、RTL 编辑语义与字体 shaping 一致性。
|
||
5. 欧洲 Latin 语言
|
||
- 通常不需要 IME pack;现有 `EN` / `123` 输入路径足够。
|
||
|
||
如果某 locale 还没有真实输入法,它可以作为 display-only review 包存在,但不得把假 IME 写进 manifest,也不得让设置页显示一个无法工作的输入法选项。
|
||
|
||
### 4.3 Built-In Baseline
|
||
|
||
固件必须始终保留最小内建基线:
|
||
|
||
1. 内建 locale:`en`
|
||
2. 内建字体:`builtin-latin-ui`
|
||
3. 内建 IME:可为空
|
||
|
||
English 必须在没有任何外部 pack 的情况下仍可工作。
|
||
|
||
这条基线不能被 removable pack 破坏。
|
||
|
||
### 4.4 Installed Is Not Loaded
|
||
|
||
`Installed` 与 `Loaded` 是两个不同状态:
|
||
|
||
1. Installed
|
||
- pack manifest 存在于 Flash/SD
|
||
- runtime registry 能发现它
|
||
2. Loaded
|
||
- 外部 `font.bin` 已经实际加载进 RAM
|
||
- 会产生即时内存占用
|
||
|
||
禁止把“安装成功”实现成“开机即把所有外部字体全部加载”。
|
||
|
||
### 4.5 UI Scope vs Content Scope
|
||
|
||
本地化运行时必须继续维持两条字体链:
|
||
|
||
1. UI chain
|
||
- 页面 chrome
|
||
- 菜单、按钮、标题、设置项等
|
||
2. Content chain
|
||
- 联系人名
|
||
- 节点名
|
||
- 聊天内容
|
||
- 其他外部文本
|
||
|
||
这两条链不能被简化成“只要非 ASCII 就统一切换某个 CJK 字体”的旁路实现。
|
||
|
||
### 4.6 Persistence Contract
|
||
|
||
当前 locale 的持久化 key 是:
|
||
|
||
1. namespace:`settings`
|
||
2. key:`display_locale`
|
||
3. value:locale id string
|
||
|
||
`display_language` 只是历史迁移键,只允许用于一次性迁移,不得再作为现行设计继续扩展。
|
||
|
||
### 4.7 Discovery Contract
|
||
|
||
运行时 registry 只扫描“已解包 runtime pack”。
|
||
|
||
它不扫描:
|
||
|
||
1. zip
|
||
2. 远程 JSON catalog
|
||
3. 仓库里的 `build.ini`
|
||
4. 构建期 charset 生成元数据
|
||
|
||
如果一个 pack 只存在于网站 zip 中、还没解到运行时目录,那它对运行时来说就是不存在。
|
||
|
||
### 4.8 Installation Contract
|
||
|
||
安装器层与运行时层必须分离。
|
||
|
||
安装器负责:
|
||
|
||
1. 拉取 catalog
|
||
2. 下载 zip
|
||
3. 校验 SHA-256
|
||
4. 解压 `payload/`
|
||
5. 更新 installed index
|
||
6. 触发 `reload_language()`
|
||
|
||
运行时负责:
|
||
|
||
1. 重新扫描可用 pack
|
||
2. 解析 manifest / strings / ranges
|
||
3. 重新选择 active locale
|
||
4. 按需加载字体
|
||
|
||
当前 Arduino/ESP32 安装器默认把下载得到的 payload 解到 Flash pack 根。
|
||
与此同时,手工把 runtime payload 拷贝到 SD 仍然是合法安装方式,因为运行时会同时编目当前支持的 Flash/SD 根。
|
||
|
||
禁止让运行时 registry 直接承担网络下载或 zip 解释职责。
|
||
|
||
### 4.9 Failure And Fallback Contract
|
||
|
||
本地化失败时必须退回到可解释状态,而不是把系统带入半失效状态。
|
||
|
||
当前允许的失败行为包括:
|
||
|
||
1. locale 缺少依赖 font pack
|
||
- 跳过该 locale
|
||
2. locale 缺少依赖 IME pack
|
||
- 跳过该 locale
|
||
3. 当前设备 memory profile 无法承受 locale 成本
|
||
- 跳过该 locale
|
||
4. 持久化的 locale id 不再可解析
|
||
- 回退到 `en`
|
||
5. 某个 content supplement 无法加载
|
||
- 页面继续存活
|
||
- 个别文字可出现缺字
|
||
|
||
禁止因为一个外部包损坏而让整个 UI 失去最小英语可用能力。
|
||
|
||
---
|
||
|
||
## 5. Versioning And Compatibility Contract
|
||
|
||
### 5.1 Firmware Version 与 Package Version 必须分离
|
||
|
||
固件版本与语言包版本不是同一个版本号体系。
|
||
|
||
它们的职责不同:
|
||
|
||
1. 固件版本
|
||
- 描述运行时代码能力
|
||
2. package version
|
||
- 描述 bundle 载荷与元数据版本
|
||
|
||
不能因为固件升级一次,就机械把所有语言包 version 同步改掉。
|
||
也不能因为语言包换了翻译文本,就伪造一次固件版本升级。
|
||
|
||
### 5.2 `min_firmware_version` 的语义
|
||
|
||
`min_firmware_version` 是下界,不是“必须完全相等”的绑定版本。
|
||
|
||
它表示:
|
||
|
||
1. 低于这个固件版本,当前 bundle 语义可能无法被正确理解
|
||
2. 高于或等于这个版本,可以认为运行时至少理解这份 bundle 契约
|
||
|
||
它不表示:
|
||
|
||
1. 这个 bundle 只能给某一个固件版本使用
|
||
2. 每次小翻译更新都必须改 `min_firmware_version`
|
||
|
||
### 5.3 `supported_memory_profiles` 的语义
|
||
|
||
`supported_memory_profiles` 描述的是设备能力兼容边界,不是语言偏好。
|
||
|
||
它影响:
|
||
|
||
1. Extensions 页展示是否兼容
|
||
2. 某设备是否应被允许安装/更新该 bundle
|
||
|
||
它不能被拿来表达:
|
||
|
||
1. 用户喜欢哪种语言
|
||
2. 当前 locale 是否被激活
|
||
|
||
### 5.4 更新判定
|
||
|
||
当前“是否有更新”以 package record 为单位判定,至少比较:
|
||
|
||
1. version
|
||
2. archive SHA-256
|
||
|
||
因此,哪怕 version 不变,只要 archive 内容变了,也可能被视为不同包。
|
||
|
||
这意味着偷偷改 zip 内容而不更新包版本,是危险的发布行为。
|
||
|
||
### 5.5 兼容性 gating 的归属
|
||
|
||
兼容性 gating 当前属于“安装/发现层”的职责,主要体现在 catalog 解析和 Extensions UI。
|
||
|
||
但运行时仍必须对手工拷贝到 Flash/SD 的 payload 保持鲁棒:
|
||
|
||
1. 不兼容 pack 可以被发现
|
||
2. 依赖不满足时可以跳过
|
||
3. 系统仍需回退到 English 基线
|
||
|
||
禁止把系统安全性完全建立在“用户一定只会通过 Extensions 正规安装”这个假设上。
|
||
|
||
### 5.6 语言包版本必须表达用户可见变化
|
||
|
||
语言包版本不是装饰字段。只要用户安装后看到的文字、可用 locale、可用 IME、字体覆盖或质量状态发生变化,就必须 bump package version。
|
||
|
||
最低要求:
|
||
|
||
1. 只修正少量错别字或补少量漏翻
|
||
- bump patch,例如 `1.0.0 -> 1.0.1`。
|
||
2. 大量补齐字符串、改写地区用语、改变 `translation_status`、移除假 IME、改变默认输入法依赖
|
||
- bump minor,例如 `1.0.0 -> 1.1.0`。
|
||
3. 改变 payload 布局或 manifest 语义,导致旧运行时可能错误理解
|
||
- bump `min_firmware_version`,并视情况 bump minor 或 major。
|
||
|
||
发布语言包更新时必须同时重建:
|
||
|
||
1. zip archive。
|
||
2. `site/data/packs.json`。
|
||
3. archive SHA-256。
|
||
4. installed/update comparison 所需的 package metadata。
|
||
|
||
否则用户看不到更新,或者看到更新却无法解释更新内容。
|
||
|
||
---
|
||
|
||
## 6. Change Classification
|
||
|
||
### 6.1 固件改动但通常不要求语言包跟随变化
|
||
|
||
以下改动通常不要求语言包更新:
|
||
|
||
1. 纯逻辑修复,不引入新的用户可见文本
|
||
2. 不改变 manifest schema 的运行时重构
|
||
3. 不改变翻译 key 的内部实现优化
|
||
4. 不改变字体需求的布局调整
|
||
|
||
### 6.2 固件改动后通常要求更新语言包字符串
|
||
|
||
以下改动通常要求至少更新一个或多个 locale pack:
|
||
|
||
1. 新增用户可见英文源串
|
||
2. 删除旧源串并引入新源串
|
||
3. 修改旧英文源串文本
|
||
4. 修改 format string 参数结构
|
||
5. 修改带转义字符的字符串结构,例如 `\n`
|
||
|
||
### 6.3 固件改动后可能要求更新字体包
|
||
|
||
以下改动不仅可能改 `strings.tsv`,还可能要求重建 font pack:
|
||
|
||
1. 新翻译文本引入当前字体未覆盖的新字形
|
||
2. `native_name` 改动引入新字形
|
||
3. 新 IME 字典或候选字集引入新字形
|
||
4. 新增 locale/self-name/设置项文本导致 charset 扩展
|
||
|
||
一旦字形覆盖变化,至少要同步处理:
|
||
|
||
1. `charset.txt`
|
||
2. `ranges.txt`
|
||
3. `font.bin`
|
||
4. `estimated_ram_bytes`
|
||
|
||
### 6.4 固件改动后必须提高 `min_firmware_version`
|
||
|
||
以下改动属于 bundle 契约变化,必须考虑提高 `min_firmware_version`:
|
||
|
||
1. manifest schema 新增运行时必需字段
|
||
2. 现有 manifest 字段语义改变
|
||
3. runtime 对 bundle 布局的期望发生变化
|
||
4. catalog / archive / installed index 语义发生不兼容变化
|
||
5. locale/font/IME 依赖规则发生不兼容变化
|
||
|
||
### 6.5 只改语言包也必须 bump package version
|
||
|
||
以下情况即使不改固件,也应 bump package version:
|
||
|
||
1. `strings.tsv` 变化
|
||
2. `manifest.ini` 变化
|
||
3. `ranges.txt` 变化
|
||
4. `font.bin` 变化
|
||
5. `package.ini` 中影响安装或兼容性的字段变化
|
||
|
||
否则 installed index 与 update check 将失去解释力。
|
||
|
||
---
|
||
|
||
## 7. Release Obligations
|
||
|
||
### 7.1 固件改动合入前必须回答的问题
|
||
|
||
1. 这次是否新增了用户可见英文源串?
|
||
2. 这次是否改动了现有英文 key?
|
||
3. 这次是否改变了 format string 结构?
|
||
4. 这次是否引入了新字形需求?
|
||
5. 这次是否改变了 manifest / package / catalog 契约?
|
||
|
||
只要上述任一答案为“是”,就不能只提交固件代码而不审视语言包。
|
||
|
||
### 7.2 语言包发布前必须回答的问题
|
||
|
||
1. `package version` 是否已反映 payload 变化?
|
||
2. 如有契约变化,`min_firmware_version` 是否已提高?
|
||
3. `font.bin` 是否与 `charset.txt` / `ranges.txt` / manifest 保持一致?
|
||
4. `estimated_ram_bytes` 是否仍真实反映生成结果?
|
||
5. `site/data/packs.json` 与 zip 产物是否已重建?
|
||
6. `translation_status` 是否符合真实质量?
|
||
7. release 包是否已经通过空值、缺 key、重复 key、占位符一致性检查?
|
||
8. release 包是否已经清除英文补偿项?
|
||
9. 该 locale 的地区用语是否经过明确审查?
|
||
10. 该 locale 的 IME 依赖是否真实可用,而不是占位后端?
|
||
|
||
### 7.3 新 locale 合入前必须满足的最小条件
|
||
|
||
1. English 基线不被破坏。
|
||
2. locale manifest 依赖完整。
|
||
3. 对应 font pack 的 RAM 成本可被当前目标 memory profile 解释。
|
||
4. 运行时目录布局、分发包布局、catalog 元数据三者一致。
|
||
5. 手工安装与 Extensions 安装都不会把系统带离 English 回退能力。
|
||
6. 默认 `translation_status` 不得伪装成 release;未审校语言必须先进入 `review` 或 `draft`。
|
||
7. 输入法要么真实可用,要么不写进 locale manifest。
|
||
8. 如果 locale 是地区敏感语言,例如繁体中文或葡萄牙语,必须明确地区语境。
|
||
|
||
---
|
||
|
||
## 8. Prohibited Implementations
|
||
|
||
以下实现方式在本规格下明确禁止:
|
||
|
||
1. 继续引入新的整数语言枚举作为主持久化键。
|
||
2. 页面直接绕过 `ui::i18n` 写死另一套翻译逻辑。
|
||
3. 通过“检测到非 ASCII 就随便切某个字体”来替代 locale/font chain。
|
||
4. 把 zip 当运行时 pack 根目录。
|
||
5. 改了英文源串却不把它当成 key 变化处理。
|
||
6. 改了翻译文本所需字形,却不重建相关字体包。
|
||
7. 改了 bundle payload,却不 bump package version。
|
||
8. 改了 bundle 契约,却不调整 `min_firmware_version`。
|
||
9. 让不兼容或损坏的 pack 破坏 English 最小基线。
|
||
10. 用机器翻译或繁简转换结果直接发布 release 包。
|
||
11. 在没有真实后端时发布 IME manifest 或 locale `ime_pack` 依赖。
|
||
12. 给台湾繁中默认启用拼音输入法。
|
||
13. release 语言包中保留大面积英文补偿项。
|
||
|
||
---
|
||
|
||
## 9. Relationship To Other Documents
|
||
|
||
本文件是规范性文档。
|
||
|
||
如果与其他文档冲突,优先级如下:
|
||
|
||
1. `docs/LOCALIZATION_SPEC.md`
|
||
2. `docs/specs/LOCALE_PACK_RELEASE_SPEC.md`
|
||
3. `docs/LOCALE_PACKS.md`
|
||
4. 各 `packs/<bundle-id>/README.md`
|
||
5. `docs/ui_localization_plan.md`
|
||
|
||
其中:
|
||
|
||
1. `docs/LOCALE_PACKS.md`
|
||
- 负责解释 pack 机制、布局和字段
|
||
2. `docs/specs/LOCALE_PACK_RELEASE_SPEC.md`
|
||
- 负责解释打包、发布、版本、catalog、archive 与更新可见性
|
||
3. `docs/ui_localization_plan.md`
|
||
- 仅保留历史演进价值,不再作为当前设计依据
|
||
|
||
---
|
||
|
||
## 10. One-Sentence Baseline
|
||
|
||
Trail Mate 的本地化不是“固件里几条翻译表”,而是“以 English key 为稳定接口、以 locale/font/IME pack 为显式依赖、以安装层与运行时层分离为前提、并允许固件与语言包独立演进但受兼容契约约束”的完整系统。
|