From 31c97163b623595bf5cd65942d2723cf1073d165 Mon Sep 17 00:00:00 2001 From: icatw <99238504+icatw@users.noreply.github.com> Date: Fri, 26 Jun 2026 10:06:46 +0800 Subject: [PATCH 1/3] fix(frontend): polish zh-CN localization --- frontend/messages/en.json | 248 +++++++++++++++++- frontend/messages/zh-CN.json | 234 ++++++++++++++++- .../activity/ConcurrencyTimeline.svelte | 5 +- .../components/content/ActivityLane.svelte | 8 +- .../lib/components/content/CallGroup.svelte | 9 +- .../src/lib/components/content/CallRow.svelte | 4 +- .../content/CallRow_CallGroup.test.ts | 10 +- .../components/content/SessionVitals.svelte | 62 +++-- .../components/content/SessionVitals.test.ts | 5 +- .../components/content/SubagentCalls.svelte | 20 +- .../components/insights/InsightsPage.svelte | 5 +- .../lib/components/layout/StatusBar.svelte | 15 +- .../components/settings/SettingsPage.svelte | 27 +- .../lib/components/sidebar/SessionItem.svelte | 4 +- .../lib/components/sidebar/SessionList.svelte | 26 +- .../components/sidebar/SessionList.test.ts | 18 +- .../src/lib/components/trash/TrashPage.svelte | 5 +- frontend/src/lib/i18n/i18n.test.ts | 22 +- 18 files changed, 634 insertions(+), 93 deletions(-) diff --git a/frontend/messages/en.json b/frontend/messages/en.json index a1e6c83fa..f8784bafa 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -67,9 +67,54 @@ "header_actions_settings": "Settings", "header_actions_keyboard_shortcuts": "Keyboard shortcuts", "header_actions_keyboard_shortcuts_shortcut": "Keyboard shortcuts (?)", - "status_bar_sessions": "{count} sessions", - "status_bar_messages": "{count} messages", - "status_bar_projects": "{count} projects", + "status_bar_sessions": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} session", + "countPlural=other": "{countLabel} sessions" + } + } + ], + "status_bar_messages": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} message", + "countPlural=other": "{countLabel} messages" + } + } + ], + "status_bar_projects": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} project", + "countPlural=other": "{countLabel} projects" + } + } + ], "status_bar_open_performance_debug": "Open performance debug", "status_bar_perf": "Perf", "status_bar_remote_unreachable_title": "Can't reach the remote server. Open settings to check the URL, token, or disconnect.", @@ -248,8 +293,49 @@ "compact_boundary_title": "Context window compacted at this point", "compact_boundary_label": "Context compacted", "compact_boundary_show_full_summary": "Show full summary", - "sidebar_session_count": "{count} sessions", + "sidebar_session_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} session", + "countPlural=other": "{countLabel} sessions" + } + } + ], "sidebar_loading": "loading", + "sidebar_multi_select": "Multi-select", + "sidebar_exit_multi_select": "Exit multi-select", + "sidebar_select_all_visible": "Select all visible", + "sidebar_clear_selection": "Clear selection", + "sidebar_batch_clear": "Clear", + "sidebar_batch_all": "All", + "sidebar_selected_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} selected", + "countPlural=other": "{countLabel} selected" + } + } + ], + "sidebar_move_selected_to_trash": "Move selected sessions to trash", + "sidebar_deleting": "Deleting...", + "sidebar_delete": "Delete", + "sidebar_cancel": "Cancel", "sidebar_status": "Status", "sidebar_active": "Active", "sidebar_active_title": "Last activity within 10 minutes", @@ -287,6 +373,8 @@ "sidebar_filters_clear_filters": "Clear filters", "sidebar_row_expand": "Expand", "sidebar_row_collapse": "Collapse", + "sidebar_row_select_session": "Select session", + "sidebar_row_deselect_session": "Deselect session", "sidebar_row_star_session": "Star session", "sidebar_row_unstar_session": "Unstar session", "sidebar_row_rename": "Rename", @@ -599,6 +687,9 @@ "usage_top_sessions_by_cost": "Top Sessions by Cost", "settings_title": "Settings", "settings_loading": "Loading settings...", + "settings_resync_title_unavailable": "Full resync unavailable in read-only mode", + "settings_resync_unavailable_hint": "Unavailable while connected to a read-only backend", + "settings_resync_hint": "Re-scan all session files from scratch", "settings_language_title": "Language", "settings_language_description": "Choose the interface language.", "settings_language_label": "Interface language", @@ -649,7 +740,22 @@ "activity_int_auto_short": "{int} int / {auto} auto", "activity_peak_label": "peak {count}", "activity_agent_min_value": "{value} agent-min", - "activity_output_tokens_value": "{count} output tokens", + "activity_output_tokens_value": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} output token", + "countPlural=other": "{countLabel} output tokens" + } + } + ], "activity_concurrency": "Concurrency", "activity_overlay": "Overlay", "activity_overlay_metric": "Concurrency overlay metric", @@ -791,6 +897,104 @@ "status_dot_stale": "Flagged session, idle for 10–60 minutes", "status_dot_unclean": "Terminated mid tool call (or file truncated)", "call_row_toggle_subagent_calls": "Toggle sub-agent calls", + "call_row_running_duration": "running {duration}+", + "call_group_parallel_label": "parallel", + "call_group_parallel_call_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} call", + "countPlural=other": "{countLabel} calls" + } + } + ], + "subagent_calls_label": "↳ sub-agent", + "subagent_calls_summary": [ + { + "declarations": [ + "input count", + "input countLabel", + "input duration", + "input running", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural", + "running" + ], + "match": { + "countPlural=one,running=true": "{countLabel} call · running {duration}+", + "countPlural=other,running=true": "{countLabel} calls · running {duration}+", + "countPlural=one,running=false": "{countLabel} call · {duration}", + "countPlural=other,running=false": "{countLabel} calls · {duration}" + } + } + ], + "activity_lane_activity": "activity", + "activity_lane_message_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} message", + "countPlural=other": "{countLabel} messages" + } + } + ], + "session_vitals_title": "Analysis", + "session_vitals_subtitle": "Session vital signs", + "session_vitals_close": "Close session analysis", + "session_vitals_session": "Session", + "session_vitals_running": "running", + "session_vitals_running_duration": "running {duration}+", + "session_vitals_tool_calls": "tool calls", + "session_vitals_tool_time": "tool time", + "session_vitals_slowest_call": "slowest call", + "session_vitals_jump_to_call": "Jump to call", + "session_vitals_turns": "turns", + "session_vitals_subagents": "sub-agents", + "session_vitals_time_spent": "Time spent", + "session_vitals_clear_category_filter": "clear category filter", + "session_vitals_completed_turns_hint": "completed turns · click to highlight", + "session_vitals_timeline": "Timeline", + "session_vitals_click_marks_to_scroll": "click marks to scroll", + "session_vitals_jump_to_turn": "Jump to {category} turn at {time}", + "session_vitals_calls": "Calls", + "session_vitals_calls_summary": [ + { + "declarations": [ + "input count", + "input countLabel", + "input runningCount", + "local countPlural = count: plural", + "local runningPlural = runningCount: plural" + ], + "selectors": [ + "countPlural", + "runningPlural" + ], + "match": { + "countPlural=one,runningPlural=one": "{countLabel} call · {runningCount} running", + "countPlural=other,runningPlural=one": "{countLabel} calls · {runningCount} running", + "countPlural=one,runningPlural=other": "{countLabel} call", + "countPlural=other,runningPlural=other": "{countLabel} calls" + } + } + ], + "session_vitals_now": "now", "code_block_copy": "Copy code block", "code_block_copy_title": "Copy code", "common_copied": "Copied!", @@ -915,7 +1119,22 @@ "insights_page_sessions_computed": "sessions computed", "insights_page_score_distribution": "Score distribution", "insights_page_pct_affected": "{pct}% affected", - "insights_page_driver_sessions": "{count} sessions", + "insights_page_driver_sessions": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} session", + "countPlural=other": "{countLabel} sessions" + } + } + ], "insights_page_session_evidence": "Session evidence", "insights_page_close": "Close", "insights_page_loading_examples": "Loading examples...", @@ -1169,7 +1388,22 @@ "trash_title": "Trash", "trash_emptying": "Emptying...", "trash_empty_trash": "Empty Trash", - "trash_msgs": "{count} msgs", + "trash_msgs": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{countLabel} msg", + "countPlural=other": "{countLabel} msgs" + } + } + ], "trash_deleted_ago": "deleted {time}", "trash_restore_session": "Restore session", "trash_restore": "Restore", diff --git a/frontend/messages/zh-CN.json b/frontend/messages/zh-CN.json index a8ea2074a..7bd185312 100644 --- a/frontend/messages/zh-CN.json +++ b/frontend/messages/zh-CN.json @@ -67,9 +67,51 @@ "header_actions_settings": "设置", "header_actions_keyboard_shortcuts": "键盘快捷键", "header_actions_keyboard_shortcuts_shortcut": "键盘快捷键 (?)", - "status_bar_sessions": "{count} 个会话", - "status_bar_messages": "{count} 条消息", - "status_bar_projects": "{count} 个项目", + "status_bar_sessions": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 个会话" + } + } + ], + "status_bar_messages": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 条消息" + } + } + ], + "status_bar_projects": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 个项目" + } + } + ], "status_bar_open_performance_debug": "打开性能调试", "status_bar_perf": "性能", "status_bar_remote_unreachable_title": "无法连接远程服务器。打开设置检查 URL、token 或断开连接。", @@ -243,8 +285,47 @@ "compact_boundary_title": "上下文窗口在此处被压缩", "compact_boundary_label": "上下文已压缩", "compact_boundary_show_full_summary": "显示完整摘要", - "sidebar_session_count": "{count} 个会话", + "sidebar_session_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 个会话" + } + } + ], "sidebar_loading": "加载中", + "sidebar_multi_select": "多选", + "sidebar_exit_multi_select": "退出多选", + "sidebar_select_all_visible": "选择所有可见会话", + "sidebar_clear_selection": "清除选择", + "sidebar_batch_clear": "清除", + "sidebar_batch_all": "全部", + "sidebar_selected_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "已选择 {countLabel} 个" + } + } + ], + "sidebar_move_selected_to_trash": "将选中的会话移至回收站", + "sidebar_deleting": "正在删除...", + "sidebar_delete": "删除", + "sidebar_cancel": "取消", "sidebar_status": "状态", "sidebar_active": "活跃", "sidebar_active_title": "10 分钟内有活动", @@ -282,6 +363,8 @@ "sidebar_filters_clear_filters": "清除筛选器", "sidebar_row_expand": "展开", "sidebar_row_collapse": "折叠", + "sidebar_row_select_session": "选择会话", + "sidebar_row_deselect_session": "取消选择会话", "sidebar_row_star_session": "固定会话", "sidebar_row_unstar_session": "取消固定会话", "sidebar_row_rename": "重命名", @@ -584,6 +667,9 @@ "usage_top_sessions_by_cost": "按成本排序的热门会话", "settings_title": "设置", "settings_loading": "正在加载设置...", + "settings_resync_title_unavailable": "只读模式下无法完整重新同步", + "settings_resync_unavailable_hint": "连接到只读后端时不可用", + "settings_resync_hint": "从头重新扫描所有会话文件", "settings_language_title": "语言", "settings_language_description": "选择界面语言。", "settings_language_label": "界面语言", @@ -634,7 +720,21 @@ "activity_int_auto_short": "{int} 交互 / {auto} 自动", "activity_peak_label": "峰值 {count}", "activity_agent_min_value": "{value} 代理分钟", - "activity_output_tokens_value": "{count} 输出 Token", + "activity_output_tokens_value": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 输出 Token" + } + } + ], "activity_concurrency": "并发", "activity_overlay": "叠加", "activity_overlay_metric": "并发叠加指标", @@ -776,6 +876,98 @@ "status_dot_stale": "已标记会话,空闲 10–60 分钟", "status_dot_unclean": "在工具调用中途终止(或文件被截断)", "call_row_toggle_subagent_calls": "切换子代理调用", + "call_row_running_duration": "运行中 {duration}+", + "call_group_parallel_label": "并行", + "call_group_parallel_call_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 次调用" + } + } + ], + "subagent_calls_label": "↳ sub-agent", + "subagent_calls_summary": [ + { + "declarations": [ + "input count", + "input countLabel", + "input duration", + "input running", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural", + "running" + ], + "match": { + "countPlural=other,running=true": "{countLabel} 次调用 · 运行中 {duration}+", + "countPlural=other,running=false": "{countLabel} 次调用 · {duration}" + } + } + ], + "activity_lane_activity": "活动", + "activity_lane_message_count": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 条消息" + } + } + ], + "session_vitals_title": "分析", + "session_vitals_subtitle": "会话生命体征", + "session_vitals_close": "关闭会话分析", + "session_vitals_session": "会话", + "session_vitals_running": "运行中", + "session_vitals_running_duration": "运行中 {duration}+", + "session_vitals_tool_calls": "tool calls", + "session_vitals_tool_time": "tool 时间", + "session_vitals_slowest_call": "最慢调用", + "session_vitals_jump_to_call": "跳转到调用", + "session_vitals_turns": "turns", + "session_vitals_subagents": "sub-agents", + "session_vitals_time_spent": "耗时分布", + "session_vitals_clear_category_filter": "清除分类筛选", + "session_vitals_completed_turns_hint": "已完成 turns · 点击高亮", + "session_vitals_timeline": "时间线", + "session_vitals_click_marks_to_scroll": "点击标记滚动", + "session_vitals_jump_to_turn": "跳转到 {category} turn,时间 {time}", + "session_vitals_calls": "调用", + "session_vitals_calls_summary": [ + { + "declarations": [ + "input count", + "input countLabel", + "input runningCount", + "local countPlural = count: plural", + "local runningPlural = runningCount: plural" + ], + "selectors": [ + "countPlural", + "runningPlural" + ], + "match": { + "countPlural=other,runningPlural=one": "{countLabel} 次调用 · {runningCount} 个运行中", + "countPlural=other,runningPlural=other": "{countLabel} 次调用" + } + } + ], + "session_vitals_now": "现在", "code_block_copy": "复制代码块", "code_block_copy_title": "复制代码", "common_copied": "已复制!", @@ -900,7 +1092,21 @@ "insights_page_sessions_computed": "个已计算会话", "insights_page_score_distribution": "评分分布", "insights_page_pct_affected": "{pct}% 受影响", - "insights_page_driver_sessions": "{count} 个会话", + "insights_page_driver_sessions": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 个会话" + } + } + ], "insights_page_session_evidence": "会话证据", "insights_page_close": "关闭", "insights_page_loading_examples": "正在加载示例...", @@ -1154,7 +1360,21 @@ "trash_title": "回收站", "trash_emptying": "正在清空...", "trash_empty_trash": "清空回收站", - "trash_msgs": "{count} 条消息", + "trash_msgs": [ + { + "declarations": [ + "input count", + "input countLabel", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=other": "{countLabel} 条消息" + } + } + ], "trash_deleted_ago": "{time} 删除", "trash_restore_session": "恢复会话", "trash_restore": "恢复", diff --git a/frontend/src/lib/components/activity/ConcurrencyTimeline.svelte b/frontend/src/lib/components/activity/ConcurrencyTimeline.svelte index 7654158a5..1ce4e539f 100644 --- a/frontend/src/lib/components/activity/ConcurrencyTimeline.svelte +++ b/frontend/src/lib/components/activity/ConcurrencyTimeline.svelte @@ -114,7 +114,10 @@ text: `${fmtBucketRange(b)} · ${m.activity_peak_label({ count: b.max_agents })}${peakSplit} · ` + `${m.activity_agent_min_value({ value: b.agent_minutes.toFixed(1) })} · ` + - `${m.activity_output_tokens_value({ count: b.output_tokens.toLocaleString() })} · ` + + `${m.activity_output_tokens_value({ + count: b.output_tokens, + countLabel: b.output_tokens.toLocaleString(), + })} · ` + `$${b.cost.toFixed(2)}`, }; } diff --git a/frontend/src/lib/components/content/ActivityLane.svelte b/frontend/src/lib/components/content/ActivityLane.svelte index 9f1dba31c..df90cd2d7 100644 --- a/frontend/src/lib/components/content/ActivityLane.svelte +++ b/frontend/src/lib/components/content/ActivityLane.svelte @@ -4,6 +4,7 @@ positioned `.activity-bar` per populated bucket. Click-to-scroll uses `ui.scrollToOrdinal`, matching ActivityMinimap's behavior. -->