From d1149b283117d3f31bc5199a145dae464a7115f1 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Sun, 24 Aug 2025 07:51:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(translations):=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E5=A4=9A=E8=AF=AD=E8=A8=80=E6=99=BA=E8=83=BD=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E5=92=8Cfallback=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增getSmartFallbackLocale方法实现智能fallback语言选择 - 增强deviceLocale方法支持更全面的语言代码匹配 - 改进中文简繁体识别逻辑,支持脚本代码和国家代码 - 添加语言代码映射表处理不同标准格式 - 优化设置语言流程,增加错误处理和日志 --- lib/core/translations/app_translations.dart | 190 +++++++++++++++++- lib/main.dart | 2 +- .../controllers/settings_controller.dart | 67 ++++-- 3 files changed, 238 insertions(+), 21 deletions(-) diff --git a/lib/core/translations/app_translations.dart b/lib/core/translations/app_translations.dart index 58b82c4fa..feee5eb94 100644 --- a/lib/core/translations/app_translations.dart +++ b/lib/core/translations/app_translations.dart @@ -44,9 +44,54 @@ import 'language/sr_rs.dart'; // 新增冰岛语导入 class AppTranslations extends Translations { static const fallbackLocale = Locale('zh', 'CN'); + + /// 智能选择fallback语言 + static Locale getSmartFallbackLocale() { + // 尝试获取系统语言信息 + Locale? systemLocale = Get.deviceLocale; + if (systemLocale == null) { + return fallbackLocale; + } + + String languageCode = systemLocale.languageCode.toLowerCase(); + + // 如果是中文,根据地区和脚本选择合适的fallback + if (languageCode == 'zh') { + String? countryCode = systemLocale.countryCode?.toUpperCase(); + String? scriptCode = systemLocale.scriptCode; + + // 根据脚本代码判断 + if (scriptCode == 'Hant') { + return const Locale('zh', 'HK'); // 繁体中文fallback + } else if (scriptCode == 'Hans') { + return const Locale('zh', 'CN'); // 简体中文fallback + } + + // 根据地区代码判断 + if (countryCode != null) { + switch (countryCode) { + case 'HK': + case 'MO': + case 'TW': + return const Locale('zh', 'HK'); // 繁体中文fallback + default: + return const Locale('zh', 'CN'); // 简体中文fallback + } + } + } + + // 对于其他语言,如果支持则使用英语,否则使用默认的中文 + if (languageCode == 'en') { + return const Locale('en', 'US'); + } + + // 默认使用简体中文 + return fallbackLocale; + } static final supportedLocales = [ const Locale('zh', 'CN'), // 简体中文 - const Locale('zh', 'HK'), // 添加繁体中文支持 + const Locale('zh', 'HK'), // 香港繁体中文 + const Locale('zh', 'TW'), // 台湾繁体中文(映射到香港繁体) const Locale('en', 'US'), // 英语 const Locale('es', 'ES'), // 添加西班牙语 const Locale('pt', 'PT'), // 添加葡萄牙语支持 @@ -85,15 +130,152 @@ class AppTranslations extends Translations { const Locale('is', 'IS'), // 新增冰岛语支持 ]; + /// 语言代码映射表,用于处理各种标准语言代码格式 + static final Map _languageCodeMapping = { + // 中文简体的各种表示方式 + 'zh-CN': const Locale('zh', 'CN'), + 'zh-Hans': const Locale('zh', 'CN'), + 'zh-Hans-CN': const Locale('zh', 'CN'), + 'zh-Hans-SG': const Locale('zh', 'CN'), + 'zh_CN': const Locale('zh', 'CN'), + 'zh_Hans': const Locale('zh', 'CN'), + 'zh_Hans_CN': const Locale('zh', 'CN'), + + // 中文繁体的各种表示方式 + 'zh-HK': const Locale('zh', 'HK'), + 'zh-TW': const Locale('zh', 'HK'), // 台湾繁体映射到香港繁体 + 'zh-Hant': const Locale('zh', 'HK'), + 'zh-Hant-HK': const Locale('zh', 'HK'), + 'zh-Hant-TW': const Locale('zh', 'HK'), + 'zh-Hant-MO': const Locale('zh', 'HK'), + 'zh_HK': const Locale('zh', 'HK'), + 'zh_TW': const Locale('zh', 'HK'), + 'zh_Hant': const Locale('zh', 'HK'), + 'zh_Hant_HK': const Locale('zh', 'HK'), + 'zh_Hant_TW': const Locale('zh', 'HK'), + + // 英语的各种表示方式 + 'en-US': const Locale('en', 'US'), + 'en-GB': const Locale('en', 'US'), + 'en_US': const Locale('en', 'US'), + 'en_GB': const Locale('en', 'US'), + }; + static Locale? deviceLocale() { final GetStorage storage = GetStorage(); - Locale? locale = Get.deviceLocale; String? language = storage.read('language'); + + // 如果用户手动设置了语言且不是跟随系统 if (language != null && language != 'system') { List languageList = language.split('_'); - locale = Locale(languageList[0], languageList[1]); + return Locale(languageList[0], languageList[1]); + } + + // 获取系统语言并进行智能匹配 + Locale? systemLocale = Get.deviceLocale; + if (systemLocale == null) { + return fallbackLocale; + } + + return _getMatchedLocale(systemLocale); + } + + /// 智能匹配系统语言到支持的语言 + static Locale _getMatchedLocale(Locale systemLocale) { + String languageCode = systemLocale.languageCode.toLowerCase(); + String? countryCode = systemLocale.countryCode?.toUpperCase(); + String? scriptCode = systemLocale.scriptCode; + + // 构建可能的语言代码组合进行匹配 + List possibleCodes = []; + + // 添加完整的语言代码组合 + if (scriptCode != null && countryCode != null) { + possibleCodes.addAll([ + '$languageCode-$scriptCode-$countryCode', + '${languageCode}_${scriptCode}_$countryCode', + ]); + } + + if (scriptCode != null) { + possibleCodes.addAll([ + '$languageCode-$scriptCode', + '${languageCode}_$scriptCode', + ]); + } + + if (countryCode != null) { + possibleCodes.addAll([ + '$languageCode-$countryCode', + '${languageCode}_$countryCode', + ]); + } + + // 添加基础语言代码 + possibleCodes.add(languageCode); + + // 尝试从映射表中找到匹配的语言 + for (String code in possibleCodes) { + if (_languageCodeMapping.containsKey(code)) { + return _languageCodeMapping[code]!; + } } - return locale; + + // 如果映射表中没有找到,使用原有的匹配逻辑 + return _fallbackMatchLocale(systemLocale); + } + + /// 备用匹配逻辑 + static Locale _fallbackMatchLocale(Locale systemLocale) { + String languageCode = systemLocale.languageCode.toLowerCase(); + String? countryCode = systemLocale.countryCode?.toUpperCase(); + String? scriptCode = systemLocale.scriptCode; + + // 处理中文的特殊情况 + if (languageCode == 'zh') { + // 优先根据脚本代码判断简繁体 + if (scriptCode != null) { + if (scriptCode == 'Hans') { + return const Locale('zh', 'CN'); // 简体中文 + } else if (scriptCode == 'Hant') { + return const Locale('zh', 'HK'); // 繁体中文 + } + } + + // 根据国家/地区代码判断 + if (countryCode != null) { + switch (countryCode) { + case 'CN': + case 'SG': + return const Locale('zh', 'CN'); // 简体中文 + case 'HK': + case 'MO': + case 'TW': + return const Locale('zh', 'HK'); // 繁体中文 + default: + // 默认使用简体中文(大陆用户更多) + return const Locale('zh', 'CN'); + } + } + + // 如果没有国家代码,默认使用简体中文 + return const Locale('zh', 'CN'); + } + + // 其他语言的匹配逻辑 + for (Locale supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == languageCode) { + // 如果国家代码也匹配,优先使用 + if (countryCode != null && supportedLocale.countryCode == countryCode) { + return supportedLocale; + } + // 否则使用第一个匹配的语言 + return supportedLocale; + } + } + + // 如果没有找到匹配的语言,使用fallback + return fallbackLocale; } @override diff --git a/lib/main.dart b/lib/main.dart index 6a976e86e..6cfa3d668 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -63,7 +63,7 @@ class MainApp extends StatelessWidget { GlobalCupertinoLocalizations.delegate, ], locale: AppTranslations.deviceLocale(), - fallbackLocale: AppTranslations.fallbackLocale, + fallbackLocale: AppTranslations.getSmartFallbackLocale(), supportedLocales: AppTranslations.supportedLocales, builder: EasyLoading.init( builder: (BuildContext context, Widget? widget) { diff --git a/lib/modules/settings/controllers/settings_controller.dart b/lib/modules/settings/controllers/settings_controller.dart index 372e664ca..71df4e42e 100644 --- a/lib/modules/settings/controllers/settings_controller.dart +++ b/lib/modules/settings/controllers/settings_controller.dart @@ -9,6 +9,7 @@ import 'package:logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; import '../../../core/themes/theme_service.dart'; +import '../../../core/translations/app_translations.dart'; import '../../../data/services/speech_factory.dart'; import '../../../routes/app_routes.dart'; import '../models/language_model.dart'; @@ -301,25 +302,59 @@ class SettingsController extends GetxController { } Future setLanguage(LanguageModel data) async { - if (data.value != 'system') { - List languageList = data.value.split('_'); - Get.updateLocale(Locale(languageList[0], languageList[1])); - } else { - Get.updateLocale(Get.deviceLocale!); - } - print("languageList: ${data.value}"); - language.value = data; - _storage.write('language', data.value); + try { + Locale? targetLocale; + + if (data.value != 'system') { + // 用户手动选择的语言 + List languageList = data.value.split('_'); + targetLocale = Locale(languageList[0], languageList[1]); + } else { + // 跟随系统语言,使用智能匹配 + targetLocale = AppTranslations.deviceLocale(); + } + + if (targetLocale != null) { + Get.updateLocale(targetLocale); + print("设置语言: ${data.value} -> ${targetLocale.toString()}"); + } else { + // 如果无法确定目标语言,使用智能fallback + targetLocale = AppTranslations.getSmartFallbackLocale(); + Get.updateLocale(targetLocale); + print("使用fallback语言: ${targetLocale.toString()}"); + } + + // 保存用户选择 + language.value = data; + await _storage.write('language', data.value); - // 更新agent服务的语音识别语言设置 - await _updateAgentLanguageSettings(data); + // 更新agent服务的语音识别语言设置 + await _updateAgentLanguageSettings(data); - // 延迟一下确保语言更新完成,然后重新进入应用 - await Future.delayed(const Duration(milliseconds: 500)); + // 显示语言切换成功提示 + // Get.snackbar( + // 'success'.tr, + // 'languageChanged'.tr, // 需要在语言文件中添加这个key + // snackPosition: SnackPosition.TOP, + // duration: const Duration(seconds: 2), + // ); - // 重新进入应用 - 回到启动页面重新初始化 - Get.offAllNamed(Routes.splash); - Get.back(); + // 延迟一下确保语言更新完成,然后重新进入应用 + await Future.delayed(const Duration(milliseconds: 500)); + + // 重新进入应用 - 回到启动页面重新初始化 + Get.offAllNamed(Routes.splash); + Get.back(); + } catch (e) { + print("设置语言时出错: $e"); + // Get.snackbar( + // 'error'.tr, + // 'languageChangeFailed'.tr, // 需要在语言文件中添加这个key + // snackPosition: SnackPosition.TOP, + // backgroundColor: Colors.red.withValues(alpha: 0.8), + // colorText: Colors.white, + // ); + } } /// 更新agent服务的语音识别语言设置