1仕組みと動作原理
唯一のコード資産は標準ライブラリのみで構成された監査スクリプトです。3つの正規表現でソースコード内の t('key') / i18n.t('key') / i18next.t('key') を抽出し、フラット化したロケールJSONのキー集合と集合演算を行います。
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
3つの差分テーブルを出力します:missing_by_locale(コード側で使用されているが該当ロケールに未定義)、unused_by_locale(ロケールに存在するがコード側で未使用)、parity_missing(ロケール間の不整合、「enには存在するがzhにはない」等)。
parity_missing[name] = sorted(other_keys - locale_key_map[name])
複数形キーは特別に除外されます。キー自体が直接一致しなくても、_one/_other などのCLDR複数形サフィックスのバリアントが存在する場合は欠落とみなしません。
PLURAL_SUFFIXES = ("_zero", "_one", "_two", "_few", "_many", "_other")
ロケール名の推論には規約があります。common.json / translation.json / messages.json のような汎用ファイル名の場合、親ディレクトリ名をロケール名として採用します(locales/en-US/common.json → en-US)。
if path.name in {"common.json", "translation.json", "messages.json"}:
ワークフローは「監査 → 修正 → 再検証」の閉ループであり、ギャップをゼロにすることを完了条件とします。監査で見つかった欠落はブロッカーとみなし、解消するまで再実行を義務付けています。
8) Validate - Re-run the audit until missing/parity issues are zero.
ハードコード文字列の検索には具体的な ripgrep の正規表現を提供します。JSXタグ内の可視テキスト用と、aria-label / title / placeholder の3つのアクセシビリティ属性用の2本立てです。
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.
技術スタック別のフレームワーク選定のデフォルト指針を提供し、「ルーティングがロケールを認識するか否か」(サブパス/サブドメイン/クエリパラメータ)を最序盤で決定するよう求めています。
- 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 で実行、標準ライブラリのみ使用。ソースコードとロケールJSONは読み取り専用で、出力は stdout のみ)
- 本地工作目录: ファイルの読み書きと成果物の出力: スクリプト自体にはファイル書き込み処理なし(コード全体に open(...,'w')、write_text、ファイルへの json.dump は存在せず、json.dump(..., sys.stdout) のみ)
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…