feat(i18n): l10n 单源地基 — 6 份手写 Dart 抽成 design/i18n/strings.json
i18n 单源第一步(用户要求:原型与实际程序必须一份数据)。 - 246 getter + 5 带参方法 × 6 语(zh/en/ja/ko/ru/es),抽取校验 0 缺失 - 抓到真漂移:strings_en.dart 原缺 quotaExhaustedNotice/openAlipayFailed 两个 key(双引号+EN漏维护),单源后六语强制对齐 - migrate_l10n_to_json.py 一次性迁移脚本(单/双引号 + getter/带参方法) 下一步:codegen(JSON→app_text.dart+strings_*.dart,替换手写)+ 原型读同源 + CI 漂移闸。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
# 从 6 份手写 strings_*.dart 抽取 l10n 到单源 JSON。只读,不改 Dart。
|
||||
import re, json, sys, os
|
||||
|
||||
BASE = "/Users/wangjia/code/pangolin/.claude/worktrees/configurable-proxy/client/lib/l10n"
|
||||
LANGS = ["zh", "en", "ja", "ko", "ru", "es"]
|
||||
|
||||
# Dart 字符串字面量:单引号或双引号(各自允许 \ 转义);getter 与带参方法
|
||||
STR = r"""(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")"""
|
||||
GET_RE = re.compile(r"String\s+get\s+(\w+)\s*=>\s*" + STR + r"\s*;")
|
||||
MET_RE = re.compile(r"String\s+(\w+)\(([^)]*)\)\s*=>\s*" + STR + r"\s*;")
|
||||
|
||||
def unescape(s):
|
||||
return s.replace("\\'", "'").replace('\\"', '"').replace('\\\\', '\\').replace('\\n', '\n').replace('\\$', '$')
|
||||
|
||||
getters = {} # key -> {lang: val}
|
||||
methods = {} # key -> {args, tpl:{lang:val}}
|
||||
counts = {}
|
||||
|
||||
for lang in LANGS:
|
||||
path = os.path.join(BASE, f"strings_{lang}.dart")
|
||||
src = open(path, encoding="utf-8").read()
|
||||
g = 0
|
||||
for m in GET_RE.finditer(src):
|
||||
k = m.group(1); v = unescape(m.group(2) if m.group(2) is not None else m.group(3))
|
||||
getters.setdefault(k, {})[lang] = v
|
||||
g += 1
|
||||
mm = 0
|
||||
for m in MET_RE.finditer(src):
|
||||
k = m.group(1); args = m.group(2).strip()
|
||||
v = unescape(m.group(3) if m.group(3) is not None else m.group(4))
|
||||
methods.setdefault(k, {"args": args, "tpl": {}})
|
||||
methods[k]["tpl"][lang] = v
|
||||
mm += 1
|
||||
counts[lang] = {"getters": g, "methods": mm}
|
||||
|
||||
# 完整性校验:每个 key 六语齐全
|
||||
missing = []
|
||||
for k, d in getters.items():
|
||||
for l in LANGS:
|
||||
if l not in d: missing.append(f"getter {k}:{l}")
|
||||
for k, d in methods.items():
|
||||
for l in LANGS:
|
||||
if l not in d["tpl"]: missing.append(f"method {k}:{l}")
|
||||
|
||||
out = {"_note": "l10n 单源(唯一真相源)。codegen 生成 client/lib/l10n/strings_*.dart + app_text.dart + 原型读同源。勿手改生成物。",
|
||||
"getters": getters, "methods": methods}
|
||||
os.makedirs("/Users/wangjia/code/pangolin/.claude/worktrees/configurable-proxy/design/i18n", exist_ok=True)
|
||||
outpath = "/Users/wangjia/code/pangolin/.claude/worktrees/configurable-proxy/design/i18n/strings.json"
|
||||
json.dump(out, open(outpath, "w", encoding="utf-8"), ensure_ascii=False, indent=2)
|
||||
|
||||
print("每语言抽取数:", counts)
|
||||
print(f"合并后:getters={len(getters)} methods={len(methods)}")
|
||||
print(f"缺失(应为0):{len(missing)}", missing[:5])
|
||||
print("输出:", outpath)
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user