/// ============================================================ /// 闲言APP — 翻译覆盖率检测 /// 创建时间: 2026-05-29 /// 更新时间: 2026-05-31 /// 作用: 各语言翻译完成度检测与覆盖率报告 /// 上次更新: 新增ko/de/it语言覆盖率检测,基于toMap自动检测所有子模块 /// ============================================================ import 'types/t.dart'; import 'languages/zh_cn.dart'; import 'languages/en.dart'; import 'languages/ja.dart'; import 'languages/zh_tw.dart'; import 'languages/ko.dart'; import 'languages/de.dart'; import 'languages/it.dart'; import 'languages/es.dart'; import 'languages/ar.dart'; import 'languages/bn.dart'; import 'languages/hi.dart'; import 'languages/pt.dart'; import 'languages/ru.dart'; import 'languages/fr.dart'; /// 翻译覆盖率检测工具 class TranslationCoverage { /// 总翻译字段数(自动计算,基于zhCN的toMap) static int get totalFieldCount { final map = zhCN.toMap(); var count = 0; for (final section in map.values) { count += section.length; } return count; } /// 各语言实际翻译完成度(0-100),覆盖自动检测的空字段计数 /// 自动检测仅判断字段是否为空,无法区分"机器翻译占位"与"人工精校" /// 因此由维护者手动标注真实进度 static const Map _progressOverride = { 'zh_CN': 100, 'en': 90, 'ja': 85, 'zh_TW': 95, 'ko': 85, 'de': 75, 'it': 70, 'es': 75, 'ar': 70, 'bn': 65, 'hi': 60, 'pt': 70, 'ru': 75, 'fr': 80, }; /// 检测所有语言的翻译完成数量 static Map checkAll() { final result = {}; result['zh_CN'] = totalFieldCount; final languages = { 'en': en, 'ja': ja, 'zh_TW': zhTW, 'ko': ko, 'de': de, 'it': it, 'es': es, 'ar': ar, 'bn': bn, 'hi': hi, 'pt': pt, 'ru': ru, 'fr': fr, }; for (final entry in languages.entries) { final overridePercent = _progressOverride[entry.key]; if (overridePercent != null) { result[entry.key] = (totalFieldCount * overridePercent / 100).round(); } else { final missing = checkCoverage(entry.value, zhCN); result[entry.key] = totalFieldCount - missing.length; } } return result; } /// 获取某语言的实际翻译完成百分比(0-100) static int getProgressPercent(String langId) { final percent = _progressOverride[langId]; if (percent != null) return percent; return 100; } /// 检测目标语言相对于参考语言的缺失翻译字段 /// 基于 toMap() 自动遍历,新增字段无需手动添加检测代码 static List checkCoverage(T target, T reference) { final targetMap = target.toMap(); final missing = []; for (final sectionEntry in targetMap.entries) { final sectionName = sectionEntry.key; final sectionMap = sectionEntry.value; for (final fieldEntry in sectionMap.entries) { if (fieldEntry.value.isEmpty) { missing.add('$sectionName.${fieldEntry.key}'); } } } return missing; } /// 获取某语言的缺失翻译字段详情 static Map> checkCoverageDetail(T target) { final targetMap = target.toMap(); final result = >{}; for (final sectionEntry in targetMap.entries) { final sectionName = sectionEntry.key; final sectionMap = sectionEntry.value; final missingFields = []; for (final fieldEntry in sectionMap.entries) { if (fieldEntry.value.isEmpty) { missingFields.add(fieldEntry.key); } } if (missingFields.isNotEmpty) { result[sectionName] = missingFields; } } return result; } /// 获取所有语言的覆盖率报告 static Map> fullReport() { final languages = { 'zh_CN': zhCN, 'en': en, 'ja': ja, 'zh_TW': zhTW, 'ko': ko, 'de': de, 'it': it, 'es': es, 'ar': ar, 'bn': bn, 'hi': hi, 'pt': pt, 'ru': ru, 'fr': fr, }; final total = totalFieldCount; final report = >{}; for (final entry in languages.entries) { final missing = checkCoverage(entry.value, zhCN); final diff = diffFields(entry.value, zhCN); final overridePercent = _progressOverride[entry.key]; final effectivePercent = overridePercent ?? ((total - missing.length) * 100 / total).round(); report[entry.key] = { 'total': total, 'translated': total - missing.length, 'missing': missing, 'percent': effectivePercent, 'missingFields': diff, }; } return report; } /// 检测目标语言与参考语言的字段差异 /// 返回参考语言中存在但目标语言中缺失或为空的字段 static Map> diffFields(T target, T reference) { final targetMap = target.toMap(); final referenceMap = reference.toMap(); final result = >{}; for (final sectionEntry in referenceMap.entries) { final sectionName = sectionEntry.key; final refSection = sectionEntry.value; final targetSection = targetMap[sectionName] ?? {}; final missing = []; for (final fieldEntry in refSection.entries) { final targetValue = targetSection[fieldEntry.key]; if (targetValue == null || targetValue.isEmpty) { missing.add(fieldEntry.key); } } if (missing.isNotEmpty) { result[sectionName] = missing; } } return result; } /// 获取所有语言ID列表(不含zh_CN) static List get allLanguageIds => [ 'en', 'ja', 'zh_TW', 'ko', 'de', 'it', 'es', 'ar', 'bn', 'hi', 'pt', 'ru', 'fr', ]; /// 获取所有语言的翻译实例映射 static Map get allLanguages => { 'zh_CN': zhCN, 'en': en, 'ja': ja, 'zh_TW': zhTW, 'ko': ko, 'de': de, 'it': it, 'es': es, 'ar': ar, 'bn': bn, 'hi': hi, 'pt': pt, 'ru': ru, 'fr': fr, }; }