#!/usr/bin/env python3 # 完整抽取 l10n → 单源 JSON:getters(String get) + lists(List get) + methods(带参)。 # 只读 Dart,不改。与已提交 strings.json 的 getters/methods 校验无回归,新增 lists 段。 import re, json, os BASE = "/Users/wangjia/code/pangolin/.claude/worktrees/configurable-proxy/client/lib/l10n" OUT = "/Users/wangjia/code/pangolin/.claude/worktrees/configurable-proxy/design/i18n/strings.json" LANGS = ["zh", "en", "ja", "ko", "ru", "es"] STR = r"""(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")""" STR_RE = re.compile(STR) 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*;") # List get name => const [ ... ]; —— 跨行,惰性到第一个 '];' LIST_RE = re.compile(r"List\s+get\s+(\w+)\s*=>\s*const\s*\[(.*?)\]\s*;", re.DOTALL) def unescape(s): return (s.replace("\\'", "'").replace('\\"', '"') .replace('\\n', '\n').replace('\\$', '$').replace('\\\\', '\\')) getters, lists, methods, counts = {}, {}, {}, {} for lang in LANGS: src = open(os.path.join(BASE, f"strings_{lang}.dart"), encoding="utf-8").read() g = m = ln = 0 for mt in GET_RE.finditer(src): k = mt.group(1) v = unescape(mt.group(2) if mt.group(2) is not None else mt.group(3)) getters.setdefault(k, {})[lang] = v; g += 1 for mt in MET_RE.finditer(src): k = mt.group(1); args = mt.group(2).strip() v = unescape(mt.group(3) if mt.group(3) is not None else mt.group(4)) methods.setdefault(k, {"args": args, "tpl": {}}) methods[k]["tpl"][lang] = v; m += 1 for mt in LIST_RE.finditer(src): k = mt.group(1); body = mt.group(2) items = [unescape(a if a is not None else b) for a, b in STR_RE.findall(body)] lists.setdefault(k, {})[lang] = items; ln += 1 counts[lang] = {"getters": g, "methods": m, "lists": ln} # 完整性:每 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 lists.items(): for l in LANGS: if l not in d: missing.append(f"list {k}:{l}") for k, d in methods.items(): for l in LANGS: if l not in d["tpl"]: missing.append(f"method {k}:{l}") # 与已提交 JSON 的 getters/methods 校验无回归 old = json.load(open(OUT, encoding="utf-8")) if os.path.exists(OUT) else {} regress = [] if old: if set(old.get("getters", {})) != set(getters): regress.append("getter 键集变化") for k, d in old.get("getters", {}).items(): if getters.get(k) != d: regress.append(f"getter 值变化:{k}") if set(old.get("methods", {})) != set(methods): regress.append("method 键集变化") out = {"_note": "l10n 单源(唯一真相源)。design/codegen/gen_l10n_dart.mjs 生成 client/lib/l10n/strings_*.dart;" "原型 serve.mjs 读同源。勿手改生成物;abstract 声明由 app_text.dart 手写(编译器强制 concrete⊆abstract)。", "getters": getters, "lists": lists, "methods": methods} json.dump(out, open(OUT, "w", encoding="utf-8"), ensure_ascii=False, indent=2) print("每语言:", counts) print(f"合并:getters={len(getters)} lists={len(lists)} methods={len(methods)}") print(f"缺失(应0):{len(missing)}", missing[:5]) print(f"回归(应0):{len(regress)}", regress[:5]) print("lists 键:", list(lists)) print("输出:", OUT)