import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../../../data/services/volcano_translation_service.dart'; import '../../../data/services/language_manager.dart'; import '../../../core/utils/logger.dart'; /// 文本翻译控制器 class TextTranslationController extends GetxController { // 依赖服务 final VolcanoTranslationService _translationService = Get.find(); final LanguageManager _languageManager = Get.find(); final GetStorage _storage = GetStorage(); // 文本输入控制器 final TextEditingController textController = TextEditingController(); // 响应式状态 final sourceLanguageChineseName = '中文(简体)'.obs; final targetLanguageChineseName = '英语'.obs; final sourceLanguageCode = 'zh-CN'.obs; final targetLanguageCode = 'en-US'.obs; final translatedText = ''.obs; final isTranslating = false.obs; final inputText = ''.obs; // 支持的语言列表 List get supportedLanguages => _languageManager.getAllChineseNames(); @override void onInit() { super.onInit(); // 初始化翻译服务 _initializeTranslationService(); _loadSavedLanguages(); // 监听文本输入变化 textController.addListener(() { inputText.value = textController.text; }); } /// 初始化翻译服务 Future _initializeTranslationService() async { try { // 已初始化则跳过 if (_translationService.isInitialized) { Logger.info('翻译服务已初始化'); return; } // final initialized = final initialized = await _translationService.initialize(); if (!initialized) { Logger.error('翻译服务初始化失败'); Get.snackbar( 'error'.tr, '翻译服务初始化失败,请检查网络连接', snackPosition: SnackPosition.TOP, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, ); } else { Logger.info('翻译服务初始化成功'); } } catch (e) { Logger.error('翻译服务初始化异常: $e'); } } @override void onClose() { textController.dispose(); super.onClose(); } /// 加载保存的语言设置 void _loadSavedLanguages() { try { final savedSourceLanguage = _storage.read('text_translation_source_language'); final savedTargetLanguage = _storage.read('text_translation_target_language'); if (savedSourceLanguage != null && supportedLanguages.contains(savedSourceLanguage)) { sourceLanguageChineseName.value = savedSourceLanguage; // 同时更新语言代码 final asrCode = _languageManager.getAsrCodeByChineseName(savedSourceLanguage); if (asrCode != null) { sourceLanguageCode.value = asrCode; } } if (savedTargetLanguage != null && supportedLanguages.contains(savedTargetLanguage)) { targetLanguageChineseName.value = savedTargetLanguage; // 同时更新语言代码 final asrCode = _languageManager.getAsrCodeByChineseName(savedTargetLanguage); if (asrCode != null) { targetLanguageCode.value = asrCode; } } } catch (e) { Logger.error('加载语言设置失败: $e'); } } /// 保存语言设置 void _saveLanguageSettings() { try { _storage.write( 'text_translation_source_language', sourceLanguageChineseName.value); _storage.write( 'text_translation_target_language', targetLanguageChineseName.value); } catch (e) { Logger.error('保存语言设置失败: $e'); } } /// 设置源语言 void setSourceLanguage(String language) { if (language != sourceLanguageChineseName.value) { sourceLanguageChineseName.value = language; // 同时更新语言代码;当选择“自动检测”时,将源语言代码置空,后续翻译流程会进行语种检测 if (language == '自动检测') { sourceLanguageCode.value = ''; } else { final asrCode = _languageManager.getAsrCodeByChineseName(language); if (asrCode != null) { sourceLanguageCode.value = asrCode; } } _saveLanguageSettings(); // 如果已有翻译结果,清空结果 if (translatedText.value.isNotEmpty) { translatedText.value = ''; } } } /// 设置目标语言 void setTargetLanguage(String language) { if (language != targetLanguageChineseName.value) { targetLanguageChineseName.value = language; // 同时更新语言代码 final asrCode = _languageManager.getAsrCodeByChineseName(language); if (asrCode != null) { targetLanguageCode.value = asrCode; } _saveLanguageSettings(); // 如果已有翻译结果,清空结果 if (translatedText.value.isNotEmpty) { translatedText.value = ''; } } } /// 交换源语言和目标语言 void swapLanguages() { final tempSource = sourceLanguageChineseName.value; final tempTarget = targetLanguageChineseName.value; final tempSourceCode = sourceLanguageCode.value; final tempTargetCode = targetLanguageCode.value; final tempInputText = textController.text; final tempTranslatedText = translatedText.value; sourceLanguageChineseName.value = tempTarget; targetLanguageChineseName.value = tempSource; sourceLanguageCode.value = tempTargetCode; targetLanguageCode.value = tempSourceCode; // 交换输入文本和翻译结果 textController.text = tempTranslatedText; translatedText.value = tempInputText; _saveLanguageSettings(); } /// 执行翻译 Future translateText() async { final text = textController.text.trim(); // 验证输入 if (text.isEmpty) { // Get.snackbar( // 'error'.tr, // 'pleaseInputText'.tr, // snackPosition: SnackPosition.TOP, // backgroundColor: Colors.orange.withOpacity(0.9), // colorText: Colors.white, // ); return; } if (text.length > 5000) { // 5000 字符限制 Get.snackbar( 'error'.tr, 'textTooLong'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.orange.withOpacity(0.9), colorText: Colors.white, ); return; } // 检查源语言和目标语言是否相同 if (sourceLanguageChineseName.value == targetLanguageChineseName.value) { translatedText.value = text; return; } isTranslating.value = true; translatedText.value = ''; try { Logger.info('开始翻译: $text'); Logger.info( '源语言: ${sourceLanguageChineseName.value} -> ${sourceLanguageCode.value}'); Logger.info( '目标语言: ${targetLanguageChineseName.value} -> ${targetLanguageCode.value}'); // 确保翻译服务已初始化 Logger.info('确保翻译服务已初始化...'); bool initialized = _translationService.isInitialized; if (!initialized) { initialized = await _translationService.initialize(); } Logger.info('翻译服务初始化结果: $initialized'); if (!initialized) { throw Exception('翻译服务初始化失败'); } Logger.info('调用翻译服务...'); // 若选择了“自动检测”,先进行语种检测 if (sourceLanguageChineseName.value == '自动检测' || sourceLanguageCode.value.isEmpty) { Logger.info('源语言为自动检测,开始语种检测…'); final detectedAsrCode = await _translationService.detectTextLanguage(text: text); if (detectedAsrCode == null || detectedAsrCode.isEmpty) { Logger.error('语种检测失败'); Get.snackbar( '错误', // 翻译键代表的中文文本内容 '语种检测失败,请手动选择源语言或稍后重试', // 翻译键代表的中文文本内容 snackPosition: SnackPosition.TOP, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, ); return; } sourceLanguageCode.value = detectedAsrCode; Logger.info('语种检测结果: $detectedAsrCode'); } // 调用翻译服务,使用检测或手动选择的源语言代码 final result = await _translationService.translateText( text: text, sourceLanguageCode: sourceLanguageCode.value, targetLanguageCode: targetLanguageCode.value, ); Logger.info('翻译服务返回结果: $result'); if (result != null && result.isNotEmpty) { translatedText.value = result; Logger.info('翻译成功: $result'); } else { Logger.error('翻译服务返回空结果'); throw Exception('翻译服务返回空结果'); } } catch (e) { Logger.error('翻译失败: $e'); Get.snackbar( 'error'.tr, 'translationFailed'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, ); } finally { isTranslating.value = false; } } /// 复制翻译结果 void copyResult() { if (translatedText.value.isNotEmpty) { Clipboard.setData(ClipboardData(text: translatedText.value)); Get.snackbar( 'success'.tr, 'copied'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.green.withOpacity(0.9), colorText: Colors.white, duration: const Duration(seconds: 2), ); } } /// 清空输入 void clearInput() { textController.clear(); translatedText.value = ''; } /// 显示语言选择对话框 void showLanguageSelector({required bool isSourceLanguage}) { Get.bottomSheet( Container( height: Get.height * 0.6, decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ Container( padding: const EdgeInsets.all(16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( isSourceLanguage ? 'sourceLanguage'.tr : 'targetLanguage'.tr, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), IconButton( onPressed: () => Get.back(), icon: const Icon(Icons.close), ), ], ), ), const Divider(height: 1), Expanded( child: ListView.builder( itemCount: (isSourceLanguage ? (supportedLanguages.length + 1) : supportedLanguages.length), itemBuilder: (context, index) { final language = isSourceLanguage ? (index == 0 ? '自动检测' : supportedLanguages[index - 1]) : supportedLanguages[index]; final isSelected = isSourceLanguage ? language == sourceLanguageChineseName.value : language == targetLanguageChineseName.value; return ListTile( title: Text(language), trailing: isSelected ? const Icon(Icons.check, color: Colors.blue) : null, onTap: () { if (isSourceLanguage) { setSourceLanguage(language); } else { setTargetLanguage(language); } Get.back(); }, ); }, ), ), ], ), ), isScrollControlled: true, ); } }