1实现原理 · 为什么它能做到
唯一的代码资产是一个纯标准库的审计脚本:用三条正则抽取源码里的 t('key') / i18n.t('key') / i18next.t('key'),与 locale JSON 扁平化后的 key 集合做集合运算。
KEY_PATTERNS = [ re.compile(r"(?<![\w.])t\(\s*['\"]([^'\"]+)['\"]"), re.compile(r"\bi18n\.t\(\s*['\"]([^'\"]+)['\"]"), re.compile(r"\bi18next\.t\(\s*['\"]([^'\"]+)['\"]"), ]
扫描时主动跳过 node_modules 与 .git,并按扩展名白名单收文件,避免在大仓库里做无意义遍历。
if "node_modules" in path.parts or ".git" in path.parts: continue
输出三张差异表:missing_by_locale(代码用了但该 locale 没有)、unused_by_locale(locale 有但代码没用到)、parity_missing(各 locale 之间的缺失,回答「en 有 zh 没有」)。
parity_missing[name] = sorted(other_keys - locale_key_map[name])
复数键被专门豁免:key 本体没直接命中、但存在 _one/_other 等 CLDR 复数后缀变体时不算缺失。
PLURAL_SUFFIXES = ("_zero", "_one", "_two", "_few", "_many", "_other")
locale 名推断有约定:common.json / translation.json / messages.json 这类通用文件名用父目录名当 locale 名(locales/en-US/common.json → en-US)。
if path.name in {"common.json", "translation.json", "messages.json"}:
工作流是「审计 → 修复 → 复验」的闭环,且把缺口归零当作完成条件:审计发现缺失即视为 blocker,改完必须复跑到零。
8) Validate - Re-run the audit until missing/parity issues are zero.
裸字符串检索给了具体的 ripgrep 正则:一条抓 JSX 标签里的可见文案,一条抓 aria-label / title / placeholder 三类可访问性属性。
rg -n --glob '<src>/**/*.{ts,tsx,js,jsx}' "aria-label=\"[^\"]+\"|title=\"[^\"]+\"|placeholder=\"[^\"]+\""
错误处理有一条硬性准则:绝不把原始 error.message 暴露到 UI,只显示本地化文案,原始细节只进日志,并给未知错误码配本地化兜底。
- Never expose raw `error.message` to UI; show localized strings only.
框架选型给了按栈的默认答案,且把「路由是否 locale 感知」(子路径/子域/query 参数)要求在最早期就定下来。
- Choose a framework-appropriate library (e.g., React: react-i18next; Next.js: next-intl; Vue: vue-i18n).
刻意划定「不该翻译」的边界:产品名、API、MCP、Bash 这类技术/品牌词保持原样。
- Some technical/brand terms should remain untranslated (e.g., product name, API, MCP, Bash).
脚本支持 --json 机器可读输出与人类摘要两种模式,便于接入 CI 或人工巡检。
if args.json: json.dump(output, sys.stdout, indent=2, ensure_ascii=False)
2核心能力
3外部依赖
| Kind | Dependency / Endpoint |
|---|---|
| cli | python3(执行 scripts/i18n_audit.py;仅标准库 argparse/json/re/pathlib/typing) |
| cli | rg(ripgrep,用于定位裸字符串与可访问性属性) |
| cli | python -m json.tool(校验 locale JSON 合法性) |
| package | i18n 库(由 agent 按栈安装,非脚本调用:react-i18next / next-intl / vue-i18n) |
| api | 宿主 Edit/写文件能力(替换源码字符串、新增 locale 键、更新测试) |
4管控建议与判定依据
- scripts/: 执行本地脚本或命令: i18n-expert/scripts/i18n_audit.py(python3 执行,纯标准库;只读源码与 locale JSON,只写 stdo
- 本地工作目录: 文件读写与工件输出: 脚本自身无写操作(全文无 open(...,'w')/write_text/json.dump 到文件,只有 json.dump(..., sys.s
5第二遍独立确认
- [ok] 外部依赖逐条是否真实存在 — python3 见 shebang;rg 两条命令见 SKILL.md Step 4 代码块;python -m json.tool 见 Step 8;i18n 库安装见 Step 2 的 Install packages;宿主写能力见 Step 5 与 Deliverables。无一条来自推测。
- [ok] 脚本是否真的只读(安全结论最关键的一条) — 通读 i18n_audit.py 全文:唯一 I/O 是 path.read_text(encoding='utf-8') 与 path.open(encoding='utf-8') 读 locale、print 与 json.dump(sys.stdout)。无写文件、无删除、无 mkdir。已在 file_writes 中明确把写入归到 agent 侧。
- [ok] 『零网络』是否被 token 扫描的空结果证明 — 扫描零命中即为证据;SKILL.md 正文也未出现任何 URL 或域名(对比同仓其他 skill 常见域名常量)。故 network_calls = []。
- [ok] 复数豁免是否真在 compute_missing 中生效 — compute_missing 内两个 continue 分支:key in locale_keys 与 has_plural_variant(key, locale_keys),后者遍历 PLURAL_SUFFIXES 六个后缀构造 f"{key}{suffix}" 再查集合。代码属实,非文档口号。
- [discrepancy] parity_missing 语义是否与 SKILL.md 表述一致 — 〔第二遍标注:措辞微调〕实现是『其它所有 locale key 并集 − 本 locale key』(other_keys - locale_key_map[name]),语义为「别家有而本家缺」,与 SKILL.md『ensuring en-US/zh-CN coverage』一致,但它不是「两两全等」的严格校验:当同缺一个 key 时两边都不报。第一遍若把 parity 描述成「严格一致校验」会夸大,已在 how_it_works/note 中写明实现语义。
- [ok] 动态 key 的处理是否被承诺为自动 — SKILL.md 明写『Manually verify dynamic keys (`t(var)`).』——正则抽取天然覆盖不到动态 key,文档没有掩盖这一限制,不存在夸大。
- [ok] 元数据(license/stars/last_push) — 取自同 repo 同 commit 的池内既有值(MIT、1385★、2026-09-09T12:33:29Z);本次未联网复核 gh。
6结论
8e220e12dd691eab…