feat(i18n): l10n codegen — strings.json 单源生成 6 份 strings_*.dart

② 单源 codegen 落地:
- strings.json 补全 lists 段(days7/featsFree/featsPro/featsTeam),
  之前 extraction 漏了 4 个 List<String> getter;现 246 getter+4 list+5 method×6 语。
- design/codegen/gen_l10n_dart.mjs:strings.json → strings_{zh,en,ja,ko,ru,es}.dart,
  getter 转义 \$、method 保留 $var 插值,dart format 定型(保证漂移闸零 diff)。
- app_text.dart 保持手写(enum/abstract 声明/AppLangMisc 逻辑),编译器强制 concrete⊆abstract 兜底。
- 往返无损:生成的 Dart 重新抽取 == strings.json 逐字节一致;flutter analyze 0 issue、flutter test 244 全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
This commit is contained in:
wangjia
2026-07-27 08:47:44 +08:00
parent 9ab550d398
commit f76e3cdffd
9 changed files with 662 additions and 372 deletions
+173 -1
View File
@@ -1,5 +1,5 @@
{
"_note": "l10n 单源(唯一真相源)。codegen 生成 client/lib/l10n/strings_*.dart + app_text.dart + 原型读同源。勿手改生成物。",
"_note": "l10n 单源(唯一真相源)。design/codegen/gen_l10n_dart.mjs 生成 client/lib/l10n/strings_*.dart;原型 serve.mjs 读同源。勿手改生成物;abstract 声明由 app_text.dart 手写(编译器强制 concrete⊆abstract)。",
"getters": {
"brand": {
"zh": "穿山甲",
@@ -1970,6 +1970,178 @@
"es": "Antes"
}
},
"lists": {
"days7": {
"zh": [
"一",
"二",
"三",
"四",
"五",
"六",
"日"
],
"en": [
"M",
"T",
"W",
"T",
"F",
"S",
"S"
],
"ja": [
"月",
"火",
"水",
"木",
"金",
"土",
"日"
],
"ko": [
"월",
"화",
"수",
"목",
"금",
"토",
"일"
],
"ru": [
"Пн",
"Вт",
"Ср",
"Чт",
"Пт",
"Сб",
"Вс"
],
"es": [
"L",
"M",
"X",
"J",
"V",
"S",
"D"
]
},
"featsFree": {
"zh": [
"仅 1 个基础节点",
"每日 10 分钟时长",
"使用前观看广告",
"注册享 7 天免费试用"
],
"en": [
"1 basic node only",
"10 min per day",
"Watch an ad to start",
"7-day free trial on sign-up"
],
"ja": [
"基本ノード1つのみ",
"1日10分",
"広告を見て開始",
"登録で7日間無料トライアル"
],
"ko": [
"기본 노드 1개",
"하루 10분",
"광고 시청 후 시작",
"가입 시 7일 무료 체험"
],
"ru": [
"Только 1 базовый узел",
"10 минут в день",
"Смотрите рекламу, чтобы начать",
"7 дней бесплатно при регистрации"
],
"es": [
"Solo 1 nodo básico",
"10 min al día",
"Mira un anuncio para empezar",
"Prueba gratis de 7 días al registrarte"
]
},
"featsPro": {
"zh": [
"80+ 全球节点",
"无限流量 · 极速",
"5 台设备同时在线",
"流媒体优化"
],
"en": [
"80+ locations",
"Unlimited · fast",
"5 devices",
"Streaming optimized"
],
"ja": [
"80以上の拠点",
"無制限 · 高速",
"5台のデバイス",
"ストリーミング最適化"
],
"ko": [
"80개 이상 지역",
"무제한 · 빠른 속도",
"기기 5대",
"스트리밍 최적화"
],
"ru": [
"80+ локаций",
"Безлимитно · быстро",
"5 устройств",
"Оптимизация для стриминга"
],
"es": [
"Más de 80 ubicaciones",
"Ilimitado · rápido",
"5 dispositivos",
"Optimizado para streaming"
]
},
"featsTeam": {
"zh": [
"专业版全部功能",
"10 个成员席位",
"集中计费与管理",
"优先客服"
],
"en": [
"Everything in Pro",
"10 seats",
"Central billing",
"Priority support"
],
"ja": [
"Proのすべての機能",
"10ライセンス",
"一括請求",
"優先サポート"
],
"ko": [
"Pro의 모든 기능",
"10인 좌석",
"통합 결제",
"우선 지원"
],
"ru": [
"Всё из Pro",
"10 мест",
"Единый счёт",
"Приоритетная поддержка"
],
"es": [
"Todo lo de Pro",
"10 plazas",
"Facturación centralizada",
"Soporte prioritario"
]
}
},
"methods": {
"adRewarded": {
"args": "int minutes",