From fa86786a0ce4266f031dd32313ce70876dc39bc6 Mon Sep 17 00:00:00 2001 From: Delicious233 <101502465+DeliciousBuding@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:15:43 +0800 Subject: [PATCH] =?UTF-8?q?fix(shared):=2037=20=E4=B8=AA=E7=A1=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E4=B8=AD=E6=96=87=20title/subtitle=20=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E5=88=B0=20i18n=20=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit workbench 页面中 33 个 title 和 4 个 subtitle 属性仍使用硬编码中文, 英文 locale 用户会看到 mixed-language 界面。将全部迁移到 sharedWorkbench namespace 的 t() 调用,新增 settings.section.* / projects.section.* / contacts.section.* 键(zh + en),覆盖设置面板子区标题、项目面板分区 标题、联系人分组标题和副标题。 SettingsPanes/SettingsMain 使用双 namespace 模式(CHATVIEW for aria, SHARED_WORKBENCH for section titles),避免 key-echo 返回 key 字符串。 Co-authored-by: Cursor --- app/shared/src/i18n/workbench.ts | 70 +++++++++++++++++++ .../pages/contacts/ContactMainParts.tsx | 10 +-- .../pages/contacts/ContactMainViews.tsx | 13 ++-- .../pages/projects/ProjectFeedPanel.tsx | 5 +- .../pages/projects/ProjectPanelParts.tsx | 17 +++-- .../pages/projects/ProjectTabViews.tsx | 18 +++-- .../workbench/pages/settings/SettingsMain.tsx | 4 +- .../pages/settings/SettingsPanes.tsx | 28 +++++--- 8 files changed, 132 insertions(+), 33 deletions(-) diff --git a/app/shared/src/i18n/workbench.ts b/app/shared/src/i18n/workbench.ts index 4a8ee5617..9ce00c548 100644 --- a/app/shared/src/i18n/workbench.ts +++ b/app/shared/src/i18n/workbench.ts @@ -132,6 +132,20 @@ export const sharedWorkbenchResources = { stateComponents: { title: '状态组件预览', description: '预览不同 Agent 运行状态的卡片样式' }, }, moreButton: { label: '设置更多' }, + section: { + interface: '界面', + layout: '布局', + runNotifications: '运行提醒', + collaborationNotifications: '协作提醒', + defaultRunConfig: '默认运行配置', + permissionPolicy: '权限策略', + singleAgentConfig: '单个 Agent 配置', + localPreview: '本地预览', + debug: '调试', + localSessionImport: '本地会话导入', + statePolicy: '状态策略', + }, + loadFailed: '设置加载失败', }, projects: { nav: { all: '全部项目', running: '运行中', completed: '已完成', archived: '已归档' }, @@ -142,6 +156,20 @@ export const sharedWorkbenchResources = { loading: '正在加载项目…', loadMoreError: '加载更多项目失败:{{message}}', retryLoadMore: '重试加载更多', + section: { + members: '成员', + projectRuns: '项目运行', + runSummary: '运行摘要', + artifacts: '产物', + artifactIndex: '产物索引', + recentActivity: '最近动态', + runRecords: '运行记录', + deliveryActivity: '交付动态', + archiveCheck: '归档检查', + archivePackage: '归档包', + projectSettings: '项目设置', + memberPolicy: '成员策略', + }, empty: { title: '暂无项目', description: '创建第一个项目以开始协作。', @@ -163,6 +191,13 @@ export const sharedWorkbenchResources = { contacts: { nav: { internal: '组织内联系人', external: '外部联系人', newFriend: '新的朋友' }, search: { placeholder: '搜索联系人' }, + section: { + external: { title: '外部联系人', subtitle: '客户、合作方和临时项目协作者,不进入 TokenDance 组织架构。' }, + starred: { title: '星标联系人', subtitle: '常用联系人会固定在这里,便于快速发起对话和项目协作。' }, + internal: { title: '组织内联系人' }, + myGroups: { title: '我的群组', subtitle: '项目群、评审群和协作群统一管理,按最新消息排序。' }, + helpDesk: { title: '服务台', subtitle: '把账号、Agent 运行和云文档问题转给对应支持入口。' }, + }, empty: { title: '暂无联系人', description: '添加联系人开始协作' }, emptySearch: { title: '没有匹配的联系人', @@ -410,6 +445,20 @@ export const sharedWorkbenchResources = { stateComponents: { title: 'State component preview', description: 'Preview card styles for different agent run states' }, }, moreButton: { label: 'More settings' }, + section: { + interface: 'Interface', + layout: 'Layout', + runNotifications: 'Run notifications', + collaborationNotifications: 'Collaboration notifications', + defaultRunConfig: 'Default run config', + permissionPolicy: 'Permission policy', + singleAgentConfig: 'Single agent config', + localPreview: 'Local preview', + debug: 'Debug', + localSessionImport: 'Local session import', + statePolicy: 'State policy', + }, + loadFailed: 'Settings load failed', }, projects: { nav: { all: 'All projects', running: 'Running', completed: 'Completed', archived: 'Archived' }, @@ -420,6 +469,20 @@ export const sharedWorkbenchResources = { loading: 'Loading projects…', loadMoreError: 'Failed to load more projects: {{message}}', retryLoadMore: 'Retry loading more', + section: { + members: 'Members', + projectRuns: 'Project runs', + runSummary: 'Run summary', + artifacts: 'Artifacts', + artifactIndex: 'Artifact index', + recentActivity: 'Recent activity', + runRecords: 'Run records', + deliveryActivity: 'Delivery activity', + archiveCheck: 'Archive check', + archivePackage: 'Archive package', + projectSettings: 'Project settings', + memberPolicy: 'Member policy', + }, empty: { title: 'No projects yet', description: 'Create your first project to start collaborating.', @@ -441,6 +504,13 @@ export const sharedWorkbenchResources = { contacts: { nav: { internal: 'Internal contacts', external: 'External contacts', newFriend: 'New friends' }, search: { placeholder: 'Search contacts' }, + section: { + external: { title: 'External contacts', subtitle: 'Clients, partners and temporary collaborators, not part of the TokenDance organization.' }, + starred: { title: 'Starred contacts', subtitle: 'Frequent contacts are pinned here for quick access to conversations and projects.' }, + internal: { title: 'Internal contacts' }, + myGroups: { title: 'My groups', subtitle: 'Project, review and collaboration groups managed together, sorted by latest message.' }, + helpDesk: { title: 'Help desk', subtitle: 'Route account, agent run and document issues to the appropriate support channel.' }, + }, empty: { title: 'No contacts yet', description: 'Add contacts to start collaborating' }, emptySearch: { title: 'No matching contacts', diff --git a/app/shared/src/workbench/pages/contacts/ContactMainParts.tsx b/app/shared/src/workbench/pages/contacts/ContactMainParts.tsx index 730f10450..88078c30f 100644 --- a/app/shared/src/workbench/pages/contacts/ContactMainParts.tsx +++ b/app/shared/src/workbench/pages/contacts/ContactMainParts.tsx @@ -209,11 +209,12 @@ export function ContactGroupsPane({ onGroupClick?: ((group: ContactGroup) => void) | undefined; onAvatarClick?: ((group: ContactGroup, anchor: HTMLElement) => void) | undefined; }): React.ReactElement { + const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return (
@@ -241,11 +242,12 @@ export function ContactServicePane({ onServiceClick?: ((desk: ServiceDesk) => void) | undefined; onAvatarClick?: ((desk: ServiceDesk, anchor: HTMLElement) => void) | undefined; }): React.ReactElement { + const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return (
diff --git a/app/shared/src/workbench/pages/contacts/ContactMainViews.tsx b/app/shared/src/workbench/pages/contacts/ContactMainViews.tsx index 9b299dd88..78f940c1e 100644 --- a/app/shared/src/workbench/pages/contacts/ContactMainViews.tsx +++ b/app/shared/src/workbench/pages/contacts/ContactMainViews.tsx @@ -1,4 +1,6 @@ import React, { useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n'; import { ContactGroupsPane, ContactListPage, @@ -76,6 +78,7 @@ export function ContactMain({ onAcceptRequest, onRejectRequest, }: ContactMainProps): React.ReactElement { + const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); const resolvedPending = pendingContacts ?? []; const [activeProfile, setActiveProfile] = useState(null); const [actionLoading, setActionLoading] = useState(false); @@ -158,8 +161,8 @@ export function ContactMain({ case 'external': return ( - + {feed.map((item) => (
diff --git a/app/shared/src/workbench/pages/projects/ProjectPanelParts.tsx b/app/shared/src/workbench/pages/projects/ProjectPanelParts.tsx index ee3245461..97f5214b0 100644 --- a/app/shared/src/workbench/pages/projects/ProjectPanelParts.tsx +++ b/app/shared/src/workbench/pages/projects/ProjectPanelParts.tsx @@ -8,6 +8,8 @@ ═══════════════════════════════════════════════════════════════════════ */ import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n'; import { DesignFileIcon } from '../../designIcons'; import type { WorkbenchDocumentPreview } from '../../documentPreview'; import { FilePreview } from '../../inspector'; @@ -35,9 +37,10 @@ export function MembersCard({ members: string[]; profiles?: WorkbenchProfileSource[] | undefined; }) { + const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return (
- +
{members.map((name) => ( @@ -79,9 +82,10 @@ export function RunsPanel({ onRunClick?: ((run: ProjectRun) => void) | undefined; profiles?: WorkbenchProfileSource[] | undefined; }) { + const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return (
- + {runs.map((run) => (
diff --git a/app/shared/src/workbench/pages/settings/SettingsMain.tsx b/app/shared/src/workbench/pages/settings/SettingsMain.tsx index b3bd0d022..463d60656 100644 --- a/app/shared/src/workbench/pages/settings/SettingsMain.tsx +++ b/app/shared/src/workbench/pages/settings/SettingsMain.tsx @@ -14,11 +14,13 @@ import { PANE_META } from './types'; import type { SettingsPageProps } from './types'; import { useTranslation } from 'react-i18next'; import { CHATVIEW_I18N_NAMESPACE } from '../../../chatview/i18n/resources'; +import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n'; export type SettingsMainProps = SettingsPageProps; export function SettingsMain(props: SettingsMainProps): React.ReactElement { const { t } = useTranslation(CHATVIEW_I18N_NAMESPACE); + const { t: tw } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); const { activePane, settingsLoading = false, @@ -88,7 +90,7 @@ export function SettingsMain(props: SettingsMainProps): React.ReactElement { {...(styles.recoveryPanel ? { className: styles.recoveryPanel } : {})} icon={} eyebrow="Settings recovery" - title="设置加载失败" + title={tw("settings.loadFailed")} description="无法从当前平台适配器读取已保存的设置。页面会暂时使用默认值,重试后可恢复远端偏好。" meta={settingsError} primaryAction={{ diff --git a/app/shared/src/workbench/pages/settings/SettingsPanes.tsx b/app/shared/src/workbench/pages/settings/SettingsPanes.tsx index 507199a54..468c4ba32 100644 --- a/app/shared/src/workbench/pages/settings/SettingsPanes.tsx +++ b/app/shared/src/workbench/pages/settings/SettingsPanes.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { CHATVIEW_I18N_NAMESPACE } from '../../../chatview/i18n/resources'; +import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n'; import { DataModeControl, SettingPath, @@ -44,9 +45,10 @@ export { ═══════════════════════════════════════════════════════════════════════ */ export function AppearancePane(props: SettingsPageProps): React.ReactElement { + const { t: tw } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return ( <> - + props.onChangeSetting('theme', v)} /> @@ -61,7 +63,7 @@ export function AppearancePane(props: SettingsPageProps): React.ReactElement { - + props.onChangeSetting('inspectorVisible', v)} /> @@ -77,9 +79,10 @@ export function AppearancePane(props: SettingsPageProps): React.ReactElement { } export function NotifyPane(props: SettingsPageProps): React.ReactElement { + const { t: tw } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return ( <> - + props.onChangeSetting('taskCompleteNotify', v)} /> @@ -91,7 +94,7 @@ export function NotifyPane(props: SettingsPageProps): React.ReactElement { - + props.onChangeSetting('projectGroupNotifyLevel', v)} /> @@ -108,9 +111,10 @@ export function NotifyPane(props: SettingsPageProps): React.ReactElement { export function AgentDefaultsPane(props: SettingsPageProps): React.ReactElement { const { t } = useTranslation(CHATVIEW_I18N_NAMESPACE); + const { t: tw } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE); return ( <> - + @@ -125,7 +129,7 @@ export function AgentDefaultsPane(props: SettingsPageProps): React.ReactElement - + {PERMISSION_ROWS.map(([tool, value, desc]) => ( - + props.onChangeSetting('copy_viteUrl', props.vitePreviewUrl)} /> @@ -176,7 +181,7 @@ export function LocalDevPane(props: SettingsPageProps): React.ReactElement { - + @@ -189,7 +194,7 @@ export function LocalDevPane(props: SettingsPageProps): React.ReactElement { {props.sessionImportVisible ? ( - + - + props.onChangeSetting('stateStrategy_empty', v)} />