- 新增 GitHub Actions 工作流实现 PR 时自动审计国际化内容 - 添加 pre-commit 钩子,提交前自动检查相关文件并拦截问题提交 - 编写完整的 i18n 审计脚本、文档与示例报告 - 实现多维度国际化校验:键匹配、占位符、data()误用、硬编码标题等
4.4 KiB
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.jsJSDoc 内 的$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 ← 最近一次报告(自动生成)
何时该跑
- 拉了新 bundle.json:
/api/lang/bundle返回结果存到lang-bundle.json后,跑一次。 - 新增 / 修改翻译 key:
lang/zh-cn/...或lang/en-us/...文件改动后,跑一次。 - 新增组件:任何 .vue/.js 引入
$lang(...)后,跑一次。 - 修复 i18n bug 后:跑一次,确认
健康度评分达99.95%。 - 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。