From 4c056b3a7b4e2c99cb0d8ea33129ef5f8b5fabe0 Mon Sep 17 00:00:00 2001 From: mcocdaa <2021137961@qq.com> Date: Sat, 17 Oct 2026 12:08:08 +0200 Subject: [PATCH] fix(i18n): localize backend errors, reactive plugin UI, bilingual tags, and eyebrows --- backend/app/agendas/outcome_tags.py | 8 +- .../domain/test_bidirectional_actions.py | 34 ++ docs/assets/demo_meetflow.gif | Bin 766370 -> 766370 bytes frontend/src/api/client.ts | 8 +- frontend/src/api/plugin-stream.ts | 4 +- frontend/src/components/AgendaDetail.vue | 6 +- frontend/src/components/AgendaQueue.vue | 2 +- frontend/src/components/AgendaWorkbench.vue | 2 +- .../src/components/CompletedMeetingChain.vue | 2 +- frontend/src/components/OutcomeComposer.vue | 3 +- .../src/components/ProjectActivityTab.vue | 2 +- frontend/src/components/ProjectOverview.vue | 2 +- .../src/components/ProjectUpdateComposer.vue | 2 +- frontend/src/composables/useVersionedSave.ts | 3 +- frontend/src/i18n/index.ts | 23 +- frontend/src/tests/agenda-workbench.test.ts | 2 +- .../tests/ai-work-assistant-plugin.test.ts | 24 ++ frontend/src/tests/api-client.test.ts | 26 +- frontend/src/tests/meeting-workspace.test.ts | 30 +- frontend/src/utils/errors.ts | 311 +++++++++++++++++- frontend/src/views/AccountView.vue | 2 +- frontend/src/views/ActionsView.vue | 2 +- frontend/src/views/AdminPluginsView.vue | 35 +- frontend/src/views/AdminUsersView.vue | 4 +- frontend/src/views/AiTasksView.vue | 6 +- frontend/src/views/DecisionsView.vue | 2 +- frontend/src/views/HomeView.vue | 8 +- frontend/src/views/InboxView.vue | 2 +- frontend/src/views/LoginView.vue | 2 +- frontend/src/views/MeetingWorkspaceView.vue | 10 +- frontend/src/views/MeetingsView.vue | 2 +- frontend/src/views/ProjectDetailView.vue | 2 +- frontend/src/views/ProjectsView.vue | 2 +- .../frontend/assistant-ui.js | 131 +++++++- plugins/meeting-export/plugin.yaml | 2 +- 35 files changed, 615 insertions(+), 91 deletions(-) diff --git a/backend/app/agendas/outcome_tags.py b/backend/app/agendas/outcome_tags.py index bb37855..68926ac 100644 --- a/backend/app/agendas/outcome_tags.py +++ b/backend/app/agendas/outcome_tags.py @@ -66,13 +66,13 @@ def parse_action_metadata( due_date_val = date.fromisoformat(token) except ValueError: break - elif token_lower in ("todo", "open"): + elif token_lower in ("todo", "open", "待办", "待开始"): status = ActionStatus.open - elif token_lower in ("in_progress", "doing", "progress"): + elif token_lower in ("in_progress", "doing", "progress", "进行中"): status = ActionStatus.in_progress - elif token_lower in ("done", "completed", "finish", "finished"): + elif token_lower in ("done", "completed", "finish", "finished", "已完成", "完成"): status = ActionStatus.done - elif token_lower in ("canceled", "cancelled"): + elif token_lower in ("canceled", "cancelled", "已取消", "取消"): status = ActionStatus.canceled else: break diff --git a/backend/tests/domain/test_bidirectional_actions.py b/backend/tests/domain/test_bidirectional_actions.py index 5cc054b..1a3312e 100644 --- a/backend/tests/domain/test_bidirectional_actions.py +++ b/backend/tests/domain/test_bidirectional_actions.py @@ -84,6 +84,40 @@ def test_parse_outcome_tags_extended_syntax(): assert actions[3].content == "传统无括号待办" +def test_parse_outcome_tags_chinese_status_tokens(): + md = """ +@行动:[待办][@林宇][2026-10-01] 整理压测报告 +@行动:[待开始][@乔安] 准备回滚预案 +@行动:[进行中][@林宇] 推进网关限流改造 +@行动:[已完成][@乔安][2026-09-30] 完成发布清单核验 +@行动:[已取消] 旧版接口迁移计划 +""" + tags = parse_outcome_tags(md) + assert len(tags) == 5 + + assert tags[0].status == ActionStatus.open + assert tags[0].owner_name == "林宇" + assert tags[0].due_date == date(2026, 10, 1) + assert tags[0].content == "整理压测报告" + + assert tags[1].status == ActionStatus.open + assert tags[1].owner_name == "乔安" + assert tags[1].content == "准备回滚预案" + + assert tags[2].status == ActionStatus.in_progress + assert tags[2].owner_name == "林宇" + assert tags[2].content == "推进网关限流改造" + + assert tags[3].status == ActionStatus.done + assert tags[3].owner_name == "乔安" + assert tags[3].due_date == date(2026, 9, 30) + assert tags[3].content == "完成发布清单核验" + + assert tags[4].status == ActionStatus.canceled + assert tags[4].owner_name is None + assert tags[4].content == "旧版接口迁移计划" + + def test_rewrite_action_in_notes(): notes = """# Notes - List item diff --git a/docs/assets/demo_meetflow.gif b/docs/assets/demo_meetflow.gif index 163dd25ffc8d20b8cd535185a11970d786269d89..7e294af93ec904237267e2c25616d9ee6985ab90 100644 GIT binary patch delta 362 zcmZ4VSZ~o|y$veNj9Z#jnYXJlGrFlT8g0)}XRKra($BORSy_Sf8v{lIRz}@+Su@7% zvSv&rYK*$mC&e(W08-YmOurbnY&VNzTK<;NX!<>G=3PJyGkuu%GXc4g{>&eMT(1D; zhz*QJQ}?h)KuO)LS6NtIGwN=?^_oQ-Xw~$5bxy-}#tw4Q_VAnR1|SQ8eo<^+d6#|r%DWurJ%9q0YMk9bidCI6lhLRh z=$`HQ>Re}2fNrqu;kpKt5$Wa12O0phT!?Y|v_7uIK%YXqv_069TOot-4u~hF!SJ6! WXFqc|6C(p70|N&O!+%y525SI-9B#`1 delta 362 zcmZ4VSZ~o|y$veNj1JAJ%-dC&8QoMEUAE__Ggh)NI&6QY&B)3Mq~91Y8n7~2w9A?? zZkIJ zOc!@zI|<}HbYimvQqs#tw4Q_VAnR1}uy=(}8|bY+reoef!G09OpfN0+ni<-9U;} zoimfsp&jU+?fL3lXH$S~u6>UH||9 diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 1b02524..9c3acec 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -1,4 +1,5 @@ import { locale } from '../i18n' +import { translateBackendError } from '../utils/errors' export class ApiError extends Error { constructor( @@ -25,7 +26,12 @@ export function apiErrorMessage( && 'message' in payload.error && typeof payload.error.message === 'string' ) { - return payload.error.message + const code = 'code' in payload.error && typeof payload.error.code === 'string' ? payload.error.code : null + const translated = translateBackendError(payload.error.message, code) + if (locale.value === 'en' && /[\u4e00-\u9fff]/.test(translated) && !/[\u4e00-\u9fff]/.test(fallback)) { + return fallback + } + return translated } return fallback } diff --git a/frontend/src/api/plugin-stream.ts b/frontend/src/api/plugin-stream.ts index 1c279e2..540f8c6 100644 --- a/frontend/src/api/plugin-stream.ts +++ b/frontend/src/api/plugin-stream.ts @@ -1,4 +1,5 @@ import { locale } from '../i18n' +import { translateBackendError } from '../utils/errors' import { apiErrorMessage, dispatchAuthExpired } from './client' function consumeEvent(block: string, onDelta: (text: string) => void): boolean { @@ -24,7 +25,8 @@ function consumeEvent(block: string, onDelta: (text: string) => void): boolean { } if (event === 'error') { if (payload && typeof payload === 'object' && 'message' in payload && typeof payload.message === 'string') { - throw new Error(payload.message) + const code = 'code' in payload && typeof payload.code === 'string' ? payload.code : null + throw new Error(translateBackendError(payload.message, code)) } throw new Error(locale.value === 'en' ? 'Failed to generate AI work brief, please try again later' : 'AI 工作简报生成失败,请稍后重试') } diff --git a/frontend/src/components/AgendaDetail.vue b/frontend/src/components/AgendaDetail.vue index 06c74f7..6e34abb 100644 --- a/frontend/src/components/AgendaDetail.vue +++ b/frontend/src/components/AgendaDetail.vue @@ -479,7 +479,7 @@ const noteActionTags = computed(() => {