i18n-expert
This skill should be used when setting up, auditing, or enforcing internationalization/localization in UI codebases (React/TS, i18next or similar, JSON locales), including installing/configuring the i18n framework, replacing hard-coded strings, ensuring en-US/zh-CN coverage, mapping error codes to localized messages, and validating key parity, pluralization, and formatting.
1How It Works & Mechanism
The sole code asset is an audit script relying purely on the standard library: it extracts t('key') / i18n.t('key') / i18next.t('key') calls from source code using three regex patterns and performs set operations against the flattened key set of locale JSON files.
KEY_PATTERNS = [ re.compile(r"(?<![\w.])t\(\s*['\"]([^'\"]+)['\"]"), re.compile(r"\bi18n\.t\(\s*['\"]([^'\"]+)['\"]"), re.compile(r"\bi18next\.t\(\s*['\"]([^'\"]+)['\"]"), ]
The scan proactively skips node_modules and .git, filtering files against an extension allowlist to prevent pointless traversals across large repositories.
if "node_modules" in path.parts or ".git" in path.parts: continue
It outputs three diff tables: missing_by_locale (used in code but absent from that locale), unused_by_locale (present in locale but unreferenced in code), and parity_missing (key gaps across locales, answering 'present in en but absent in zh').
parity_missing[name] = sorted(other_keys - locale_key_map[name])
Plural keys are explicitly exempted: when a base key is not directly matched, it is not flagged as missing if CLDR plural suffix variants like _one/_other exist.
PLURAL_SUFFIXES = ("_zero", "_one", "_two", "_few", "_many", "_other")
Locale name inference follows conventions: generic filenames such as common.json / translation.json / messages.json inherit their parent directory name as the locale name (locales/en-US/common.json → en-US).
if path.name in {"common.json", "translation.json", "messages.json"}:
The workflow follows a closed loop of 'Audit → Fix → Re-verify', treating zero-gap status as the definition of done: any audit gap is a blocker, requiring re-runs until zero issues remain.
8) Validate - Re-run the audit until missing/parity issues are zero.
Concrete ripgrep regular expressions are provided for detecting hardcoded strings: one captures visible text inside JSX tags, and another detects three accessibility attributes (aria-label, title, and placeholder).
rg -n --glob '<src>/**/*.{ts,tsx,js,jsx}' "aria-label=\"[^\"]+\"|title=\"[^\"]+\"|placeholder=\"[^\"]+\""
Error handling enforces a strict rule: never expose raw error.message to the UI, display only localized text, relegate raw details to logs, and provide localized fallbacks for unknown error codes.
- Never expose raw `error.message` to UI; show localized strings only.
Framework selection provides default recommendations per stack and mandates determining early on whether routing is locale-aware (subpaths, subdomains, or query parameters).
- Choose a framework-appropriate library (e.g., React: react-i18next; Next.js: next-intl; Vue: vue-i18n).
Deliberate boundaries define what should NOT be translated: technical and brand terms like product names, API, MCP, and Bash remain untouched.
- Some technical/brand terms should remain untranslated (e.g., product name, API, MCP, Bash).
The script supports both machine-readable --json output and a human-readable summary mode, making it convenient for CI integration or manual inspection.
if args.json: json.dump(output, sys.stdout, indent=2, ensure_ascii=False)
2Core Capabilities
3External Dependencies
| 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 键、更新测试) |
4Recommended Governance & Evidence
- scripts/: Execute local script or command: i18n-expert/scripts/i18n_audit.py (executed with python3, pure standard library; read-only access to source code and locale JSON, writes only to stdout)
- 本地工作目录: File read/write and artifact output: The script performs no write operations itself (no open(...,'w'), write_text, or json.dump to file; only json.dump(..., sys.stdout))
5Second-Pass Verification
- [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。
6Verdict & Scenarios
8e220e12dd691eab…