Browse Source

feat(i18n): 添加并完善翻译键和国际化文本

添加用量统计模块的翻译键和文本
完善图片翻译模块的国际化支持
统一各模块的时间范围和统计项翻译
更新翻译控制器和视图以使用翻译键
weicu
lxm 10 months ago
parent
commit
fa0116a1b5
  1. 110
      lib/core/translations/language/en_us.dart
  2. 102
      lib/core/translations/language/zh_cn.dart
  3. 41
      lib/data/models/translation_usage_stats.dart
  4. 2
      lib/modules/common/widgets/language_selector_bar.dart
  5. 8
      lib/modules/common/widgets/recharge_dialog.dart
  6. 3
      lib/modules/meeting/controllers/meeting_home_controller.dart
  7. 87
      lib/modules/picture_translation/controllers/picture_translation_controller.dart
  8. 60
      lib/modules/picture_translation/views/picture_translation_history_detail_view.dart
  9. 192
      lib/modules/picture_translation/views/picture_translation_view.dart
  10. 8
      lib/modules/text_translation/controllers/text_translation_controller.dart
  11. 8
      lib/modules/text_translation/views/text_translation_view.dart
  12. 2
      lib/modules/translation/middleware/controllers/translation_middleware_controller.dart
  13. 8
      lib/modules/translation/views/dialogs/language_selection_dialog.dart
  14. 4
      lib/modules/translation/views/translation_view.dart
  15. 4
      lib/modules/translation/views/widgets/translation_item_widget.dart
  16. 72
      lib/modules/usage/controllers/meeting_stats_controller.dart
  17. 34
      lib/modules/usage/controllers/translation_stats_controller.dart
  18. 4
      lib/modules/usage/views/aichat_stats_view.dart
  19. 22
      lib/modules/usage/views/meeting_stats_view.dart
  20. 76
      lib/modules/usage/views/translation_stats_view.dart
  21. 2
      lib/modules/usage/views/usage_view.dart

110
lib/core/translations/language/en_us.dart

@ -186,6 +186,52 @@ const Map<String, String> enUS = {
"usageStatsInfo": "View Your Usage Statistics",
"scene": "Scenarios",
/// 用量统计模块
"aiChat": "AI Chat",
"translationStats": "Translation Statistics",
"meetingStats": "Meeting Statistics",
"today": "Today",
"thisWeek": "This Week",
"thisMonth": "This Month",
"history": "History",
"currentSessionStats": "Current Session Stats",
"translationCount": "Translation Count",
"sessionDuration": "Session Duration",
"characters": "Characters",
"recordingDuration": "Recording Duration",
"totalApiCalls": "Total API Calls",
"sessionCount": "Session Count",
"totalCharacters": "Total Characters",
"apiCallStats": "API Call Stats",
"translationApi": "Translation API",
"asr": "ASR",
"tts": "TTS",
// "aiSummary": "AI Summary",
"dataVolumeStats": "Data Volume Stats",
"sourceTextCharacters": "Source Text Characters",
"ttsTextCharacters": "TTS Text Characters",
"effectiveAudioDuration": "Effective Audio Duration",
"totalSessionDuration": "Total Session Duration",
"costStats": "Cost Stats",
"estimatedCost": "Estimated Cost",
"dailyCostThreshold": "Daily Cost Threshold",
"monthlyCostThreshold": "Monthly Cost Threshold",
"usageBehaviorStats": "Usage Behavior Stats",
"mostUsedLanguagePair": "Most-used language pair",
"mostUsedMode": "Most-used mode",
"asrApiCalls": "ASR Calls",
"totalAudioDuration": "Total Audio Duration",
"audioFileSize": "Audio File Size",
"transcriptBytes": "Transcript Bytes",
//通知文案
"loadFailed": "Load Failed",
"statsLoadFailedTryLater":
"Statistics failed to load. Please try again later.",
"cleanupComplete": "Cleanup Complete",
"cleanedOldData": "Cleaned data older than 90 days",
"exportFeature": "Export Feature",
"exportInDevelopment": "Data export is under development",
// 商品页面(AI/翻译/会议)
'availablePackages': 'Available Packages',
'remainingQuota': 'Remaining Quota',
@ -1150,6 +1196,7 @@ const Map<String, String> enUS = {
// 翻译主页 (translation_view.dart)
"translationHistory": "Translation History",
"historyRecords": "History Records",
"enableRecording": "Enable Recording",
"viewAudioFiles": "View Audio Files",
"headsetUser": "Headset User",
@ -1162,9 +1209,15 @@ const Map<String, String> enUS = {
// 通用对话按钮与选项(用于统一语言选择弹窗等)
// 翻译键代表的中文文本内容:取消/确认/自动检测
"autoDetect": "Auto Detect",
// Text translation & language detection
"languageDetectionFailed": "Language detection failed",
"translationFailed": "Translation failed",
"pleaseInputText": "Please input text",
"textTooLong": "Text too long, max 5000 characters",
// 翻译历史页
"noTranslationHistory": "No translation history",
"clearResults": "Clear Results",
"clearHistory": "Clear History",
"clearHistoryConfirm":
"Are you sure you want to clear all translation history? This action cannot be undone.",
@ -1173,6 +1226,57 @@ const Map<String, String> enUS = {
"deleteSessionConfirm":
"Are you sure you want to delete all translation records for this session? This action cannot be undone.",
// Picture Translation module
"selectImageSource": "Select Image Source",
"imagePreview": "Image Preview",
"translationResult": "Translation Result",
"recognitionResult": "Recognition Result",
"translatedImagePreview": "Translated Image Preview",
"translatedImageLoadFailed": "Failed to load translated image",
"pleaseSelectImage": "Please select an image",
"imageLoadFailed": "Image load failed",
"imageQuality": "Image Quality",
"maxSize": "Max Size",
"close": "Close",
"setImageQuality": "Set Image Quality",
"currentQuality": "Current quality: @value%",
"setMaxSize": "Set Max Size",
"currentMaxSize": "Current: @pxpx",
"waitingForAction": "Waiting for action",
"pleaseSelectImageToStart": "Please select an image to start",
"chooseImage": "Choose Image",
"openingCamera": "Opening camera...",
"openingPhotoAlbum": "Opening photo album...",
"cancelled": "Cancelled",
"userCancelledSelection": "User cancelled selection",
"translatingImage": "Translating Image",
"callingImageTranslateService": "Calling image translation service...",
"savingRecord": "Saving Record",
"savingTranslationResult": "Saving translation result...",
"translationCompleted": "Translation Completed",
"allStepsCompleted": "All steps completed",
"processingFailed": "Processing Failed",
"imageProcessingOrTranslationFailed":
"Image processing or translation failed. Please retry.\nError: {error}",
"imageTooLarge": "Image size exceeds 4MB limit",
"imageTooLargeHint":
"Image size exceeds 4MB. Reduce quality or dimensions and retry",
"emptyTranslationResult": "Image translation API returned empty result",
"imageTranslationFailedTryLater":
"Image translation failed. Network issue or rate limit. Please try later",
"imageTranslationApiException":
"Image translation API exception. Check network and retry",
"permissionRequired": "Permission Required",
"cameraPermissionRequired": "Camera permission required to take photos",
"photoAlbumPermissionRequired":
"Photo album permission required to pick images",
"translationDetails": "Translation Details",
"originalImage": "Original Image",
"sourceLanguage": "Source Language",
"targetLanguage": "Target Language",
"translationTime": "Translation Time",
"shareInDevelopment": "Sharing feature under development",
// 翻译录音文件列表页
"translateAudioFiles": "Translate Audio Files",
"noAudioFiles": "No audio files",
@ -1382,6 +1486,9 @@ const Map<String, String> enUS = {
"justNow": "Just now",
"minutesAgo": "@minutes minutes ago",
"yesterday": "Yesterday",
// Time extensions (used by picture translation)
"daysAgo": "@days days ago",
"hoursAgo": "@hours hours ago",
//补充
"insufficientIntegral": "Insufficient integral",
@ -1390,4 +1497,7 @@ const Map<String, String> enUS = {
"insufficientBalanceDesc":
'Insufficient balance, please go to the corresponding recharge page to recharge.',
"recharge": 'Go to Recharge',
// 会员到期提示(中文注释)
"aiMemberExpiredDesc":
'AI membership expired, please go to the membership recharge page to renew.',
};

102
lib/core/translations/language/zh_cn.dart

@ -179,6 +179,50 @@ const Map<String, String> zhCN = {
"usageStats": "用量统计",
"usageStatsInfo": "查看您的使用统计数据",
"scene": "场景",
// 用量统计模块
"aiChat": "AI聊天",
"translationStats": "翻译统计",
"meetingStats": "会议统计",
"today": "今日",
"thisWeek": "本周",
"thisMonth": "本月",
"history": "历史",
"currentSessionStats": "当前会话统计",
"translationCount": "翻译次数",
"sessionDuration": "会话时长",
"characters": "字符数",
"recordingDuration": "录音时长",
"totalApiCalls": "总调用次数",
"sessionCount": "会话数量",
"totalCharacters": "总字符数",
"apiCallStats": "API调用统计",
"translationApi": "翻译API",
"asr": "语音识别",
"tts": "语音合成",
//"aiSummary": "AI摘要",
"dataVolumeStats": "数据量统计",
"sourceTextCharacters": "源文本字符",
"ttsTextCharacters": "TTS文本字符",
"effectiveAudioDuration": "有效音频时长",
"totalSessionDuration": "总会话时长",
"costStats": "成本统计",
"estimatedCost": "预估成本",
"dailyCostThreshold": "日成本预警阈值",
"monthlyCostThreshold": "月成本预警阈值",
"usageBehaviorStats": "使用行为统计",
"mostUsedLanguagePair": "最常用语言对",
"mostUsedMode": "最常用模式",
"asrApiCalls": "ASR调用次数",
"totalAudioDuration": "音频总时长",
"audioFileSize": "音频文件大小",
"transcriptBytes": "转写字节",
// 通知文案
"loadFailed": "加载失败",
"statsLoadFailedTryLater": "统计数据加载失败,请稍后重试",
"cleanupComplete": "清理完成",
"cleanedOldData": "已清理90天前的过期数据",
"exportFeature": "导出功能",
"exportInDevelopment": "数据导出功能正在开发中",
// 商品页面(AI/翻译/会议)
'availablePackages': '可购买套餐',
@ -1067,15 +1111,68 @@ const Map<String, String> zhCN = {
// 通用对话按钮与选项(用于统一语言选择弹窗等)
// 以下翻译键的中文文本内容如注释所示
"autoDetect": "自动检测", // 自动检测
// 文本翻译与语种检测
"languageDetectionFailed": "语言检测失败",
"translationFailed": "翻译失败",
"pleaseInputText": "请输入文本",
"textTooLong": "文本过长,最多5000字符",
// 翻译历史页
"noTranslationHistory": "暂无历史记录",
"historyRecords": "历史记录",
"clearResults": "清空结果",
"clearHistory": "清除历史记录",
"clearHistoryConfirm": "确定要清除所有翻译历史记录吗?此操作无法撤销。",
"unknownLanguage": "未知语言",
"deleteSessionRecord": "删除会话记录",
"deleteSessionConfirm": "确定要删除该会话的所有翻译记录吗?此操作无法撤销。",
// 图片翻译模块(Picture Translation)
"selectImageSource": "选择图片来源",
"imagePreview": "图片预览",
"translationResult": "翻译结果",
"recognitionResult": "识别结果",
"translatedImagePreview": "翻译后的图片预览",
"translatedImageLoadFailed": "翻译图片加载失败",
"pleaseSelectImage": "请选择图片",
"imageLoadFailed": "图片加载失败",
"imageQuality": "图片质量",
"maxSize": "最大尺寸",
"close": "关闭",
"setImageQuality": "设置图片质量",
"currentQuality": "当前质量: @value%",
"setMaxSize": "设置最大尺寸",
"currentMaxSize": "当前: @pxpx",
"waitingForAction": "等待操作",
"pleaseSelectImageToStart": "请选择图片开始翻译",
"chooseImage": "选择图片",
"openingCamera": "正在打开相机...",
"openingPhotoAlbum": "正在打开相册...",
"cancelled": "已取消",
"userCancelledSelection": "用户取消了选择",
"translatingImage": "翻译图片",
"callingImageTranslateService": "正在调用图片翻译服务...",
"savingRecord": "保存记录",
"savingTranslationResult": "正在保存翻译结果...",
"translationCompleted": "翻译完成",
"allStepsCompleted": "所有步骤已完成",
"processingFailed": "处理失败",
"imageProcessingOrTranslationFailed": "图片处理或翻译失败,请重试。\n错误信息: {error}",
"imageTooLarge": "图片大小超过4MB限制",
"imageTooLargeHint": "图片大小超过4MB限制,请降低质量或尺寸后重试",
"emptyTranslationResult": "图片翻译接口返回空结果",
"imageTranslationFailedTryLater": "图片翻译失败,可能的原因:网络异常或接口限流,请稍后重试",
"imageTranslationApiException": "图片翻译接口调用异常,请检查网络后重试",
"permissionRequired": "权限需求",
"cameraPermissionRequired": "需要相机权限才能拍照",
"photoAlbumPermissionRequired": "需要相册权限才能选择图片",
"translationDetails": "翻译详情",
"originalImage": "原图片",
"sourceLanguage": "源语言",
"targetLanguage": "目标语言",
"translationTime": "翻译时间",
"shareInDevelopment": "分享功能开发中",
// 翻译录音文件列表页
"translateAudioFiles": "翻译录音文件",
"noAudioFiles": "暂无音频文件",
@ -1266,6 +1363,9 @@ const Map<String, String> zhCN = {
"justNow": "刚刚",
"minutesAgo": "@minutes分钟前",
"yesterday": "昨天",
// 时间扩展(图片翻译模块使用)
"daysAgo": "@days天前",
"hoursAgo": "@hours小时前",
//补充
"insufficientIntegral": "积分不足",
@ -1273,4 +1373,6 @@ const Map<String, String> zhCN = {
//余额不足弹窗
"insufficientBalanceDesc": "余额不足,请前往对应充值界面进行充值",
"recharge": "前往充值",
// 会员到期提示
"aiMemberExpiredDesc": "AI会员已到期,请前往会员充值续费",
};

41
lib/data/models/translation_usage_stats.dart

@ -1,5 +1,3 @@
/// 翻译模式统计数据
class TranslationModeStats {
final int apiCalls; // API调用次数
@ -46,7 +44,8 @@ class TranslationModeStats {
return TranslationModeStats(
apiCalls: apiCalls ?? this.apiCalls,
sourceCharacters: sourceCharacters ?? this.sourceCharacters,
effectiveAudioDuration: effectiveAudioDuration ?? this.effectiveAudioDuration,
effectiveAudioDuration:
effectiveAudioDuration ?? this.effectiveAudioDuration,
ttsCharacters: ttsCharacters ?? this.ttsCharacters,
cost: cost ?? this.cost,
);
@ -158,7 +157,7 @@ class TranslationUsageStats {
final double estimatedCost; // 预估成本
final String currency; // 货币单位
final Map<String, double> costBreakdown; // 成本分解(ASR/TTS/Translation)
TranslationUsageStats({
required this.id,
required this.date,
@ -196,7 +195,8 @@ class TranslationUsageStats {
final languagePairStatsMap = <String, LanguagePairStats>{};
if (json['languagePairStats'] != null) {
final languagePairStatsJson = json['languagePairStats'] as Map<String, dynamic>;
final languagePairStatsJson =
json['languagePairStats'] as Map<String, dynamic>;
languagePairStatsJson.forEach((key, value) {
languagePairStatsMap[key] = LanguagePairStats.fromJson(value);
});
@ -219,9 +219,15 @@ class TranslationUsageStats {
asrApiCalls: json['asrApiCalls'] ?? 0,
ttsApiCalls: json['ttsApiCalls'] ?? 0,
aiSummaryApiCalls: json['aiSummaryApiCalls'] ?? 0,
sourceTextCharacters: json['sourceTextCharacters'] ?? json['sourceCharacterCount'] ?? 0, // 兼容旧字段
effectiveAudioDuration: json['effectiveAudioDuration'] ?? json['audioRecordingDuration'] ?? 0, // 兼容旧字段
ttsTextCharacters: json['ttsTextCharacters'] ?? json['targetCharacterCount'] ?? 0, // 兼容旧字段
sourceTextCharacters: json['sourceTextCharacters'] ??
json['sourceCharacterCount'] ??
0, // 兼容旧字段
effectiveAudioDuration: json['effectiveAudioDuration'] ??
json['audioRecordingDuration'] ??
0, // 兼容旧字段
ttsTextCharacters: json['ttsTextCharacters'] ??
json['targetCharacterCount'] ??
0, // 兼容旧字段
totalSessionDuration: json['totalSessionDuration'] ?? 0,
asrNetworkBytes: json['asrNetworkBytes'] ?? 0,
ttsNetworkBytes: json['ttsNetworkBytes'] ?? 0,
@ -328,12 +334,14 @@ class TranslationUsageStats {
ttsApiCalls: ttsApiCalls ?? this.ttsApiCalls,
aiSummaryApiCalls: aiSummaryApiCalls ?? this.aiSummaryApiCalls,
sourceTextCharacters: sourceTextCharacters ?? this.sourceTextCharacters,
effectiveAudioDuration: effectiveAudioDuration ?? this.effectiveAudioDuration,
effectiveAudioDuration:
effectiveAudioDuration ?? this.effectiveAudioDuration,
ttsTextCharacters: ttsTextCharacters ?? this.ttsTextCharacters,
totalSessionDuration: totalSessionDuration ?? this.totalSessionDuration,
asrNetworkBytes: asrNetworkBytes ?? this.asrNetworkBytes,
ttsNetworkBytes: ttsNetworkBytes ?? this.ttsNetworkBytes,
translationNetworkBytes: translationNetworkBytes ?? this.translationNetworkBytes,
translationNetworkBytes:
translationNetworkBytes ?? this.translationNetworkBytes,
sessionCount: sessionCount ?? this.sessionCount,
modeStats: modeStats ?? this.modeStats,
languagePairStats: languagePairStats ?? this.languagePairStats,
@ -345,7 +353,8 @@ class TranslationUsageStats {
}
/// 获取总API调用次数
int get totalApiCalls => translationApiCalls + asrApiCalls + ttsApiCalls + aiSummaryApiCalls;
int get totalApiCalls =>
translationApiCalls + asrApiCalls + ttsApiCalls + aiSummaryApiCalls;
/// 获取总字符数(精确计费基础)
int get totalCharacterCount => sourceTextCharacters + ttsTextCharacters;
@ -354,19 +363,21 @@ class TranslationUsageStats {
int get totalAudioDuration => effectiveAudioDuration + totalSessionDuration;
/// 获取总网络流量
int get totalNetworkBytes => asrNetworkBytes + ttsNetworkBytes + translationNetworkBytes;
int get totalNetworkBytes =>
asrNetworkBytes + ttsNetworkBytes + translationNetworkBytes;
/// 获取最常用的语言对
String get mostUsedLanguagePair {
if (languagePairStats.isEmpty) return '无数据';
if (languagePairStats.isEmpty) return 'null';
return languagePairStats.entries
.reduce((a, b) => a.value.translationCount > b.value.translationCount ? a : b)
.reduce((a, b) =>
a.value.translationCount > b.value.translationCount ? a : b)
.key;
}
/// 获取最常用的翻译模式
String get mostUsedMode {
if (modeStats.isEmpty) return '无数据';
if (modeStats.isEmpty) return 'null';
return modeStats.entries
.reduce((a, b) => a.value.apiCalls > b.value.apiCalls ? a : b)
.key;

2
lib/modules/common/widgets/language_selector_bar.dart

@ -58,7 +58,7 @@ class LanguageSelectorBar extends StatelessWidget {
isDarkMode ? AppColors.primary.withOpacity(0.2) : Colors.blue[50];
final swapIconColor = isDarkMode ? AppColors.primary : Colors.blue;
// 规范化特殊项的翻译键,例如:自动检测 -> autoDetect(翻译键代表的中文文本内容)
// 规范化特殊项的翻译键,例如:自动检测 -> autoDetect(对应中文:自动检测)
String _normalizeKey(String text) {
switch (text) {
case '自动检测':

8
lib/modules/common/widgets/recharge_dialog.dart

@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../routes/app_routes.dart';
/// 显示充值弹窗
/// [type] 充值类型,可选值为 'agent'、'translation'、'meeting'
/// 分别跳转对应ai充值、翻译充值、会议充值界面
void showRechargeDialog(String type) {
Get.dialog(
Dialog(
@ -24,7 +27,10 @@ void showRechargeDialog(String type) {
),
const SizedBox(height: 12),
Text(
'insufficientBalanceDesc'.tr, //'余额不足,请前往对应充值界面进行充值',
(type == 'agent'
? 'aiMemberExpiredDesc'
: 'insufficientBalanceDesc')
.tr, // 会员过期描述 / 余额不足描述
textAlign: TextAlign.center,
),
const SizedBox(height: 20),

3
lib/modules/meeting/controllers/meeting_home_controller.dart

@ -410,7 +410,8 @@ class MeetingHomeController extends GetxController {
Logger.error('importFailed'
.tr
.replaceAll('{filePath}', filePath)
.replaceAll('{error}', e.toString())); // 翻译键代表的中文文本内容
.replaceAll('{error}',
e.toString())); // 对应中文:导入文件失败: {filePath}, error: {error}
}
} else {
effectivePath = filePath;

87
lib/modules/picture_translation/controllers/picture_translation_controller.dart

@ -34,8 +34,8 @@ class PictureTranslationController extends GetxController {
final isProcessing = false.obs;
final pickedImageFile = Rx<File?>(null);
final currentStep = ProcessingStep(
title: '等待操作',
description: '请选择图片开始翻译',
title: 'waitingForAction'.tr, // 等待操作
description: 'pleaseSelectImageToStart'.tr, // 请选择图片开始翻译
status: ProcessingStatus.idle,
).obs;
@ -152,13 +152,17 @@ class PictureTranslationController extends GetxController {
if (source == ImageSource.camera) {
final status = await Permission.camera.request();
if (!status.isGranted) {
Get.snackbar('权限需求', '需要相机权限才能拍照');
Get.snackbar(
'permissionRequired'.tr, // 权限需求
'cameraPermissionRequired'.tr); // 需要相机权限才能拍照
return false;
}
} else {
final status = await Permission.photos.request();
if (!status.isGranted) {
Get.snackbar('权限需求', '需要相册权限才能选择图片');
Get.snackbar(
'permissionRequired'.tr, // 权限需求
'photoAlbumPermissionRequired'.tr); // 需要相册权限才能选择图片
return false;
}
}
@ -194,8 +198,10 @@ class PictureTranslationController extends GetxController {
try {
isProcessing.value = true;
_updateStep(
'选择图片',
'正在打开${source == ImageSource.camera ? '相机' : '相册'}...',
'chooseImage'.tr, // 选择图片
(source == ImageSource.camera
? 'openingCamera'.tr // 正在打开相机...
: 'openingPhotoAlbum'.tr), // 正在打开相册...
ProcessingStatus.picking);
final XFile? image = await _imagePicker.pickImage(
@ -206,7 +212,10 @@ class PictureTranslationController extends GetxController {
);
if (image == null) {
_updateStep('已取消', '用户取消了选择', ProcessingStatus.idle);
_updateStep(
'cancelled'.tr, // 已取消
'userCancelledSelection'.tr, // 用户取消了选择
ProcessingStatus.idle);
return;
}
@ -217,23 +226,39 @@ class PictureTranslationController extends GetxController {
pickedImageFile.value = file;
// 直接调用图片翻译API(包含识别+回贴)
_updateStep('翻译图片', '正在调用图片翻译服务...', ProcessingStatus.translating,
_updateStep(
'translatingImage'.tr, // 翻译图片
'callingImageTranslateService'.tr, // 正在调用图片翻译服务...
ProcessingStatus.translating,
progress: 0.6);
await _performImageTranslation(file);
// 保存历史记录
if (sourceText.value.isNotEmpty && translatedText.value.isNotEmpty) {
_updateStep('保存记录', '正在保存翻译结果...', ProcessingStatus.saving,
_updateStep(
'savingRecord'.tr, // 保存记录
'savingTranslationResult'.tr, // 正在保存翻译结果...
ProcessingStatus.saving,
progress: 0.9);
await _saveTranslationResult(file);
}
_updateStep('翻译完成', '所有步骤已完成', ProcessingStatus.idle, progress: 1.0);
_updateStep(
'translationCompleted'.tr, // 翻译完成
'allStepsCompleted'.tr, // 所有步骤已完成
ProcessingStatus.idle,
progress: 1.0);
} catch (e) {
Logger.error('PictureTranslation', '处理失败: $e');
_updateStep('处理失败', e.toString(), ProcessingStatus.error);
_showErrorDialog('处理失败', '图片处理或翻译失败,请重试。\n错误信息: $e');
_updateStep(
'processingFailed'.tr, // 处理失败
e.toString(),
ProcessingStatus.error);
_showErrorDialog(
'processingFailed'.tr, // 处理失败
'imageProcessingOrTranslationFailed'.tr.replaceAll(
'{error}', e.toString())); // 图片处理或翻译失败,请重试。错误信息: {error}
} finally {
isProcessing.value = false;
}
@ -286,8 +311,13 @@ class PictureTranslationController extends GetxController {
// 图片大小限制:4MB(文档要求)
const int maxSize = 4 * 1024 * 1024;
if (bytes.lengthInBytes > maxSize) {
_updateStep('处理失败', '图片大小超过4MB限制', ProcessingStatus.error);
_showErrorDialog('处理失败', '图片大小超过4MB限制,请降低质量或尺寸后重试');
_updateStep(
'processingFailed'.tr, // 处理失败
'imageTooLarge'.tr, // 图片大小超过4MB限制
ProcessingStatus.error);
_showErrorDialog(
'processingFailed'.tr, // 处理失败
'imageTooLargeHint'.tr); // 图片大小超过4MB限制,请降低质量或尺寸后重试
return;
}
@ -301,8 +331,13 @@ class PictureTranslationController extends GetxController {
);
if (result == null) {
_updateStep('处理失败', '图片翻译接口返回空结果', ProcessingStatus.error);
_showErrorDialog('处理失败', '图片翻译失败,可能的原因:网络异常或接口限流,请稍后重试');
_updateStep(
'processingFailed'.tr, // 处理失败
'emptyTranslationResult'.tr, // 图片翻译接口返回空结果
ProcessingStatus.error);
_showErrorDialog(
'processingFailed'.tr, // 处理失败
'imageTranslationFailedTryLater'.tr); // 失败原因提示
return;
}
@ -322,8 +357,13 @@ class PictureTranslationController extends GetxController {
}
} catch (e) {
Logger.error('PictureTranslation', '图片翻译调用失败: $e');
_updateStep('处理失败', e.toString(), ProcessingStatus.error);
_showErrorDialog('处理失败', '图片翻译接口调用异常,请检查网络后重试');
_updateStep(
'processingFailed'.tr, // 处理失败
e.toString(),
ProcessingStatus.error);
_showErrorDialog(
'processingFailed'.tr, // 处理失败
'imageTranslationApiException'.tr); // 接口调用异常
}
}
@ -362,7 +402,7 @@ class PictureTranslationController extends GetxController {
actions: [
TextButton(
onPressed: () => Get.back(),
child: const Text('确定'),
child: Text('confirm'.tr), // 确认
),
],
),
@ -403,7 +443,9 @@ class PictureTranslationController extends GetxController {
void copyText(String text) {
if (text.isNotEmpty) {
// 这里可以添加复制到剪切板的逻辑
Get.snackbar('成功', '文本已复制到剪切板');
Get.snackbar(
'success'.tr, // 成功
'copied'.tr); // 已复制
}
}
@ -413,6 +455,9 @@ class PictureTranslationController extends GetxController {
translatedText.value = '';
translatedImageBytes.value = null;
pickedImageFile.value = null;
_updateStep('等待操作', '请选择图片开始翻译', ProcessingStatus.idle);
_updateStep(
'waitingForAction'.tr, // 等待操作
'pleaseSelectImageToStart'.tr, // 请选择图片开始翻译
ProcessingStatus.idle);
}
}

60
lib/modules/picture_translation/views/picture_translation_history_detail_view.dart

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../core/theme/app_colors.dart';
@ -20,8 +21,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor:
isDarkMode ? AppColors.darkBackground : Colors.grey[50],
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.grey[50],
appBar: AppBar(
leading: IconButton(
icon: Icon(
@ -32,7 +32,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
onPressed: () => Get.back(),
),
centerTitle: true,
title: Text('翻译详情',
title: Text('translationDetails'.tr, // 翻译详情
style: TextStyle(
color: isDarkMode ? AppColors.textPrimary : Colors.black87)),
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
@ -56,9 +56,15 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
SizedBox(height: 16.h),
_buildLanguageInfo(),
SizedBox(height: 16.h),
_buildTextSection('识别结果', item.sourceText, Colors.blue),
_buildTextSection(
'recognitionResult'.tr, // 识别结果
item.sourceText,
Colors.blue),
SizedBox(height: 16.h),
_buildTextSection('翻译结果', item.translatedText, Colors.green),
_buildTextSection(
'translationResult'.tr, // 翻译结果
item.translatedText,
Colors.green),
SizedBox(height: 16.h),
_buildTimeInfo(),
],
@ -89,12 +95,11 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
Padding(
padding: EdgeInsets.all(16.w),
child: Text(
'原图片',
'originalImage'.tr, // 原图片
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
color: Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
),
),
),
@ -122,7 +127,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
size: 48.sp, color: AppColors.error),
SizedBox(height: 8.h),
Text(
'图片加载失败',
'imageLoadFailed'.tr, // 图片加载失败
style: TextStyle(
fontSize: 14.sp, color: AppColors.error),
),
@ -161,7 +166,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'源语言',
'sourceLanguage'.tr, // 源语言
style: TextStyle(
fontSize: 12.sp,
color: Get.isDarkMode
@ -170,7 +175,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
),
SizedBox(height: 4.h),
Text(
item.sourceLanguageName,
item.sourceLanguageName.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -187,7 +192,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'目标语言',
'targetLanguage'.tr, // 目标语言
style: TextStyle(
fontSize: 12.sp,
color: Get.isDarkMode
@ -196,7 +201,7 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
),
SizedBox(height: 4.h),
Text(
item.targetLanguageName,
item.targetLanguageName.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -245,11 +250,13 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
icon: Icon(Icons.copy, size: 20.sp, color: color),
onPressed: () {
Clipboard.setData(ClipboardData(text: content));
Get.snackbar('成功', '已复制到剪切板');
Get.snackbar(
'success'.tr, // 成功
'copied'.tr); // 已复制
},
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
tooltip: '复制',
tooltip: 'copy'.tr, // 复制
),
],
),
@ -287,12 +294,11 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'翻译时间',
'translationTime'.tr, // 翻译时间
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
color: Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
),
),
SizedBox(height: 8.h),
@ -300,7 +306,8 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
_formatDateTime(item.timestamp),
style: TextStyle(
fontSize: 14.sp,
color: Get.isDarkMode ? AppColors.textSecondary : Colors.grey[600],
color:
Get.isDarkMode ? AppColors.textSecondary : Colors.grey[600],
),
),
],
@ -309,17 +316,18 @@ class PictureTranslationHistoryDetailView extends StatelessWidget {
}
String _formatDateTime(DateTime dateTime) {
return '${dateTime.year}年${dateTime.month}月${dateTime.day}日 '
'${dateTime.hour.toString().padLeft(2, '0')}:'
'${dateTime.minute.toString().padLeft(2, '0')}';
return DateFormat('yyyy-MM-dd HH:mm').format(dateTime);
}
void _shareTranslation() {
final shareText = '原文:${item.sourceText}\n\n'
'译文:${item.translatedText}\n\n'
'翻译方向:${item.sourceLanguageName} → ${item.targetLanguageName}';
final shareText = '${'originalText'.tr}:${item.sourceText}\n\n' // 原文
'${'translatedText'.tr}:${item.translatedText}\n\n' // 译文
'${'sourceLanguage'.tr}:${item.sourceLanguageName.tr} → ' // 源语言
'${'targetLanguage'.tr}:${item.targetLanguageName.tr}'; // 目标语言
// 这里可以调用分享插件
Get.snackbar('提示', '分享功能开发中');
Get.snackbar(
'tip'.tr, // 提示
'shareInDevelopment'.tr); // 分享功能开发中
}
}

192
lib/modules/picture_translation/views/picture_translation_view.dart

@ -21,8 +21,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor:
isDarkMode ? AppColors.darkBackground : Colors.grey[50],
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.grey[50],
appBar: _buildAppBar(isDarkMode),
body: SafeArea(
child: Obx(() {
@ -85,7 +84,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
IconButton(
icon: const Icon(Icons.history),
onPressed: _showHistoryBottomSheet,
tooltip: 'historyRecords'.tr, //历史记录
tooltip: 'historyRecords'.tr, // 历史记录
),
PopupMenuButton<String>(
onSelected: _handleMenuAction,
@ -157,12 +156,11 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'选择图片来源'.tr, //选择图片来源
'selectImageSource'.tr, // 选择图片来源
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
color: Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
),
),
SizedBox(height: 12.h),
@ -277,12 +275,11 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Padding(
padding: EdgeInsets.all(16.w),
child: Text(
'图片预览',
'imagePreview'.tr, // 图片预览
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
color: Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
),
),
),
@ -377,8 +374,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
),
);
case ProcessingStatus.error:
return Icon(Icons.error_outline,
color: AppColors.error, size: 20.sp);
return Icon(Icons.error_outline, color: AppColors.error, size: 20.sp);
case ProcessingStatus.idle:
return Icon(Icons.check_circle_outline,
color: AppColors.success, size: 20.sp);
@ -423,25 +419,24 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Padding(
padding: EdgeInsets.all(16.w),
child: Text(
'翻译结果',
'translationResult'.tr, // 翻译结果
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
color: Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
),
),
),
if (controller.sourceText.value.isNotEmpty)
_buildTextCard(
'识别结果',
'recognitionResult'.tr, // 识别结果
controller.sourceText.value,
controller.sourceLanguageChineseName.value,
Colors.blue,
),
if (controller.translatedText.value.isNotEmpty)
_buildTextCard(
'翻译结果',
'translationResult'.tr, // 翻译结果
controller.translatedText.value,
controller.targetLanguageChineseName.value,
Colors.green,
@ -449,22 +444,22 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
if (controller.translatedImageBytes.value != null) ...[
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Text(
'翻译后的图片预览',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
child: Text(
'translatedImagePreview'.tr, // 翻译后的图片预览
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color:
Get.isDarkMode ? AppColors.textPrimary : Colors.black87,
),
),
),
),
SizedBox(height: 8.h),
Container(
height: 200.h,
margin:
EdgeInsets.symmetric(horizontal: 16.w).copyWith(bottom: 16.h),
decoration: BoxDecoration(
SizedBox(height: 8.h),
Container(
height: 200.h,
margin:
EdgeInsets.symmetric(horizontal: 16.w).copyWith(bottom: 16.h),
decoration: BoxDecoration(
color: Get.isDarkMode
? AppColors.cardBackground
: Colors.grey[100],
@ -491,7 +486,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
size: 48.sp, color: Colors.red[400]),
SizedBox(height: 8.h),
Text(
'翻译图片加载失败',
'translatedImageLoadFailed'.tr, // 翻译图片加载失败
style: TextStyle(
fontSize: 14.sp, color: Colors.red[600]),
),
@ -517,8 +512,8 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
decoration: BoxDecoration(
color: color.withOpacity(Get.isDarkMode ? 0.15 : 0.05),
borderRadius: BorderRadius.circular(8.r),
border: Border.all(
color: color.withOpacity(Get.isDarkMode ? 0.3 : 0.2)),
border:
Border.all(color: color.withOpacity(Get.isDarkMode ? 0.3 : 0.2)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -538,11 +533,11 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
icon: Icon(Icons.copy, size: 18.sp, color: color),
onPressed: () {
Clipboard.setData(ClipboardData(text: content));
Get.snackbar('success'.tr, 'copied'.tr); // 翻译键代表的中文文本内容
Get.snackbar('success'.tr, 'copied'.tr); // 对应中文:复制成功
},
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
tooltip: 'copy'.tr, // 翻译键代表的中文文本内容
tooltip: 'copy'.tr, // 复制
),
],
),
@ -551,8 +546,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
content,
style: TextStyle(
fontSize: 15.sp,
color:
Get.isDarkMode ? Colors.white70 : Colors.black87,
color: Get.isDarkMode ? Colors.white70 : Colors.black87,
height: 1.4),
),
],
@ -584,7 +578,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'translationHistory'.tr, // 翻译键代表的中文文本内容
'translationHistory'.tr, // 翻译历史
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -594,7 +588,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
),
TextButton(
onPressed: _showHistoryBottomSheet,
child: Text('viewAll'.tr), // 翻译键代表的中文文本内容
child: Text('viewAll'.tr), // 查看全部
),
],
),
@ -604,7 +598,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
padding:
EdgeInsets.symmetric(horizontal: 16.w).copyWith(bottom: 16.h),
child: Text(
'noTranslationHistory'.tr, // 翻译键代表的中文文本内容
'noTranslationHistory'.tr, // 暂无历史记录
style: TextStyle(
fontSize: 14.sp,
color: Get.isDarkMode
@ -629,8 +623,9 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
child: Container(
width: 40.w,
height: 40.w,
color:
Get.isDarkMode ? Colors.white.withOpacity(0.05) : Colors.grey[200],
color: Get.isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[200],
child: Icon(Icons.image,
color: Get.isDarkMode ? Colors.white70 : Colors.grey[400]),
),
@ -642,18 +637,16 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
style: TextStyle(fontSize: 14.sp),
),
subtitle: Text(
'${item.sourceLanguageName} → ${item.targetLanguageName}',
'${item.sourceLanguageName.tr} → ${item.targetLanguageName.tr}', // 源语言名/目标语言名
style: TextStyle(
fontSize: 12.sp,
color:
Get.isDarkMode ? AppColors.textSecondary : Colors.grey[600]),
color: Get.isDarkMode ? AppColors.textSecondary : Colors.grey[600]),
),
trailing: Text(
_formatTime(item.timestamp),
style: TextStyle(
fontSize: 12.sp,
color:
Get.isDarkMode ? Colors.white54 : Colors.grey[500]),
color: Get.isDarkMode ? Colors.white54 : Colors.grey[500]),
),
onTap: () => _showHistoryDetail(item),
);
@ -675,19 +668,16 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'translationHistory'.tr, // 翻译键代表的中文文本内容
'translationHistory'.tr, // 翻译历史
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Get.isDarkMode
? AppColors.textPrimary
: null),
color: Get.isDarkMode ? AppColors.textPrimary : null),
),
IconButton(
onPressed: () => Get.back(),
icon: Icon(Icons.close,
color:
Get.isDarkMode ? AppColors.textPrimary : null),
color: Get.isDarkMode ? AppColors.textPrimary : null),
),
],
),
@ -698,7 +688,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
if (controller.historyList.isEmpty) {
return Center(
child: Text(
'noTranslationHistory'.tr, // 翻译键代表的中文文本内容
'noTranslationHistory'.tr, // 暂无历史记录
style: TextStyle(
fontSize: 16.sp,
color: Get.isDarkMode
@ -745,13 +735,18 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
final difference = now.difference(timestamp);
if (difference.inDays > 0) {
return '${difference.inDays}天前';
return 'daysAgo'
.tr
.replaceAll('@days', difference.inDays.toString()); // @days天前
} else if (difference.inHours > 0) {
return '${difference.inHours}小时前';
return 'hoursAgo'
.tr
.replaceAll('@hours', difference.inHours.toString()); // @hours小时前
} else if (difference.inMinutes > 0) {
return '${difference.inMinutes}分钟前';
return 'minutesAgo'.tr.replaceAll(
'@minutes', difference.inMinutes.toString()); // @minutes分钟前
} else {
return '刚刚';
return 'justNow'.tr; // 刚刚
}
}
@ -759,7 +754,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Get.dialog(
AlertDialog(
backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white,
title: Text('设置',
title: Text('settings'.tr, // 设置
style: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black87)),
content: Column(
@ -768,16 +763,17 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
ListTile(
leading: Icon(Icons.photo_size_select_actual,
color: Get.isDarkMode ? Colors.white : null),
title: Text('图片质量',
title: Text('imageQuality'.tr, // 图片质量
style: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black87)),
subtitle: Obx(() => Text(
'currentQuality'.tr.replaceAll(
'@value',
controller.imageQuality.value
.toString()), // 当前质量: @value%
style: TextStyle(
color:
Get.isDarkMode ? Colors.white : Colors.black87)),
subtitle:
Obx(() => Text('当前: ${controller.imageQuality.value}%',
style: TextStyle(
color: Get.isDarkMode
? Colors.white70
: Colors.black54))),
Get.isDarkMode ? Colors.white70 : Colors.black54))),
onTap: () {
Get.back();
_showImageQualityDialog();
@ -786,16 +782,15 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
ListTile(
leading: Icon(Icons.photo_size_select_large,
color: Get.isDarkMode ? Colors.white : null),
title: Text('最大尺寸',
title: Text('maxSize'.tr, // 最大尺寸
style: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black87)),
subtitle: Obx(() => Text(
'currentMaxSize'.tr.replaceAll('@px',
controller.maxImageSize.value.toString()), // 当前: @pxpx
style: TextStyle(
color:
Get.isDarkMode ? Colors.white : Colors.black87)),
subtitle:
Obx(() => Text('当前: ${controller.maxImageSize.value}px',
style: TextStyle(
color: Get.isDarkMode
? Colors.white70
: Colors.black54))),
Get.isDarkMode ? Colors.white70 : Colors.black54))),
onTap: () {
Get.back();
_showImageSizeDialog();
@ -806,7 +801,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('关闭',
child: Text('close'.tr, // 关闭
style: TextStyle(
color: Get.isDarkMode ? Colors.white70 : Colors.black54)),
),
@ -819,13 +814,17 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Get.dialog(
AlertDialog(
backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white,
title: Text('设置图片质量',
title: Text('setImageQuality'.tr, // 设置图片质量
style: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black87)),
content: Obx(() => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('当前质量: ${controller.imageQuality.value}%',
Text(
'currentQuality'.tr.replaceAll(
'@value',
controller.imageQuality.value
.toString()), // 当前质量: @value%
style: TextStyle(
color:
Get.isDarkMode ? Colors.white70 : Colors.black54)),
@ -843,7 +842,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('确定',
child: Text('confirm'.tr, // 确认
style: TextStyle(
color: Get.isDarkMode ? Colors.white70 : Colors.black54)),
),
@ -857,7 +856,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Get.dialog(
AlertDialog(
backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white,
title: Text('设置最大尺寸',
title: Text('setMaxSize'.tr, // 设置最大尺寸
style: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black87)),
content: Column(
@ -879,7 +878,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('取消',
child: Text('cancel'.tr, // 取消
style: TextStyle(
color: Get.isDarkMode ? Colors.white70 : Colors.black54)),
),
@ -892,16 +891,16 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
Get.dialog(
AlertDialog(
backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white,
title: Text('清空历史',
title: Text('clearHistory'.tr, // 清除历史记录
style: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black87)),
content: Text('确定要清空所有翻译历史吗?此操作不可撤销。',
content: Text('clearHistoryConfirm'.tr, // 确定要清除所有翻译历史记录吗?此操作无法撤销。
style: TextStyle(
color: Get.isDarkMode ? Colors.white70 : Colors.black54)),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('取消',
child: Text('cancel'.tr, // 取消
style: TextStyle(
color: Get.isDarkMode ? Colors.white70 : Colors.black54)),
),
@ -910,7 +909,8 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
controller.clearHistory();
Get.back();
},
child: Text('确定', style: TextStyle(color: AppColors.error)),
child: Text('confirm'.tr, // 确认
style: TextStyle(color: AppColors.error)),
),
],
),
@ -923,11 +923,10 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
height: 200.h,
margin: EdgeInsets.symmetric(horizontal: 16.w).copyWith(bottom: 16.h),
decoration: BoxDecoration(
color:
Get.isDarkMode ? AppColors.cardBackground : Colors.grey[100],
color: Get.isDarkMode ? AppColors.cardBackground : Colors.grey[100],
borderRadius: BorderRadius.circular(8.r),
border:
Border.all(color: Get.isDarkMode ? Colors.white12 : Colors.grey[300]!),
border: Border.all(
color: Get.isDarkMode ? Colors.white12 : Colors.grey[300]!),
),
child: file == null
? Center(
@ -936,10 +935,11 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
children: [
Icon(Icons.image_outlined,
size: 48.sp,
color: Get.isDarkMode ? Colors.white54 : Colors.grey[400]),
color:
Get.isDarkMode ? Colors.white54 : Colors.grey[400]),
SizedBox(height: 8.h),
Text(
'请选择图片',
'pleaseSelectImage'.tr, // 请选择图片
style: TextStyle(
fontSize: 14.sp,
color: Get.isDarkMode
@ -967,7 +967,7 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
size: 48.sp, color: Colors.red[400]),
SizedBox(height: 8.h),
Text(
'图片加载失败',
'imageLoadFailed'.tr, // 图片加载失败
style: TextStyle(
fontSize: 14.sp,
color: Get.isDarkMode
@ -985,11 +985,15 @@ class PictureTranslationView extends GetView<PictureTranslationController> {
}
Widget _buildSourceTextBox() {
return _buildTextBox('识别结果', controller.sourceText.value);
return _buildTextBox(
'recognitionResult'.tr, // 识别结果
controller.sourceText.value);
}
Widget _buildTranslatedTextBox() {
return _buildTextBox('翻译结果', controller.translatedText.value);
return _buildTextBox(
'translationResult'.tr, // 翻译结果
controller.translatedText.value);
}
Widget _buildTextBox(String title, String content) {

8
lib/modules/text_translation/controllers/text_translation_controller.dart

@ -257,8 +257,8 @@ class TextTranslationController extends GetxController {
if (detectedAsrCode == null || detectedAsrCode.isEmpty) {
Logger.error('语种检测失败');
Get.snackbar(
'error'.tr, // 翻译键代表的中文文本内容
'languageDetectionFailed'.tr, // 翻译键代表的中文文本内容
'error'.tr, // 错误
'languageDetectionFailed'.tr, // 语言检测失败
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.9),
colorText: Colors.white,
@ -288,8 +288,8 @@ class TextTranslationController extends GetxController {
} catch (e) {
Logger.error('翻译失败: $e');
Get.snackbar(
'error'.tr,
'translationFailed'.tr,
'error'.tr, // 错误
'translationFailed'.tr, // 翻译失败
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.9),
colorText: Colors.white,

8
lib/modules/text_translation/views/text_translation_view.dart

@ -99,10 +99,12 @@ class TextTranslationView extends GetView<TextTranslationController> {
return LanguageSelectorBar(
sourceText: () => controller.sourceLanguageChineseName.value,
targetText: () => controller.targetLanguageChineseName.value,
onTapSource: () => controller.showLanguageSelector(isSourceLanguage: true),
onTapTarget: () => controller.showLanguageSelector(isSourceLanguage: false),
onTapSource: () =>
controller.showLanguageSelector(isSourceLanguage: true),
onTapTarget: () =>
controller.showLanguageSelector(isSourceLanguage: false),
onSwap: controller.swapLanguages,
translateLanguageNames: true, // 翻译键代表的中文文本内容
translateLanguageNames: true, // 是否翻译语言名称
fontSizeSp: 15,
);
}

2
lib/modules/translation/middleware/controllers/translation_middleware_controller.dart

@ -91,7 +91,7 @@ class TranslationMiddlewareController extends GetxController {
void navigateToTranslationFeature(TranslationOption option) {
// 不可用则提示用户连接设备
if (!isOptionEnabled(option)) {
// 翻译键代表的中文文本内容
// 连接设备 / 请连接 Voitrans 设备
Get.snackbar('connectDevice'.tr,
'pleaseConnectDeepSoundDevice'.tr, // 连接设备 / 请连接 Voitrans 设备
snackPosition: SnackPosition.TOP,

8
lib/modules/translation/views/dialogs/language_selection_dialog.dart

@ -65,8 +65,8 @@ class LanguageSelectionDialog {
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Text(
isSource
? 'selectSourceLanguage'.tr // 翻译键代表的中文文本内容
: 'selectTargetLanguage'.tr, // 翻译键代表的中文文本内容
? 'selectSourceLanguage'.tr // 选择源语言
: 'selectTargetLanguage'.tr, // 选择目标语言
style: TextStyle(
fontSize: 18.sp, // 调整字号
fontWeight: FontWeight.w600, // 使用数字字重
@ -94,7 +94,7 @@ class LanguageSelectionDialog {
: displayLanguages[
hasAutoDetect ? index - 1 : index];
final displayText = isAutoDetectItem
? 'autoDetect'.tr // 翻译键代表的中文文本内容
? 'autoDetect'.tr // 自动检测
: (translateLanguageNames
? valueText.tr
: valueText);
@ -196,7 +196,7 @@ class LanguageSelectionDialog {
child: TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr, // 翻译键代表的中文文本内容
'cancel'.tr, // 取消
style: TextStyle(
color: isDarkMode ? const Color(0xFF6200EE) : Colors.blue,
),

4
lib/modules/translation/views/translation_view.dart

@ -314,7 +314,7 @@ class TranslationView extends GetView<TranslationController> {
onTapTarget: () =>
LanguageSelectionDialog.show(false, isDarkMode),
onSwap: controller.swapLanguages,
translateLanguageNames: true, // 翻译键代表的中文文本内容
translateLanguageNames: true, // 是否翻译语言名称
fontSizeSp: 15,
targetSuffix: controller.currentMode.value == 'call'
? Icon(
@ -1019,7 +1019,7 @@ class TranslationView extends GetView<TranslationController> {
onTapSource: () => LanguageSelectionDialog.show(true, isDarkMode),
onTapTarget: () => LanguageSelectionDialog.show(false, isDarkMode),
onSwap: controller.swapLanguages,
translateLanguageNames: true, // 翻译键代表的中文文本内容
translateLanguageNames: true, // 是否翻译语言名称
fontSizeSp: 15,
),
);

4
lib/modules/translation/views/widgets/translation_item_widget.dart

@ -140,7 +140,7 @@ class TranslationItemWidget extends GetView<TranslationController> {
child: Container(
padding: EdgeInsets.all(4.w),
child: Tooltip(
message: 'copy'.tr, // 翻译键代表的中文文本内容
message: 'copy'.tr, // 复制
child: Icon(
Icons.copy,
size: 20.sp,
@ -169,7 +169,7 @@ class TranslationItemWidget extends GetView<TranslationController> {
child: Container(
padding: EdgeInsets.all(4.w),
child: Tooltip(
message: 'delete'.tr, // 翻译键代表的中文文本内容
message: 'delete'.tr, // 删除
child: Icon(
Icons.delete_outline,
size: 20.sp,

72
lib/modules/usage/controllers/meeting_stats_controller.dart

@ -8,34 +8,32 @@ class MeetingStatsController extends GetxController {
final isLoading = false.obs;
final selectedTabIndex = 0.obs;
final selectedTimeRange = '今日'.obs;
final Rx<MeetingAsrHistoryStats> todayStats =
MeetingAsrHistoryStats(
userId: '',
allAsrCalls: 0,
allAudioSeconds: 0,
allAudioFileBytes: 0,
allTranscriptBytes: 0,
).obs;
final Rx<MeetingAsrHistoryStats> weekStats =
MeetingAsrHistoryStats(
userId: '',
allAsrCalls: 0,
allAudioSeconds: 0,
allAudioFileBytes: 0,
allTranscriptBytes: 0,
).obs;
final Rx<MeetingAsrHistoryStats> monthStats =
MeetingAsrHistoryStats(
userId: '',
allAsrCalls: 0,
allAudioSeconds: 0,
allAudioFileBytes: 0,
allTranscriptBytes: 0,
).obs;
final RxList<MeetingAsrDailyStats> historyDaily = <MeetingAsrDailyStats>[].obs;
final selectedTimeRange = 'today'.tr.obs; // 今日
final Rx<MeetingAsrHistoryStats> todayStats = MeetingAsrHistoryStats(
userId: '',
allAsrCalls: 0,
allAudioSeconds: 0,
allAudioFileBytes: 0,
allTranscriptBytes: 0,
).obs;
final Rx<MeetingAsrHistoryStats> weekStats = MeetingAsrHistoryStats(
userId: '',
allAsrCalls: 0,
allAudioSeconds: 0,
allAudioFileBytes: 0,
allTranscriptBytes: 0,
).obs;
final Rx<MeetingAsrHistoryStats> monthStats = MeetingAsrHistoryStats(
userId: '',
allAsrCalls: 0,
allAudioSeconds: 0,
allAudioFileBytes: 0,
allTranscriptBytes: 0,
).obs;
final RxList<MeetingAsrDailyStats> historyDaily =
<MeetingAsrDailyStats>[].obs;
@override
void onInit() {
@ -72,7 +70,8 @@ class MeetingStatsController extends GetxController {
final historyStart = now.subtract(const Duration(days: 7));
historyDaily.value = await _usageService.getMeetingHistoryStats(
startDate: DateTime(historyStart.year, historyStart.month, historyStart.day),
startDate:
DateTime(historyStart.year, historyStart.month, historyStart.day),
endDate: DateTime(now.year, now.month, now.day),
);
@ -88,16 +87,16 @@ class MeetingStatsController extends GetxController {
selectedTabIndex.value = index;
switch (index) {
case 0:
selectedTimeRange.value = '今日';
selectedTimeRange.value = 'today'.tr; // 今日
break;
case 1:
selectedTimeRange.value = '本周';
selectedTimeRange.value = 'thisWeek'.tr; // 本周
break;
case 2:
selectedTimeRange.value = '本月';
selectedTimeRange.value = 'thisMonth'.tr; // 本月
break;
case 3:
selectedTimeRange.value = '历史';
selectedTimeRange.value = 'history'.tr; // 历史
break;
}
}
@ -117,15 +116,15 @@ class MeetingStatsController extends GetxController {
String formatDuration(int seconds) {
if (seconds < 60) {
return '$seconds秒';
return '$seconds${'seconds'.tr}'; // 秒
} else if (seconds < 3600) {
final minutes = seconds ~/ 60;
final remainingSeconds = seconds % 60;
return '$minutes分$remainingSeconds秒';
return '$minutes${'minutes'.tr}$remainingSeconds${'seconds'.tr}'; // 分钟秒
} else {
final hours = seconds ~/ 3600;
final minutes = (seconds % 3600) ~/ 60;
return '$hours小时$minutes分';
return '$hours${'hours'.tr}$minutes${'minutes'.tr}'; // 小时分钟
}
}
@ -149,4 +148,3 @@ class MeetingStatsController extends GetxController {
await loadAllStats();
}
}

34
lib/modules/usage/controllers/translation_stats_controller.dart

@ -9,7 +9,7 @@ class TranslationStatsController extends GetxController {
final isLoading = false.obs;
final selectedTabIndex = 0.obs;
final selectedTimeRange = '今日'.obs;
final selectedTimeRange = 'today'.tr.obs; // 今日
final Rx<TranslationUsageStats> todayStats =
TranslationUsageStats.empty('').obs;
@ -62,8 +62,8 @@ class TranslationStatsController extends GetxController {
} catch (e) {
Logger.error('加载统计数据失败: $e');
Get.snackbar(
'加载失败',
'统计数据加载失败,请稍后重试',
'loadFailed'.tr, // 加载失败
'statsLoadFailedTryLater'.tr, // 统计数据加载失败,请稍后重试
snackPosition: SnackPosition.TOP,
backgroundColor: Get.theme.colorScheme.error.withValues(alpha: 0.1),
colorText: Get.theme.colorScheme.error,
@ -180,7 +180,7 @@ class TranslationStatsController extends GetxController {
switch (selectedTabIndex.value) {
case 0:
data.add({
'label': '今日',
'label': 'today'.tr, // 今日
'apiCalls': todayStats.value.totalApiCalls,
'cost': 0.0,
'characters': todayStats.value.totalCharacterCount,
@ -188,7 +188,7 @@ class TranslationStatsController extends GetxController {
break;
case 1:
data.add({
'label': '本周',
'label': 'thisWeek'.tr, // 本周
'apiCalls': weekStats.value.totalApiCalls,
'cost': 0.0,
'characters': weekStats.value.totalCharacterCount,
@ -196,7 +196,7 @@ class TranslationStatsController extends GetxController {
break;
case 2:
data.add({
'label': '本月',
'label': 'thisMonth'.tr, // 本月
'apiCalls': monthStats.value.totalApiCalls,
'cost': 0.0,
'characters': monthStats.value.totalCharacterCount,
@ -222,16 +222,16 @@ class TranslationStatsController extends GetxController {
switch (index) {
case 0:
selectedTimeRange.value = '今日';
selectedTimeRange.value = 'today'.tr; // 今日
break;
case 1:
selectedTimeRange.value = '本周';
selectedTimeRange.value = 'thisWeek'.tr; // 本周
break;
case 2:
selectedTimeRange.value = '本月';
selectedTimeRange.value = 'thisMonth'.tr; // 本月
break;
case 3:
selectedTimeRange.value = '历史';
selectedTimeRange.value = 'history'.tr; // 历史
break;
}
@ -258,8 +258,8 @@ class TranslationStatsController extends GetxController {
void cleanupOldData() {
_usageService.cleanupOldData();
Get.snackbar(
'清理完成',
'已清理90天前的过期数据',
'cleanupComplete'.tr, // 清理完成
'cleanedOldData'.tr, // 已清理90天前的过期数据
snackPosition: SnackPosition.TOP,
backgroundColor: Get.theme.colorScheme.primary.withValues(alpha: 0.1),
colorText: Get.theme.colorScheme.primary,
@ -269,8 +269,8 @@ class TranslationStatsController extends GetxController {
Future<void> exportStats() async {
try {
Get.snackbar(
'导出功能',
'数据导出功能正在开发中',
'exportFeature'.tr, // 导出功能
'exportInDevelopment'.tr, // 数据导出功能正在开发中
snackPosition: SnackPosition.TOP,
backgroundColor: Get.theme.colorScheme.primary.withValues(alpha: 0.1),
colorText: Get.theme.colorScheme.primary,
@ -282,15 +282,15 @@ class TranslationStatsController extends GetxController {
String formatDuration(int seconds) {
if (seconds < 60) {
return '$seconds秒';
return '$seconds${'seconds'.tr}'; // 秒
} else if (seconds < 3600) {
final minutes = seconds ~/ 60;
final remainingSeconds = seconds % 60;
return '$minutes分$remainingSeconds秒';
return '$minutes${'minutes'.tr}$remainingSeconds${'seconds'.tr}'; // 分钟秒
} else {
final hours = seconds ~/ 3600;
final minutes = (seconds % 3600) ~/ 60;
return '$hours小时$minutes分';
return '$hours${'hours'.tr}$minutes${'minutes'.tr}'; // 小时分钟
}
}

4
lib/modules/usage/views/aichat_stats_view.dart

@ -29,7 +29,7 @@ class AiChatStatsView extends GetView<AiChatStatsController> {
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.white,
elevation: 0.5,
title: Text(
'AI chat',
'aiChat'.tr, // AI聊天
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
@ -70,7 +70,7 @@ class AiChatStatsView extends GetView<AiChatStatsController> {
SizedBox(width: 8.w),
Expanded(
child: Text(
'AI聊天积分',
'remainingQuota'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,

22
lib/modules/usage/views/meeting_stats_view.dart

@ -31,7 +31,7 @@ class MeetingStatsView extends GetView<MeetingStatsController> {
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.white,
elevation: 0.5,
title: Text(
'会议统计',
'meetingStats'.tr, // 会议统计
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
@ -91,7 +91,7 @@ class MeetingStatsView extends GetView<MeetingStatsController> {
SizedBox(width: 8.w),
Expanded(
child: Text(
'会议积分',
'remainingQuota'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -127,10 +127,10 @@ class MeetingStatsView extends GetView<MeetingStatsController> {
),
child: Obx(() => Row(
children: [
_buildTimeRangeTab('今日', 0, isDarkMode),
_buildTimeRangeTab('本周', 1, isDarkMode),
_buildTimeRangeTab('本月', 2, isDarkMode),
_buildTimeRangeTab('历史', 3, isDarkMode),
_buildTimeRangeTab('today'.tr, 0, isDarkMode), // 今日
_buildTimeRangeTab('thisWeek'.tr, 1, isDarkMode), // 本周
_buildTimeRangeTab('thisMonth'.tr, 2, isDarkMode), // 本月
_buildTimeRangeTab('history'.tr, 3, isDarkMode), // 历史
],
)),
);
@ -186,7 +186,7 @@ class MeetingStatsView extends GetView<MeetingStatsController> {
Icon(Icons.dashboard, color: AppColors.primary, size: 20.sp),
SizedBox(width: 8.w),
Obx(() => Text(
'${controller.selectedTimeRange.value}概览',
'${controller.selectedTimeRange.value}${'overview'.tr}',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -199,13 +199,13 @@ class MeetingStatsView extends GetView<MeetingStatsController> {
children: [
Expanded(
child: _buildStatItem(
'ASR调用次数',
'asrApiCalls'.tr, // ASR调用次数
controller.formatNumber(stats.allAsrCalls),
Icons.api,
isDarkMode)),
Expanded(
child: _buildStatItem(
'音频总时长',
'totalAudioDuration'.tr, // 音频总时长
controller.formatDuration(stats.allAudioSeconds),
Icons.mic,
isDarkMode)),
@ -216,13 +216,13 @@ class MeetingStatsView extends GetView<MeetingStatsController> {
children: [
Expanded(
child: _buildStatItem(
'音频文件大小',
'audioFileSize'.tr, // 音频文件大小
controller.formatBytes(stats.allAudioFileBytes),
Icons.folder,
isDarkMode)),
Expanded(
child: _buildStatItem(
'转写字节',
'transcriptBytes'.tr, // 转写字节
controller.formatNumber(stats.allTranscriptBytes),
Icons.text_snippet,
isDarkMode)),

76
lib/modules/usage/views/translation_stats_view.dart

@ -36,7 +36,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
title: GestureDetector(
onTap: controller.onTitleTap,
child: Text(
'翻译统计',
'translationStats'.tr, //
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
@ -143,7 +143,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
SizedBox(width: 8.w),
Expanded(
child: Text(
'翻译积分',
'remainingQuota'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -180,10 +180,10 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
child: Obx(() => Row(
children: [
_buildTimeRangeTab('今日', 0, isDarkMode),
_buildTimeRangeTab('本周', 1, isDarkMode),
_buildTimeRangeTab('本月', 2, isDarkMode),
_buildTimeRangeTab('历史', 3, isDarkMode),
_buildTimeRangeTab('today'.tr, 0, isDarkMode), // 今日
_buildTimeRangeTab('thisWeek'.tr, 1, isDarkMode), // 本周
_buildTimeRangeTab('thisMonth'.tr, 2, isDarkMode), // 本月
_buildTimeRangeTab('history'.tr, 3, isDarkMode), // 历史
],
)),
);
@ -245,7 +245,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
SizedBox(width: 8.w),
Text(
'当前会话统计',
'currentSessionStats'.tr, // 当前会话统计
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -259,7 +259,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
children: [
Expanded(
child: _buildStatItem(
'翻译次数',
'translationCount'.tr, // 翻译次数
controller.realtimeStats.translationCount.toString(),
Icons.translate,
isDarkMode,
@ -267,8 +267,8 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
Expanded(
child: _buildStatItem(
'会话时长',
'${controller.realtimeStats.sessionDurationMinutes}分钟',
'sessionDuration'.tr, // 会话时长
'${controller.realtimeStats.sessionDurationMinutes}${'minutes'.tr}',
Icons.timer,
isDarkMode,
),
@ -280,7 +280,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
children: [
Expanded(
child: _buildStatItem(
'字符数',
'characters'.tr, // 字符数
controller.formatNumber(
controller.realtimeStats.sourceCharacters +
controller.realtimeStats.targetCharacters,
@ -291,7 +291,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
Expanded(
child: _buildStatItem(
'录音时长',
'recordingDuration'.tr, // 录音时长
controller.formatDuration(
controller.realtimeStats.recordingDuration),
Icons.mic,
@ -331,7 +331,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
SizedBox(width: 8.w),
Obx(() => Text(
'${controller.selectedTimeRange.value}概览',
'${controller.selectedTimeRange.value}${'overview'.tr}',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -345,7 +345,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
children: [
Expanded(
child: _buildStatItem(
'总调用次数',
'totalApiCalls'.tr, // 总调用次数
controller
.formatNumber(controller.currentStats.totalApiCalls),
Icons.api,
@ -359,7 +359,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
children: [
Expanded(
child: _buildStatItem(
'会话数量',
'sessionCount'.tr, // 会话数量
controller.currentStats.sessionCount.toString(),
Icons.chat,
isDarkMode,
@ -367,7 +367,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
Expanded(
child: _buildStatItem(
'总字符数',
'totalCharacters'.tr, // 总字符数
controller.formatNumber(
controller.currentStats.totalCharacterCount),
Icons.text_snippet,
@ -437,7 +437,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
SizedBox(width: 8.w),
Text(
'API调用统计',
'apiCallStats'.tr, // API调用统计
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -450,19 +450,25 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
Obx(() => Column(
children: [
_buildApiCallRow(
'翻译API',
'translationApi'.tr, // 翻译API
controller.currentStats.translationApiCalls,
Icons.translate,
isDarkMode),
SizedBox(height: 12.h),
_buildApiCallRow('语音识别', controller.currentStats.asrApiCalls,
Icons.mic, isDarkMode),
_buildApiCallRow(
'asr'.tr,
controller.currentStats.asrApiCalls,
Icons.mic,
isDarkMode),
SizedBox(height: 12.h),
_buildApiCallRow('语音合成', controller.currentStats.ttsApiCalls,
Icons.volume_up, isDarkMode),
_buildApiCallRow(
'tts'.tr,
controller.currentStats.ttsApiCalls,
Icons.volume_up,
isDarkMode),
SizedBox(height: 12.h),
_buildApiCallRow(
'AI摘要',
'aiSummary'.tr, // AI总结
controller.currentStats.aiSummaryApiCalls,
Icons.summarize,
isDarkMode),
@ -530,7 +536,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
SizedBox(width: 8.w),
Text(
'数据量统计',
'dataVolumeStats'.tr, // 数据量统计
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -546,7 +552,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
children: [
Expanded(
child: _buildStatItem(
'源文本字符',
'sourceTextCharacters'.tr, // 源文本字符
controller.formatNumber(
controller.currentStats.sourceTextCharacters),
Icons.text_fields,
@ -555,7 +561,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
Expanded(
child: _buildStatItem(
'TTS文本字符',
'ttsTextCharacters'.tr, // TTS文本字符
controller.formatNumber(
controller.currentStats.ttsTextCharacters),
Icons.translate,
@ -569,7 +575,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
children: [
Expanded(
child: _buildStatItem(
'有效音频时长',
'effectiveAudioDuration'.tr, // 有效音频时长
controller.formatDuration(
controller.currentStats.effectiveAudioDuration),
Icons.mic,
@ -578,7 +584,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
Expanded(
child: _buildStatItem(
'总会话时长',
'totalSessionDuration'.tr, // 总会话时长
controller.formatDuration(
controller.currentStats.totalSessionDuration),
Icons.volume_up,
@ -620,7 +626,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
SizedBox(width: 8.w),
Text(
'成本统计',
'costStats'.tr, // 成本统计
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -642,7 +648,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${controller.selectedTimeRange.value}预估成本',
'${controller.selectedTimeRange.value}${'estimatedCost'.tr}',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
@ -666,7 +672,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'日成本预警阈值',
'dailyCostThreshold'.tr, // 日成本预警阈值
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
@ -687,7 +693,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'月成本预警阈值',
'monthlyCostThreshold'.tr, // 月成本预警阈值
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.black54,
@ -736,7 +742,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
),
SizedBox(width: 8.w),
Text(
'使用行为统计',
'usageBehaviorStats'.tr, // 使用行为统计
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -749,14 +755,14 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
Obx(() => Column(
children: [
_buildUsageBehaviorRow(
'最常用语言对',
'mostUsedLanguagePair'.tr, // 最常用语言对
controller.currentStats.mostUsedLanguagePair,
Icons.language,
isDarkMode,
),
SizedBox(height: 12.h),
_buildUsageBehaviorRow(
'最常用模式',
'mostUsedMode'.tr, // 最常用模式
controller.currentStats.mostUsedMode,
Icons.settings,
isDarkMode,

2
lib/modules/usage/views/usage_view.dart

@ -43,7 +43,7 @@ class UsageView extends GetView<UsageController> {
// 4. 使用生成的导航项
items: (controller.showAiChat.value
? const [
_NavItem(Icons.chat_bubble_outline, 'AI chat'),
_NavItem(Icons.chat_bubble_outline, 'aiChat'),
_NavItem(Icons.translate, 'interpretation'),
_NavItem(Icons.people, 'meeting'),
]

Loading…
Cancel
Save