From 6254d06c7a90c5212d8ebd558105b0737085110a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Mon, 15 Jun 2026 15:06:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96:=20CR-08=20i18n=20batch2?= =?UTF-8?q?=E5=85=A8=E9=87=8F(ProjectDetail5=E5=A4=84+TaskDetail16key+AiCh?= =?UTF-8?q?at3=E5=A4=84+store=20error=20fallback=2023=E5=A4=84+useAiSend?= =?UTF-8?q?=203=E5=A4=84)+@/i18n=E8=B7=AF=E5=BE=84=E7=BB=9F=E4=B8=80+vite?= =?UTF-8?q?=E5=88=AB=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AiChat.vue | 7 +++---- src/composables/ai/useAiEvents.ts | 2 +- src/composables/ai/useAiSend.ts | 9 +++++--- src/composables/ai/useAiStream.ts | 2 +- src/i18n/en/ai.ts | 2 ++ src/i18n/en/aiChat.ts | 3 +++ src/i18n/en/ideas.ts | 6 ++++++ src/i18n/en/knowledge.ts | 12 +++++++++++ src/i18n/en/projectDetail.ts | 8 ++++++++ src/i18n/en/projects.ts | 11 ++++++++++ src/i18n/en/taskDetail.ts | 24 ++++++++++++++++++++++ src/i18n/en/tasks.ts | 6 ++++++ src/i18n/zh-CN/ai.ts | 2 ++ src/i18n/zh-CN/aiChat.ts | 3 +++ src/i18n/zh-CN/ideas.ts | 6 ++++++ src/i18n/zh-CN/knowledge.ts | 12 +++++++++++ src/i18n/zh-CN/projectDetail.ts | 8 ++++++++ src/i18n/zh-CN/projects.ts | 11 ++++++++++ src/i18n/zh-CN/taskDetail.ts | 24 ++++++++++++++++++++++ src/i18n/zh-CN/tasks.ts | 6 ++++++ src/utils/time.ts | 2 +- src/views/ProjectDetail.vue | 13 ++++++------ src/views/Settings.vue | 2 +- src/views/TaskDetail.vue | 34 ++++++++++++++++--------------- 24 files changed, 181 insertions(+), 34 deletions(-) create mode 100644 src/i18n/en/taskDetail.ts create mode 100644 src/i18n/zh-CN/taskDetail.ts diff --git a/src/components/AiChat.vue b/src/components/AiChat.vue index 2276277..db58c58 100644 --- a/src/components/AiChat.vue +++ b/src/components/AiChat.vue @@ -104,7 +104,7 @@ - @@ -468,8 +468,7 @@ async function confirmDeleteConversation(id: string) { /** 清空当前对话(真删 DB messages,带二次确认防误删) */ async function confirmClearChat() { - // i18n 不在本任务白名单:文案硬编码,后续补 aiChat.confirmClearChat key - if (!await confirmDialog('确定清空当前对话的所有消息?此操作不可恢复。')) return + if (!await confirmDialog(t('aiChat.confirmClearChat'))) return await store.clearChat() } @@ -685,7 +684,7 @@ async function handleSend() { pendingSkill.value = skill // 用户可见提示(原仅 console.error,用户无感);Tauri IPC 错误是字符串非 Error 对象 const msg = e instanceof Error ? e.message : String(e) - showToast(`发送失败:${msg}`, 'error') + showToast(t('aiChat.toastSendFail', { msg }), 'error') } await nextTick() scrollToBottom() diff --git a/src/composables/ai/useAiEvents.ts b/src/composables/ai/useAiEvents.ts index a7ecd8b..9a3eb07 100644 --- a/src/composables/ai/useAiEvents.ts +++ b/src/composables/ai/useAiEvents.ts @@ -13,7 +13,7 @@ import { listen, emit } from '@tauri-apps/api/event' import { aiApi } from '../../api' import { useAppSettingsStore } from '../../stores/appSettings' import { state } from '../../stores/ai' -import i18n from '../../i18n' +import i18n from '@/i18n' import { nextMsgId } from './aiShared' import { resetStreamWatchdog, clearStreamWatchdog } from './useAiStream' import { drainQueue } from './useAiSend' diff --git a/src/composables/ai/useAiSend.ts b/src/composables/ai/useAiSend.ts index ae1e248..a0141fe 100644 --- a/src/composables/ai/useAiSend.ts +++ b/src/composables/ai/useAiSend.ts @@ -13,10 +13,13 @@ import { invoke } from '@tauri-apps/api/core' import { aiApi } from '../../api' import { useAppSettingsStore } from '../../stores/appSettings' import { state } from '../../stores/ai' +import i18n from '../../i18n' import { resetStreamWatchdog, clearStreamWatchdog } from './useAiStream' import { startListener, findToolCall } from './useAiEvents' import { nextMsgId } from './aiShared' +const t = ((i18n as any).global.t as (k: string, named?: Record) => string).bind((i18n as any).global) + const appSettings = useAppSettingsStore() /// 待发送队列上限(超过抛错提示用户) @@ -46,7 +49,7 @@ async function sendMessage(text: string, skill?: string) { } if (backendGenerating) { if (state.queue.length >= QUEUE_LIMIT) { - throw new Error(`待发送队列已满(最多 ${QUEUE_LIMIT} 条)`) + throw new Error(t('ai.queueFull', { limit: QUEUE_LIMIT })) } // 后端真在生成但本地 streaming 已复位(false):状态不同步——对齐本地 streaming=true // 让用户感知(禁用输入框等),并入队等待 AiCompleted 续发;不入队则消息静默丢失。 @@ -62,7 +65,7 @@ async function sendMessage(text: string, skill?: string) { // 生成中:进入待发送队列,当前对话完成后(AiCompleted)由 drainQueue 自动续发 if (state.streaming) { if (state.queue.length >= QUEUE_LIMIT) { - throw new Error(`待发送队列已满(最多 ${QUEUE_LIMIT} 条)`) + throw new Error(t('ai.queueFull', { limit: QUEUE_LIMIT })) } state.queue.push({ text: text.trim(), skill: skill || undefined }) return @@ -127,7 +130,7 @@ async function approveToolCall(toolCallId: string, approved: boolean) { console.error('[AI] 审批操作未送达后端:', e) if (tc) { tc.status = 'completed' - tc.result = `审批操作未送达后端:${e instanceof Error ? e.message : String(e)}` + tc.result = t('ai.approvalNotDelivered', { error: e instanceof Error ? e.message : String(e) }) } throw e } diff --git a/src/composables/ai/useAiStream.ts b/src/composables/ai/useAiStream.ts index 57ed7dc..fa683ba 100644 --- a/src/composables/ai/useAiStream.ts +++ b/src/composables/ai/useAiStream.ts @@ -12,7 +12,7 @@ //! 循环依赖;下沉到 aiShared 后本模块不再 import useAiEvents,环消除) import { state } from '../../stores/ai' -import i18n from '../../i18n' +import i18n from '@/i18n' import { nextMsgId } from './aiShared' // composable 内非组件上下文(无 setup),用 vue-i18n 全局实例的 t 而非 useI18n()。 diff --git a/src/i18n/en/ai.ts b/src/i18n/en/ai.ts index 4da3c24..0eca252 100644 --- a/src/i18n/en/ai.ts +++ b/src/i18n/en/ai.ts @@ -12,5 +12,7 @@ export default { errorNetwork: 'Network connection failed. Please check your network.', streamInterruptedAfterTool: '⚠ The tool finished, but the following reply was interrupted (no data stream for a long time). You can click Continue to retry.', streamInterrupted: '⚠ The response was interrupted (no data stream for a long time). This may be due to a network disconnection or a backend error. Please try again.', + queueFull: 'Send queue is full (max {limit} items)', + approvalNotDelivered: 'Approval operation failed to reach the backend: {error}', }, } diff --git a/src/i18n/en/aiChat.ts b/src/i18n/en/aiChat.ts index 797680d..63e90b6 100644 --- a/src/i18n/en/aiChat.ts +++ b/src/i18n/en/aiChat.ts @@ -60,5 +60,8 @@ export default { // ── Confirm dialog ── confirmDeleteConversation: 'Delete chat "{title}"? This cannot be undone.', + clearChat: 'Clear', + confirmClearChat: 'Are you sure you want to clear all messages in this chat? This cannot be undone.', + toastSendFail: 'Send failed: {msg}', }, } diff --git a/src/i18n/en/ideas.ts b/src/i18n/en/ideas.ts index f1103ac..7de8799 100644 --- a/src/i18n/en/ideas.ts +++ b/src/i18n/en/ideas.ts @@ -76,5 +76,11 @@ export default { confirmDelete: 'Delete idea "{title}"? This cannot be undone.', promoteFailed: 'Promotion failed', evalFailed: 'Evaluation failed', + // Error fallbacks (user-visible via state.error) + err: { + loadFailed: 'Failed to load ideas', + createFailed: 'Failed to create idea', + deleteFailed: 'Failed to delete idea', + }, }, } diff --git a/src/i18n/en/knowledge.ts b/src/i18n/en/knowledge.ts index e77cf65..21df75a 100644 --- a/src/i18n/en/knowledge.ts +++ b/src/i18n/en/knowledge.ts @@ -74,5 +74,17 @@ export default { deployment_note: 'Deployment Note', workflow_optimization: 'Workflow Optimization', }, + // Error fallbacks (user-visible via state.error) + err: { + loadFailed: 'Failed to load knowledge base', + loadInboxFailed: 'Failed to load inbox', + searchFailed: 'Search failed', + createFailed: 'Failed to create knowledge', + updateStatusFailed: 'Failed to update status', + archiveFailed: 'Failed to archive', + loadConfigFailed: 'Failed to load config', + saveConfigFailed: 'Failed to save config', + extractFailed: 'Extraction failed', + }, }, } diff --git a/src/i18n/en/projectDetail.ts b/src/i18n/en/projectDetail.ts index db6d13a..44faab7 100644 --- a/src/i18n/en/projectDetail.ts +++ b/src/i18n/en/projectDetail.ts @@ -55,6 +55,14 @@ export default { relocateConfirmRelocate: 'Relocate project directory to:\n{dir}\n\nTech stack will be re-detected. Confirm?', relocateConfirmBind: 'Bind project directory to:\n{dir}\n\nTech stack will be re-detected. Confirm?', relocateFailed: 'Relocate failed: {msg}', + // Import directory + importDir: 'Import Directory', + importConfirm: 'Import as new project?\n{dir}\n\nThe directory name will be used as project name, tech stack will be detected, and README first section will fill description.', + importSuccess: 'Imported project "{name}"', + importFailed: 'Import failed: {msg}', + // Approval actions + approvalConfirm: 'Confirm ({count})', + approvalCancel: 'Cancel', // Tech stack techStackLabel: 'Tech Stack', }, diff --git a/src/i18n/en/projects.ts b/src/i18n/en/projects.ts index b26d243..92af1a7 100644 --- a/src/i18n/en/projects.ts +++ b/src/i18n/en/projects.ts @@ -45,5 +45,16 @@ export default { cancelled: '❌ Cancelled', active: '🚀 In Progress', }, + // Error fallbacks (user-visible via state.error) + err: { + loadFailed: 'Failed to load projects', + createFailed: 'Failed to create project', + importFailed: 'Failed to import project', + deleteFailed: 'Failed to delete project', + loadTrashFailed: 'Failed to load trash', + restoreFailed: 'Failed to restore project', + purgeFailed: 'Failed to delete permanently', + loadWorkflowFailed: 'Failed to load workflow records', + }, }, } diff --git a/src/i18n/en/taskDetail.ts b/src/i18n/en/taskDetail.ts new file mode 100644 index 0000000..8749e8e --- /dev/null +++ b/src/i18n/en/taskDetail.ts @@ -0,0 +1,24 @@ +export default { + taskDetail: { + // Header + backToList: '← Back to Tasks', + refresh: 'Refresh', + // Status hints + loading: 'Loading...', + loadFailed: 'Failed to load', + // Panel + infoTitle: 'Task Info', + // Field labels + title: 'Title', + description: 'Description', + status: 'Status', + priority: 'Priority', + project: 'Project', + branch: 'Branch', + assignee: 'Assignee', + baseBranch: 'Base Branch', + workflowDef: 'Workflow Definition', + createdAt: 'Created At', + updatedAt: 'Updated At', + }, +} diff --git a/src/i18n/en/tasks.ts b/src/i18n/en/tasks.ts index 9a3fc17..7d0d0bc 100644 --- a/src/i18n/en/tasks.ts +++ b/src/i18n/en/tasks.ts @@ -52,5 +52,11 @@ export default { merged: '✅ Merged', abandoned: '🗑️ Abandoned', }, + // Error fallbacks (user-visible via state.error) + err: { + loadFailed: 'Failed to load tasks', + createFailed: 'Failed to create task', + deleteFailed: 'Failed to delete task', + }, }, } diff --git a/src/i18n/zh-CN/ai.ts b/src/i18n/zh-CN/ai.ts index af05afd..78321c7 100644 --- a/src/i18n/zh-CN/ai.ts +++ b/src/i18n/zh-CN/ai.ts @@ -12,5 +12,7 @@ export default { errorNetwork: '网络连接失败,请检查网络', streamInterruptedAfterTool: '⚠ 工具已执行完成,后续回复中断(长时间无数据流)。可点继续重试。', streamInterrupted: '⚠ 响应中断(长时间无数据流)。可能是网络断连或后端异常,请重试。', + queueFull: '待发送队列已满(最多 {limit} 条)', + approvalNotDelivered: '审批操作未送达后端:{error}', }, } diff --git a/src/i18n/zh-CN/aiChat.ts b/src/i18n/zh-CN/aiChat.ts index bccb57f..c316f62 100644 --- a/src/i18n/zh-CN/aiChat.ts +++ b/src/i18n/zh-CN/aiChat.ts @@ -60,5 +60,8 @@ export default { // ── 确认弹层 ── confirmDeleteConversation: '确定删除对话「{title}」?该操作不可恢复。', + clearChat: '清空', + confirmClearChat: '确定清空当前对话的所有消息?此操作不可恢复。', + toastSendFail: '发送失败:{msg}', }, } diff --git a/src/i18n/zh-CN/ideas.ts b/src/i18n/zh-CN/ideas.ts index 5c93208..684d013 100644 --- a/src/i18n/zh-CN/ideas.ts +++ b/src/i18n/zh-CN/ideas.ts @@ -76,5 +76,11 @@ export default { confirmDelete: '确定删除灵感「{title}」?此操作不可撤销。', promoteFailed: '立项失败', evalFailed: '评估失败', + // 错误回退(state.error 用户可见) + err: { + loadFailed: '加载灵感失败', + createFailed: '创建灵感失败', + deleteFailed: '删除灵感失败', + }, }, } diff --git a/src/i18n/zh-CN/knowledge.ts b/src/i18n/zh-CN/knowledge.ts index 2e2d0c7..b1216e8 100644 --- a/src/i18n/zh-CN/knowledge.ts +++ b/src/i18n/zh-CN/knowledge.ts @@ -90,5 +90,17 @@ export default { deployment_note: '部署经验', workflow_optimization: '工作流优化', }, + // 错误回退(state.error 用户可见) + err: { + loadFailed: '加载知识库失败', + loadInboxFailed: '加载收件箱失败', + searchFailed: '检索失败', + createFailed: '创建知识失败', + updateStatusFailed: '更新状态失败', + archiveFailed: '归档失败', + loadConfigFailed: '加载配置失败', + saveConfigFailed: '保存配置失败', + extractFailed: '立即抽取失败', + }, }, } diff --git a/src/i18n/zh-CN/projectDetail.ts b/src/i18n/zh-CN/projectDetail.ts index 1ae5e92..f72edd7 100644 --- a/src/i18n/zh-CN/projectDetail.ts +++ b/src/i18n/zh-CN/projectDetail.ts @@ -55,6 +55,14 @@ export default { relocateConfirmRelocate: '将项目目录重定位到:\n{dir}\n\n技术栈将重新探测。确认?', relocateConfirmBind: '将项目目录绑定到:\n{dir}\n\n技术栈将重新探测。确认?', relocateFailed: '重定位失败: {msg}', + // 导入目录 + importDir: '导入目录', + importConfirm: '导入目录为新项目?\n{dir}\n\n将自动用目录名作项目名,探测技术栈,并读 README 首段填描述。', + importSuccess: '已导入项目「{name}」', + importFailed: '导入失败: {msg}', + // 审批操作 + approvalConfirm: '确认({count})', + approvalCancel: '取消', // 技术栈 techStackLabel: '技术栈', }, diff --git a/src/i18n/zh-CN/projects.ts b/src/i18n/zh-CN/projects.ts index 67e2d57..119d5a0 100644 --- a/src/i18n/zh-CN/projects.ts +++ b/src/i18n/zh-CN/projects.ts @@ -44,5 +44,16 @@ export default { cancelled: '❌ 已取消', active: '🚀 进行中', }, + // 错误回退(state.error 用户可见) + err: { + loadFailed: '加载项目失败', + createFailed: '创建项目失败', + importFailed: '导入项目失败', + deleteFailed: '删除项目失败', + loadTrashFailed: '加载回收站失败', + restoreFailed: '恢复项目失败', + purgeFailed: '彻底删除失败', + loadWorkflowFailed: '加载工作流记录失败', + }, }, } diff --git a/src/i18n/zh-CN/taskDetail.ts b/src/i18n/zh-CN/taskDetail.ts new file mode 100644 index 0000000..7802fa1 --- /dev/null +++ b/src/i18n/zh-CN/taskDetail.ts @@ -0,0 +1,24 @@ +export default { + taskDetail: { + // 头部 + backToList: '← 返回任务列表', + refresh: '刷新', + // 状态提示 + loading: '加载中...', + loadFailed: '加载失败', + // 面板 + infoTitle: '任务信息', + // 字段标签 + title: '标题', + description: '描述', + status: '状态', + priority: '优先级', + project: '关联项目', + branch: '分支', + assignee: '负责人', + baseBranch: '基础分支', + workflowDef: '工作流定义', + createdAt: '创建时间', + updatedAt: '更新时间', + }, +} diff --git a/src/i18n/zh-CN/tasks.ts b/src/i18n/zh-CN/tasks.ts index ea18b00..14bce65 100644 --- a/src/i18n/zh-CN/tasks.ts +++ b/src/i18n/zh-CN/tasks.ts @@ -52,5 +52,11 @@ export default { merged: '✅ 已合并', abandoned: '🗑️ 已放弃', }, + // 错误回退(state.error 用户可见) + err: { + loadFailed: '加载任务失败', + createFailed: '创建任务失败', + deleteFailed: '删除任务失败', + }, }, } diff --git a/src/utils/time.ts b/src/utils/time.ts index 6ff138e..1ff9d7b 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -11,7 +11,7 @@ * 正确做法:先转 number 再 new Date。本模块统一处理毫秒字符串 / 秒级 / ISO / number / 空。 */ -import i18n from '../i18n' +import i18n from '@/i18n' // CR-260615-08(P1-10):相对时间走 i18n(原硬编码中文,en locale 时间恒中文)。 // utils 纯函数无 setup,用 vue-i18n 全局实例(参考 useAiEvents.ts:16-25),any 中转规避 TS2589。 diff --git a/src/views/ProjectDetail.vue b/src/views/ProjectDetail.vue index 96b7d6a..4908388 100644 --- a/src/views/ProjectDetail.vue +++ b/src/views/ProjectDetail.vue @@ -9,7 +9,7 @@
- +
@@ -198,7 +198,7 @@ :disabled="multiDecisions.length === 0" @click="handleApprovalMulti" > - 确认({{ multiDecisions.length }}) + {{ $t('projectDetail.approvalConfirm', { count: multiDecisions.length }) }}