#!/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)