feat(i18n): 完成全量 UI 文本国际化,替换所有硬编码中文为 AppLocalizations 调用

- core/localization: 新增约 60 个翻译键(含参数化方法),中英双语覆盖
- shared/widgets: CommonDialog 默认参数国际化
- features/home: 完成页操作步骤指引、状态栏串口连接状态、程序列表状态标签
- features/programs: 表头状态列、表单验证提示、导入/模板操作反馈、删除确认(参数化)
- features/program_detail: 步骤列表/表单标题、删除确认、速度档位显示(参数化)
- features/device: run_state_provider 错误消息改为错误码
- features/settings: 升级页、密码面板、语言面板、U盘导入面板、串口配置面板全部替换

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Developer
2026-06-12 15:09:47 +08:00
parent 5d65744618
commit 3d849bd468
23 changed files with 688 additions and 127 deletions

View File

@@ -259,7 +259,7 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
SizedBox(
width: 80,
child: Text(
'状态',
l10n?.status ?? '状态',
style: TextStyle(
fontWeight: FontWeight.w600,
color: AppTheme.textPrimary,
@@ -358,7 +358,7 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
borderRadius: BorderRadius.circular(4),
),
child: Text(
program.status == 1 ? '启用' : '停用',
program.status == 1 ? (l10n?.enabled ?? '启用') : (l10n?.disabled ?? '停用'),
style: TextStyle(
color: program.status == 1
? AppTheme.successColor
@@ -413,6 +413,7 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
/// 导入程序
Future<void> _importPrograms(BuildContext context, WidgetRef ref) async {
final l10n = AppLocalizations.of(context);
try {
// 选择文件
final result = await FilePicker.platform.pickFiles(
@@ -428,7 +429,7 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
final file = result.files.first;
if (file.path == null) {
if (!context.mounted) return;
ToastService.showError(context, '无法读取文件');
ToastService.showError(context, l10n?.cannotReadFile ?? '无法读取文件');
return;
}
@@ -441,25 +442,26 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
if (!context.mounted) return;
if (importedCount > 0) {
ToastService.showSuccess(context, '成功处理 $importedCount 个程序');
ToastService.showSuccess(context, l10n?.processedPrograms(importedCount) ?? '成功处理 $importedCount 个程序');
} else {
ToastService.showWarning(context, 'Excel 中无有效程序数据');
ToastService.showWarning(context, l10n?.noValidProgramData ?? 'Excel 中无有效程序数据');
}
} catch (e) {
if (!context.mounted) return;
ToastService.showError(context, '导入失败: ${e.toString()}');
ToastService.showError(context, '${l10n?.importFailed ?? '导入失败'}: ${e.toString()}');
}
}
/// 下载 Excel 模板
Future<void> _downloadTemplate(BuildContext context) async {
final l10n = AppLocalizations.of(context);
try {
final path = await ExcelTemplateService.instance.generateTemplate();
if (!context.mounted) return;
ToastService.showSuccess(context, '模板已保存: $path');
ToastService.showSuccess(context, '${l10n?.templateSaved ?? '模板已保存'}: $path');
} catch (e) {
if (!context.mounted) return;
ToastService.showError(context, '生成模板失败: ${e.toString()}');
ToastService.showError(context, '${l10n?.generateTemplateFailed ?? '生成模板失败'}: ${e.toString()}');
}
}
@@ -484,8 +486,8 @@ class _ProgramsPageState extends ConsumerState<ProgramsPage> {
title: Text(l10n?.confirm ?? '确认'),
content: Text(
ids.length == 1
? '确定要删除此程序吗?'
: '确定要删除选中的 ${ids.length} 个程序吗?',
? (l10n?.deleteConfirmSingle ?? '确定要删除此程序吗?')
: (l10n?.deleteConfirmMultiple(ids.length) ?? '确定要删除选中的 ${ids.length} 个程序吗?'),
),
actions: [
TextButton(

View File

@@ -71,14 +71,14 @@ class _ProgramFormDialogState extends ConsumerState<ProgramFormDialog> {
controller: _codeController,
decoration: InputDecoration(
labelText: l10n?.programCode ?? '编号',
hintText: '例如: P001',
hintText: l10n?.hintCode ?? '例如: P001',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return '请输入编号';
return l10n?.enterCode ?? '请输入编号';
}
return null;
},
@@ -90,14 +90,14 @@ class _ProgramFormDialogState extends ConsumerState<ProgramFormDialog> {
controller: _nameController,
decoration: InputDecoration(
labelText: l10n?.programName ?? '名称',
hintText: '请输入程序名称',
hintText: l10n?.hintProgramName ?? '请输入程序名称',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return '请输入名称';
return l10n?.enterName ?? '请输入名称';
}
return null;
},
@@ -140,7 +140,7 @@ class _ProgramFormDialogState extends ConsumerState<ProgramFormDialog> {
Row(
children: [
Text(
'状态',
l10n?.status ?? '状态',
style: TextStyle(color: AppTheme.textPrimary),
),
const Spacer(),
@@ -154,7 +154,7 @@ class _ProgramFormDialogState extends ConsumerState<ProgramFormDialog> {
activeColor: AppTheme.successColor,
),
Text(
_isEnabled ? '启用' : '停用',
_isEnabled ? (l10n?.enabled ?? '启用') : (l10n?.disabled ?? '停用'),
style: TextStyle(
color: _isEnabled ? AppTheme.successColor : AppTheme.idleColor,
),
@@ -222,7 +222,7 @@ class _ProgramFormDialogState extends ConsumerState<ProgramFormDialog> {
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('保存失败,请检查编号是否重复'),
content: Text(l10n?.saveFailed ?? '保存失败,请检查编号是否重复'),
backgroundColor: AppTheme.errorColor,
),
);