Browse Source

feat(translations): 改进多语言智能匹配和fallback逻辑

- 新增getSmartFallbackLocale方法实现智能fallback语言选择
- 增强deviceLocale方法支持更全面的语言代码匹配
- 改进中文简繁体识别逻辑,支持脚本代码和国家代码
- 添加语言代码映射表处理不同标准格式
- 优化设置语言流程,增加错误处理和日志
weicu
lxm 1 year ago
parent
commit
d1149b2831
  1. 190
      lib/core/translations/app_translations.dart
  2. 2
      lib/main.dart
  3. 67
      lib/modules/settings/controllers/settings_controller.dart

190
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<String, Locale> _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<String> 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

2
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) {

67
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<void> 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服务的语音识别语言设置

Loading…
Cancel
Save