i18n 规范
本规范参考 momei 项目的国际化治理体系(
translation-governance.md/i18n.md)适配而成,聚焦 dependfix 的 README 多语言、docs 翻译与平台 UI 国际化三条链路。
1. 目标与适用范围
本规范定义 dependfix 多语言文档与产品词条的协作规则,目标是避免出现"页面已翻译、系统链路未补齐、质量门禁未覆盖"的半完成语言。
适用范围包括:
- README 多语言版本(
README.md中文原版 +README.en-US.md等翻译版) - 文档站公开页面(
docs/中文原版 +docs/i18n/<locale>/翻译版) - 管理平台 UI 词条(
apps/platform/i18n/locales/<locale>.json) - 与语言发布相关的回退策略与质量门禁
2. 语言发布分级
新增语言采用分级准入:
draft:仅允许本地验证,不进入公开语言切换入口。ui-ready:完成核心 UI、语言入口、回退链和基础质量校验,可公开展示。seo-ready:在ui-ready基础上补齐邮件、SEO、站点地图与回归检查,可作为正式全球语言发布。
发布原则:
- 默认先接入
ui-ready,避免一次性追求全量翻译。 - 没有通过回归校验的语言,不得升级为
seo-ready。 - 快速迭代模块允许暂时回退到中文原文,但必须在文档与待办中明确标注。
2.1 文档翻译 freshness 分层
文档翻译按页面职责分层治理,不统一按"所有页面都必须 30 天内同步"处理:
| Tier | freshness 口径 | 允许内容形态 | 当前典型范围 |
|---|---|---|---|
must-sync | 30 天 | 面向公开入口的操作等价翻译 | en-US 首页、快速开始、README |
summary-sync | 45 天 | 摘要同步,保留原文回链 | 路线图摘要、核心高频规范页 |
source-only | 不做天数 SLA,但必须显式声明"中文事实源优先" | 保留 locale URL 的入口页,不承诺持续维护正文 | 低频设计页、低频 Guide、深层 Standards |
补充约束:
source-only页面必须显式提供中文原文入口,不允许保留看起来像完整翻译、实际上已长期失新的旧正文。source-only页面不得继续占据 locale 导航和侧边栏主入口,避免用户误判维护承诺范围。summary-sync页面允许结构摘要化,但必须覆盖本轮已经进入质量门、导航主入口或贡献流程的关键变化点。
2.2 当前 locale 文档范围
| Locale | 当前承诺范围 |
|---|---|
en-US | 公开入口页保持 must-sync;路线图、开发指南与核心高频规范页保持 summary-sync;设计页、低频 Guide 降为 source-only |
3. 平台 UI 国际化
3.1 语言标识规范
项目内部统一采用 BCP 47 风格区域码作为唯一业务规范:
zh-CN(简体中文,默认)en-US(英文)
后续扩展候选:zh-TW(繁体中文)、ko-KR(韩文)、ja-JP(日文)。
规范要求:
apps/platform/i18n/locales/<locale>.json文件名必须使用这套标识。apps/platform/nuxt.config.ts的i18n.locales配置、语言切换器、服务端翻译装配都必须以这套标识为准。- 文件名使用完整区域码(
en-US.json),code字段可保持短码(en)用于 URL 前缀,两者映射见apps/platform/i18n/localeDetector.ts。
3.2 回退链
缺词时按以下回退链解析:
| Locale | fallbackChain |
|---|---|
zh-CN | zh-CN |
en-US | en-US -> zh-CN |
zh-TW(未来) | zh-TW -> zh-CN -> en-US |
ko-KR(未来) | ko-KR -> en-US -> zh-CN |
zh-TW 与 zh-CN 语义最接近,缺词优先回退简体中文;ko-KR 的 UI 缺词优先回退英文,减少机器感过强的中文兜底。
3.3 文案归属层级
- 页面私有:只服务单一页面或单一流程的词条,保留在对应页面命名空间(如
alerts.*、repos.*)。 - 模块共享:同一业务模块下多个页面复用的词条,收敛到该模块共享命名空间(如
common.actions.*)。 - 全局共享:跨模块稳定复用的按钮、状态、提示和壳层文案,放在
common命名空间。 - 禁止为了减少翻译工作量,让公共页长期引用后台页面 key,或让后台页直接复用公共页私有 key。
- 在决定是否上收到共享命名空间前,先运行
pnpm i18n:audit:duplicates。该脚本只标记"所有扫描语言里翻译签名完全一致"的重复候选,避免因为单语种撞词就误判为可复用文案。 - 审计结果只提供候选,不直接等于应该抽取;是否提取到共享命名空间,仍要结合组件职责、加载边界和未来演进方向逐条判断。
3.X locale 文件 insert anchor 必须用目标 locale 文本(M25.4 阶段实证)
locale 文件多段对称(zh-CN.json + en-US.json),insert anchor 必须用目标 locale 实际文本(如 en-US 段必须用 loadFailed: "Failed to load: {message}" 英文 anchor;zh-CN 段必须用 loadFailed: "加载失败:{message}" 中文 anchor)。
根因:JSON.parse 容忍重复键 last-key-wins,anchor 错位导致后续段被改写但前端无 lint 检测 i18n 字段语义。M24.1 Phase 4 B1 实证:en-US.json alerts.errors.loadFailed 被中文污染("加载失败:{message}")—— 本次 en PRCheck 段 insert anchor 用 zh-CN 中文文本,导致 en-US 段尾部被改写。集成测试 + 视觉测试前无法发现。
修复模式:
- 双向检测(en-US ↔ zh-CN):
scripts/i18n-anchor-check.mjs(M25.4 commit80912c2落地)覆盖 (a) 正常态——en-US/zh-CN 键集相同 + 文本不同;(b) 异常态——en-US/zh-CN anchor 用错位文本;(c) 异常态——en-US 段尾部某字段值与 zh-CN 相同(locale 错位污染);(d) 值 locale 区分度(任意 code 在 zh-CN locale 取值 ≠ en-US locale 取值是"对称态";两者相等是"错位污染") - CI 集成:
.github/workflows/test.ymlstep 9 跑pnpm run i18n:anchor-check——本批 CI 步骤新增不破坏现有check:docs/lint:md/typecheck链路 - zod-helpers 配套:
apps/platform/server/utils/zod-helpers.tsparseOptional<T>(schema, query, fieldName): { success: boolean, value?: T, isProvided: boolean }helper 强制三态语义(testing.md §6 失败处理后段)
详见 经验归档 §六十一 M25.4 i18n-anchor-check 工具化 + 经验归档 §五十六 M24.1 教训 2/5。
4. README 多语言规范
- 中文原版固定为
README.md,翻译版使用README.<locale>.md命名(如README.en-US.md)。 - 每个语言版本头部必须包含语言切换链接区,指向全部已发布语言版本。
- README 属于
must-sync层级,翻译版必须跟随原版结构变化同步更新,不得长期滞后。
5. 术语约束
翻译时遵循以下约束:
- 保留产品名、协议名、云厂商名与主流技术名:如
GitHub、Dependabot、pnpm、TypeORM。 - 同一术语在同一语言中保持统一,不允许同页混用不同译法。
locale、fallback、readiness等治理术语优先与现有设计文档保持一致。- 繁体中文必须避免残留简体字;韩语页面避免用英文占位直接暴露给 UI。
推荐在提交前抽样检查以下高风险词:
- 文案状态词:启用、停用、发布、审核、失败、成功
- 设置键名:仓库、凭据、扫描、告警、定时、批量、同步
6. 贡献流程
6.1 开始前
- 明确目标语言与阶段目标:是补齐
ui-ready,还是推进到seo-ready。 - 检查对应模块是否已有 locale 文件、README 版本和文档目录。
- 在 todo.md 中更新当前阶段状态,避免重复劳动。
6.2 翻译中
- 优先补高频路径:首页、认证、设置、后台关键链路。
- 新增文档页时,优先同步首页、快速开始和 README。
- 翻译文档的物理路径统一落在
docs/i18n/<locale>/,对外文档站 URL 继续保持/<locale>/...。 - 合并前必须通过
pnpm docs:check:i18n;若发现旧目录(docs/<locale>/)回流,或同一翻译页同时存在于旧目录与docs/i18n/<locale>/,视为阻塞问题,禁止继续提交。 - 若某页决定降为
source-only,必须同步更新页面正文、Frontmatter、locale 导航范围与翻译治理说明,不能只在脚本里豁免。 - 若某模块暂不翻译,需保留原文来源说明,而不是留空或放英文占位。
6.3 提交前
至少执行以下校验:
pnpm lint:md:check
pnpm docs:check:i18n
pnpm lint
pnpm typecheck涉及平台 locale 词条变更时,额外执行:
pnpm i18n:audit:missing
pnpm i18n:audit:unused涉及文档翻译时,额外执行:
pnpm docs:check:i18n6.4 Blocker 入口与最小检查矩阵
pnpm i18n:audit:missing 的口径统一为"缺词 parity blocker":
| 场景 | 必跑命令 | blocker 判定 |
|---|---|---|
| 日常 i18n 代码改动 | pnpm i18n:audit:missing | 只要本次变更触及 apps/platform/i18n/locales/** 或共享组件命名空间,缺词就按本次 Review Gate blocker 处理 |
| 发版前 / 阶段收口 | CI 的 i18n:audit:missing 步骤 | 失败直接阻断发版 |
| docs 翻译变更 | pnpm docs:check:i18n | 旧目录回流或重复翻译页即阻塞,禁止提交 |
pnpm i18n:audit:unused 的口径统一为 warning / cleanup candidate,不直接阻断 release 或阶段收口。只有当本次任务目标本身就是"删除旧 key、收敛未使用文案、证明某模块可安全裁剪"时,才把 unused 结果升级为当前任务的必过检查。
i18n 相关改动的最小检查矩阵统一如下:
| 改动类型 | 最小检查矩阵 |
|---|---|
| 仅补 locale 文案 | pnpm i18n:audit:missing + pnpm lint:i18n |
| locale 模块注册、运行时加载、共享组件跨页面复用 | 上述命令 + pnpm i18n:audit:duplicates |
| 文案复用 / 命名空间收敛 | 上述命令 + pnpm i18n:audit:duplicates + pnpm i18n:audit:unused |
| 文档翻译 | pnpm docs:check:i18n + pnpm lint:md:check |
| 发版前或阶段收口 | CI 全部 i18n 步骤通过 |
7. 回归检查清单
每轮语言扩展完成后,按以下顺序回归:
- 语言切换入口是否可见,且能正确切换 locale。
- 公共页面、后台关键页面是否仍有明显未翻译占位。
pnpm i18n:audit:missing是否通过,且无缺失 key。- 文档站对应语言首页与快速开始页是否可访问。
pnpm docs:check:i18n是否通过,无旧目录回流或重复翻译页。
8. PR / 交付说明建议
提交翻译相关变更时,说明中建议包含:
- 本轮新增或补齐的语言与模块
- 是否新增 README / 文档站翻译页面
- 已执行的校验命令与结果
- 仍未覆盖的模块或已知残留