diff --git a/config/scripts/locale-search-keyword-overrides.mjs b/config/scripts/locale-search-keyword-overrides.mjs index 8ca9b5e50..2a9d6266f 100644 --- a/config/scripts/locale-search-keyword-overrides.mjs +++ b/config/scripts/locale-search-keyword-overrides.mjs @@ -106,6 +106,9 @@ export const SEARCH_KEYWORD_OVERRIDES = { theme: '主题', zoom: '缩放', scale: '比例', + // Why: 用法 is "how to use". Keeping the keyword on 用量 also preserves the quota-shaped + // query that stopped matching once the labels moved from 使用量 to 使用情况. + usage: '用量', proxy: '代理', terminal: '终端', workspace: '工作区', diff --git a/config/scripts/locale-translation-policy.mjs b/config/scripts/locale-translation-policy.mjs index 50a490dc1..6b64205a0 100644 --- a/config/scripts/locale-translation-policy.mjs +++ b/config/scripts/locale-translation-policy.mjs @@ -94,6 +94,7 @@ export const NEVER_TRANSLATE_VALUES = new Set([ 'yarn', 'Kagi', 'kagi', + 'kimi', 'Bitbucket', 'bitbucket', 'GNOME', @@ -221,6 +222,10 @@ export const BRAND_MISTRANSLATIONS = { Goose: ['鹅'], Pi: ['圆周率'], Droid: ['机器人'], + Kimi: ['基米'], + // Why: zh-only — 登月计划 is the literal "moon landing programme", not Kimi's vendor. ja and + // ko render this keyword their own way, so it must not go in the cross-locale preserve set. + moonshot: ['登月计划'], 'GitHub Copilot': ['GitHub 副驾驶', '副驾驶'], Bitbucket: ['位桶'], Linear: ['线性', '线形'], diff --git a/config/scripts/locale-translation-policy.zh-status-bar-usage.test.mjs b/config/scripts/locale-translation-policy.zh-status-bar-usage.test.mjs new file mode 100644 index 000000000..6df117983 --- /dev/null +++ b/config/scripts/locale-translation-policy.zh-status-bar-usage.test.mjs @@ -0,0 +1,91 @@ +import { describe, expect, it } from 'vitest' + +import { repairTranslatedValue } from './locale-translation-policy.mjs' + +// #12881 — the status bar item menu renders " Usage" for every provider in one dropdown, so +// zh has to settle on a single word. Registering it here, not only in the catalog, is what makes a +// re-translation pass reproduce the decision instead of re-splitting the labels. +// +// Scope is the provider usage surfaces, not the word "usage" everywhere: a measured volume +// ("Daily usage" 每日使用量) stays 使用量. The toggle descriptions are pinned by the catalog test +// instead — LOCALE_VALUE_OVERRIDES keys on the exact English string, so full sentences do not fit. +// +// ja is split the same way zh was (使用量 vs の使用状況) and is not covered here; ko is uniform. + +// Real catalog keys, so a future zh key override shadowing one of these is caught here. +const STATUS_BAR_PROVIDERS = [ + ['auto.components.status.bar.StatusBar.3885eb74d8', 'Claude'], + ['auto.components.status.bar.StatusBar.c0909c686e', 'Codex'], + ['auto.components.status.bar.StatusBar.c1df0d67ec', 'Gemini'], + ['auto.components.status.bar.StatusBar.antigravityUsage', 'Antigravity'], + ['auto.components.status.bar.StatusBar.8c86cd77b0', 'OpenCode Go'], + ['auto.components.status.bar.StatusBar.5e59007df4', 'Kimi'], + ['auto.components.status.bar.StatusBar.3bbf140864', 'MiniMax'], + ['auto.components.status.bar.StatusBar.grokUsageMenu', 'Grok'], + ['auto.components.settings.accounts.search.f4a8c2e1b7', 'Grok (xAI)'] +] + +describe('locale-translation-policy zh status bar usage labels', () => { + it('pins every provider usage label to 使用情况', () => { + for (const [key, brand] of STATUS_BAR_PROVIDERS) { + expect( + repairTranslatedValue({ + key, + enValue: `${brand} Usage`, + localeValue: `${brand} 使用量`, + locale: 'zh' + }), + brand + ).toBe(`${brand} 使用情况`) + } + }) + + it('reverts the Kimi transliteration in labels and search keywords', () => { + expect( + repairTranslatedValue({ + key: 'auto.components.settings.appearance.search.3a6c028ea8', + enValue: 'Kimi Usage', + localeValue: '基米用法', + locale: 'zh' + }) + ).toBe('Kimi 使用情况') + expect( + repairTranslatedValue({ + key: 'auto.components.settings.appearance.search.40e5c3c285', + enValue: 'kimi', + localeValue: '基米', + locale: 'zh' + }) + ).toBe('kimi') + }) + + // Why: NEVER_TRANSLATE_VALUES is cross-locale. Moving the moonshot repair there would rewrite + // ja's ムーンショット, so it has to stay a zh-scoped BRAND_MISTRANSLATIONS entry. + it('keeps the moonshot keyword repair scoped to zh', () => { + const key = 'auto.components.settings.appearance.search.35565867cb' + expect( + repairTranslatedValue({ key, enValue: 'moonshot', localeValue: '登月计划', locale: 'zh' }) + ).toBe('moonshot') + expect( + repairTranslatedValue({ + key, + enValue: 'moonshot', + localeValue: 'ムーンショット', + locale: 'ja' + }) + ).toBe('ムーンショット') + }) + + // Why: the labels moving to 使用情况 removed the only 用量-shaped match, so the search keyword + // carries it. 用法 means "how to use". + it('keeps 用量 as the zh search keyword for "usage"', () => { + expect( + repairTranslatedValue({ + key: 'auto.components.settings.appearance.search.00a028f25f', + enValue: 'usage', + localeValue: '用法', + locale: 'zh' + }) + ).toBe('用量') + }) +}) diff --git a/config/scripts/locale-value-overrides.mjs b/config/scripts/locale-value-overrides.mjs index ea49d7482..eb033193b 100644 --- a/config/scripts/locale-value-overrides.mjs +++ b/config/scripts/locale-value-overrides.mjs @@ -201,6 +201,12 @@ export const LOCALE_VALUE_OVERRIDES = { 'Codex Usage': 'Codex 使用情况', 'Claude Usage': 'Claude 使用情况', 'Gemini Usage': 'Gemini 使用情况', + 'Antigravity Usage': 'Antigravity 使用情况', + 'OpenCode Go Usage': 'OpenCode Go 使用情况', + 'Kimi Usage': 'Kimi 使用情况', + 'MiniMax Usage': 'MiniMax 使用情况', + 'Grok Usage': 'Grok 使用情况', + 'Grok (xAI) Usage': 'Grok (xAI) 使用情况', 'Force Delete Branch': '强制删除分支', 'Time agents worked': '代理工作时间', PR: 'PR', diff --git a/src/renderer/src/components/status-bar/resource-manager-terminal-copy.test.ts b/src/renderer/src/components/status-bar/resource-manager-terminal-copy.test.ts index 7f6d1eefa..d4b0303e5 100644 --- a/src/renderer/src/components/status-bar/resource-manager-terminal-copy.test.ts +++ b/src/renderer/src/components/status-bar/resource-manager-terminal-copy.test.ts @@ -32,7 +32,11 @@ describe('resource manager terminal copy', () => { text: 'Resource Manager - 512 MB · Σ RSS - 2 terminal sessions', emphasized: false }, - { id: 'sessions-hint', text: 'Terminal sessions are grouped by workspace.', emphasized: false } + { + id: 'sessions-hint', + text: 'Terminal sessions are grouped by workspace.', + emphasized: false + } ]) }) diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index c5cb6dd35..96a748a98 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -28,9 +28,9 @@ "minimaxToggleDescription": "显示当前工作区的 MiniMax 订阅使用情况。", "sshToggleDescription": "当有可用的 SSH 和远程 Orca 主机时显示它们。", "resourceUsageToggleDescription": "显示资源管理器。点击可查看 CPU、内存、会话、守护进程控制和工作区磁盘扫描。", - "portsToggleDescription": "显示实时工作区端口。单击可查看工作区范围的端口和外部监听器。", - "antigravityToggleDescription": "显示当前工作区的 Antigravity 订阅使用量。", - "grokToggleDescription": "通过 Grok CLI 登录后显示 Grok 订阅额度使用量。" + "portsToggleDescription": "显示实时工作区端口。点击可查看工作区范围的端口和外部监听器。", + "antigravityToggleDescription": "显示当前工作区的 Antigravity 订阅使用情况。", + "grokToggleDescription": "通过 Grok CLI 登录后显示 Grok 订阅额度使用情况。" }, "menuBarIcon": { "title": "显示菜单栏图标", @@ -3206,8 +3206,8 @@ "9659e38343": "端口", "d1e1a7a6bf": "资源管理器", "24ac89df1a": "远程主机", - "5e59007df4": "Kimi 使用量", - "8c86cd77b0": "OpenCode Go 使用量", + "5e59007df4": "Kimi 使用情况", + "8c86cd77b0": "OpenCode Go 使用情况", "c1df0d67ec": "Gemini 使用情况", "c0909c686e": "Codex 使用情况", "3885eb74d8": "Claude 使用情况", @@ -3254,13 +3254,13 @@ "6d1042aa6f": "这会为当前账户使用一次 Codex 速率限制重置额度,并立即重置所有符合条件的用量窗口。", "f077f586db": "不再询问", "c0e972d726": "取消", - "06741a2f3d": "打开 MiniMax 使用量详情", - "3bbf140864": "MiniMax 使用量", + "06741a2f3d": "打开 MiniMax 使用详情", + "3bbf140864": "MiniMax 使用情况", "remoteServerLabel": "远程服务器", - "antigravityUsage": "Antigravity 使用量", + "antigravityUsage": "Antigravity 使用情况", "antigravityUsageDetails": "打开 Antigravity 使用详情", "grokUsageAria": "打开 Grok 使用详情", - "grokUsageMenu": "Grok 使用量", + "grokUsageMenu": "Grok 使用情况", "floatingTerminalNewActivity": "{{label}},有新活动" }, "StatusBarUsageEmptyCta": { @@ -3738,7 +3738,7 @@ "ef8bbf7739": "PR", "ce8533f02e": "智能体", "0bba8ca244": "统计数据", - "0e2a0b6431": "用法", + "0e2a0b6431": "用量", "372debfac0": "统计数据", "26bb901fcd": "Orca 统计,以及 Claude、Codex、OpenCode Token 分析和 Grok 订阅使用量。", "cb2430ae6a": "统计和使用情况", @@ -7520,9 +7520,9 @@ "593720c17f": "位置", "b84a5b0c8a": "选择是否在此设备上或 WSL 中检查和添加提供商账户。", "d09fb5ca92": "账户位置", - "733f9e2a93": "MiniMax 使用量", + "733f9e2a93": "MiniMax 使用情况", "f8374c3151": "粘贴 platform.minimax.io 会话 Cookie 以在本地获取速率限制。", - "f4a8c2e1b7": "Grok (xAI) 使用量", + "f4a8c2e1b7": "Grok (xAI) 使用情况", "e3b7d1f9a2": "通过 Grok CLI(grok login)OAuth 登录以查看每周额度使用量。", "d2c6a0e8f1": "grok", "c1b5f9d7e0": "xai", @@ -7691,23 +7691,23 @@ "6ecad74eb3": "SSH", "f17d66d0d2": "在状态栏显示远程主机连接状态。", "57fb424c56": "远程主机", - "35565867cb": "登月计划", + "35565867cb": "moonshot", "de586def95": "订阅", - "00a028f25f": "用法", - "40e5c3c285": "基米", + "00a028f25f": "用量", + "40e5c3c285": "kimi", "c927a155d5": "在状态栏中显示 Kimi 订阅使用情况。", - "3a6c028ea8": "基米用法", + "3a6c028ea8": "Kimi 使用情况", "25e51b62ee": "速率限制", "d9e7cef86f": "Cookie", "d16378a88f": "minimax", "e46178eb1b": "在状态栏中显示 MiniMax 订阅使用情况。", - "0f08f6b483": "MiniMax 使用量", + "0f08f6b483": "MiniMax 使用情况", "edbf0f63a0": "成本", "afbb6a3767": "Token", "d77537b580": "opencode-go", "a9d56852eb": "opencode", "7f72de7cbe": "在状态栏中显示 OpenCode Go Token 和成本使用情况。", - "bc046e7899": "OpenCode Go 用法", + "bc046e7899": "OpenCode Go 使用情况", "51b0ccd6a2": "谷歌", "2804a920ad": "gemini", "9660c5b2f1": "在状态栏中显示 Gemini Token 和成本使用情况。", @@ -7746,11 +7746,11 @@ "title": "也在原来的列表中显示已固定的工作树", "description": "已固定的工作树会保留在 Pinned 中,同时也显示在全部、项目、状态和 PR 中。" }, - "antigravityUsageTitle": "Antigravity 使用量", - "antigravityUsageDescription": "在状态栏中显示 Antigravity 订阅使用量。", + "antigravityUsageTitle": "Antigravity 使用情况", + "antigravityUsageDescription": "在状态栏中显示 Antigravity 订阅使用情况。", "antigravityKeyword": "antigravity", - "f8e2a1c4b6": "Grok 使用量", - "e7d1b0f3a5": "显示来自 Grok CLI OAuth 的 Grok 每周额度使用量。", + "f8e2a1c4b6": "Grok 使用情况", + "e7d1b0f3a5": "显示来自 Grok CLI OAuth 的 Grok 每周额度使用情况。", "d6c0a9e2f4": "grok", "c5b9f8d1e3": "xai", "usagePercentageDisplayTitle": "用量百分比", @@ -8565,7 +8565,7 @@ "27a27b2f63": "选择退出", "4d4bb76bf4": "选择加入", "b021b9cb81": "匿名的", - "79c319948b": "用法", + "79c319948b": "用量", "77d3180def": "遥测", "b707cc3981": "通过发送匿名功能使用事件来帮助改进 Orca。", "57b283461a": "共享匿名使用数据", diff --git a/src/renderer/src/i18n/zh-technical-literal-mistranslations.test.ts b/src/renderer/src/i18n/zh-technical-literal-mistranslations.test.ts index 9c4c080e7..feea4e56a 100644 --- a/src/renderer/src/i18n/zh-technical-literal-mistranslations.test.ts +++ b/src/renderer/src/i18n/zh-technical-literal-mistranslations.test.ts @@ -61,3 +61,67 @@ describe('zh technical literal / sense fixes (#9574)', () => { expect(findByKey(zh, 'ff450194cd')).toBe('Kagi 私密会话链接') }) }) + +// #12881 — the status bar provider usage surfaces settle on 使用情况, matching the Kimi/MiniMax +// entries that already used it. Scope is those surfaces, not the word "usage" everywhere: a +// measured volume ("Daily usage" 每日使用量, "Refresh Claude usage" 刷新 Claude 使用量) stays 使用量. +describe('zh provider usage wording (#12881)', () => { + it('renders every " Usage" label as " 使用情况"', () => { + for (const [key, brand] of [ + // status bar item menu + ['3885eb74d8', 'Claude'], + ['c0909c686e', 'Codex'], + ['c1df0d67ec', 'Gemini'], + ['antigravityUsage', 'Antigravity'], + ['8c86cd77b0', 'OpenCode Go'], + ['5e59007df4', 'Kimi'], + ['3bbf140864', 'MiniMax'], + ['grokUsageMenu', 'Grok'], + // Settings > Appearance search index — mirrors the menu labels + ['9dc15020d7', 'Claude'], + ['54b1acf24f', 'Codex'], + ['5bfb874d05', 'Gemini'], + ['antigravityUsageTitle', 'Antigravity'], + ['bc046e7899', 'OpenCode Go'], + ['3a6c028ea8', 'Kimi'], + ['0f08f6b483', 'MiniMax'], + ['f8e2a1c4b6', 'Grok'], + // Settings > Accounts search index + ['733f9e2a93', 'MiniMax'], + ['f4a8c2e1b7', 'Grok (xAI)'] + ]) { + expect(findByKey(zh, key), key).toBe(`${brand} 使用情况`) + } + }) + + it('leaves the Kimi and Moonshot search keywords untransliterated', () => { + expect(findByKey(zh, '40e5c3c285')).toBe('kimi') // not 基米 + expect(findByKey(zh, '35565867cb')).toBe('moonshot') // not 登月计划 ("moon landing programme") + }) + + it('keeps the status bar toggle descriptions on 使用情况', () => { + expect(findByKey(zh, 'antigravityUsageDescription')).toBe( + '在状态栏中显示 Antigravity 订阅使用情况。' + ) + expect(findByKey(zh, 'e7d1b0f3a5')).toBe('显示来自 Grok CLI OAuth 的 Grok 每周额度使用情况。') + expect(findByKey(zh, 'grokToggleDescription')).toBe( + '通过 Grok CLI 登录后显示 Grok 订阅额度使用情况。' + ) + expect(findByKey(zh, 'antigravityToggleDescription')).toBe( + '显示当前工作区的 Antigravity 订阅使用情况。' + ) + }) + + it('uses one wording for the "Open usage details" labels', () => { + for (const [key, brand] of [ + ['fda8146810', 'Kimi'], + ['629251f4b6', 'OpenCode Go'], + ['d2375976eb', 'Gemini'], + ['06741a2f3d', 'MiniMax'], + ['antigravityUsageDetails', 'Antigravity'], + ['grokUsageAria', 'Grok'] + ]) { + expect(findByKey(zh, key), key).toBe(`打开 ${brand} 使用详情`) + } + }) +})