Files
lucky_shop/scripts/I18N_AUDIT.md
ZF sun f37baad045 feat(i18n): add full i18n audit toolchain and pre-commit hook
- 新增 GitHub Actions 工作流实现 PR 时自动审计国际化内容
- 添加 pre-commit 钩子,提交前自动检查相关文件并拦截问题提交
- 编写完整的 i18n 审计脚本、文档与示例报告
- 实现多维度国际化校验:键匹配、占位符、data()误用、硬编码标题等
2026-07-04 09:57:43 +08:00

4.4 KiB

i18n 审计流程

把所有"$lang 是否能正常翻译"的检查收口到一个入口: 新增组件 / 新增翻译 / 拉取新 bundle.json 之后,跑这一个命令就能出报告。

快速开始

# 标准体检(最常用)
python scripts/i18n_audit.py

# 严格模式 — 出现真问题就 exit 1,适合 CI / pre-commit hook
python scripts/i18n_audit.py --strict

# 拉了新 bundle.json(覆盖了 lang-bundle.json),指定新的:
python scripts/i18n_audit.py --bundle ./lang-bundle.2026-07-04.json

报告结束时会输出:

  健康度评分:
    ✓ 99.95% 翻译覆盖,0 个真问题
    或
    ! 存在 N 类问题需要修:
      - <类目 1>
      - <类目 2>

完整结构化报告写到 scripts/lang_audit_report_v2.json,适合 diff 或后续处理。

它在做什么(7 个检查)

# 检查维度 暴露什么问题 真实程度
1 静态 $lang(key) 字面 → bundle leaf key 字符串不存在于 bundle 直接失效
2 占位符参数匹配 key 含 {name} 但调用没传 { name: ... },运行时会字面显示 {name} 直接失效
3 data() 中误用 data() { return { x: this.$lang(...) } } 在 mp/鸿蒙 remote-only 模式下会永久缓存空串 远程首屏失效
4 bundle ↔ 本地 lang drift lang/zh-cn/... 有的 key,bundle 没有(可能影响兜底) 加载策略变更时显现
5 pages.json 硬编码导航标题 navigationBarTitleText: "商品分类",运行时必须 lang.refresh() 兜底 取决于 refresh() 调用时机
6 i18n-lazy mixin 使用情况 哪些组件没遵循延迟初始化约定 标记数据风险点
7 P2 动态 key (verify-p2-keys.js) 拼接类 $lang('prefix.' + var) 在所有值下都能解析 模拟 runtime

误报防御(已针对历史坑修过)

  • JS 注释剥离 改用等长空白,正则偏移不偏(以前的 ghost key 大都是这个原因)
  • [^'\"]+ 跨换行陷阱 已用手动 paren-depth 解析替代,不会把整个文件吃进 key
  • JS 对象简写 { appName } 等同于 { appName: appName },正则同时识别
  • /api/lang/bundle 真会有的 tabBar.* 走 root level,审计对 common.tabBar.home 故意不报警
  • lang.js JSDoc 内 的 $lang('title')、$lang('welcomeText') 示例被注释剥离规则前置过滤

文件清单

scripts/
├── i18n_audit.py                ← 唯一入口(run this)
├── audit_lang_bundle_v2.py      ← 静态扫描(被 i18n_audit.py 调)
├── audit_lang_bundle.js         ← Node 端 lang 加载工具
├── verify-p2-keys.js            ← 动态 key 验证(被 i18n_audit.py 调)
├── I18N_AUDIT.md                ← 本文档
└── lang_audit_report_v2.json    ← 最近一次报告(自动生成)

何时该跑

  1. 拉了新 bundle.json:/api/lang/bundle 返回结果存到 lang-bundle.json 后,跑一次。
  2. 新增 / 修改翻译 key:lang/zh-cn/... 或 lang/en-us/... 文件改动后,跑一次。
  3. 新增组件:任何 .vue/.js 引入 $lang(...) 后,跑一次。
  4. 修复 i18n bug 后:跑一次,确认健康度评分达 99.95%。
  5. PR 合并前(CI):python scripts/i18n_audit.py --strict,exit code 控制是否合入。

想加新的检查怎么办

在 audit_lang_bundle_v2.py 加一个 section,产生新字段 → 在 i18n_audit.py::summarize 里加一行 print。audit_lang_bundle_v2.py 写好了自动落入结构化报告。

已知"非 bug 但需注意"(已知风险不需修)

  • pages.json 中 20 个 navigationBarTitleText 硬编码:由 lang.refresh() 自动覆盖,只要 refresh 在页面 mount 后被调到即可。
  • components-diy/diy-tab.vue 的 title 是运行时 DIY 数据:DIY 数据规范/白名单层面解决,不在审计范围。

最近一次结果速查

cat scripts/lang_audit_report_v2.json

主要字段:

{
  "code_calls_total": 2675,
  "code_unique_keys": 2083,
  "found_in_bundle": 2082,
  "missing_summary": {"SYNTAX_BUG": 1},
  "missing_classified": {...},
  "placeholder_issues": [],
  "data_lang_issues": {...},
  "hardcoded_navbar_titles": [...],
  "tabbar_missing": [...],
  "local_only_keys": []
}

placeholder_issues 为 [] 是绿;data_lang_issues 为 {} 是绿;missing_summary.SYNTAX_BUG ≥ 1 通常是 grep 误报,详见 missing_classified 字段的 reason。