From 07ea055d4e3c55ea7da3805f857f4467d17f482d Mon Sep 17 00:00:00 2001 From: Tim Kang Date: Wed, 28 Oct 2026 09:34:46 +0900 Subject: [PATCH] fix(i18n): interpolate the settings-search empty-state query instead of concatenating translated fragments (#19693) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(i18n): interpolate the settings-search empty-state query The empty state rendered three sibling JSX nodes: a translated prefix `No settings found for "`, the raw query, then a translated closing `"`. English reads correctly only because English puts the quoted term after the verb. Korean and Chinese put it before, so translators given the leading fragment in isolation localized it as a complete clause and the query was concatenated after the sentence had already ended: ko: "에 대한 설정을 찾을 수 없습니다.screen reader" zh: 找不到“的设置screen reader” No value for the prefix key can fix this. A fixed prefix/suffix split hard-codes one word order into the code, and the position where a language needs the interpolated value is exactly what differs between languages — so any single split is wrong for some locale by construction. The message has to be one string with a placeholder, which moves the decision of where the query goes from the JSX into each locale's catalog entry. Replace the fragments with one `{{value0}}` message under a new key. The old keys are retired rather than reused: their translations are clause fragments and would be wrong under the new shape. Korean and Chinese get the natural order; es/fr/ja reassemble their own existing fragments around the placeholder. ko/zh are also pinned in the cross-locale key overrides next to the existing precedent for this same fragment-concatenation class, so a catalog regeneration cannot reintroduce the clause form. Co-Authored-By: Claude Opus 5 (1M context) * test(i18n): drop assertions the expected-message table already makes Three of the file's assertions restated what the per-locale exact-match table proves on its own, and one setup step was dead: - "carries the query placeholder in every locale" — an exact match on the rendered sentence cannot pass if a catalog value lost `{{value0}}`, since the query would be missing from the output. Its `undefined` skip branch was also unreachable: the catalogs it iterates are the same six the table covers. - "closes the ko/zh clause after the query" — `toBe` on the full string already fixes where the clause sits relative to the query. - `beforeEach(changeLanguage('en'))` — the remaining table test sets its own language per case, and the catalog test reads the JSON directly and never consults i18n. Verified by mutation rather than assumed. Each of these makes the trimmed file fail, so nothing the deleted assertions guarded is now unguarded: ko value loses {{value0}} 1 failed / 6 passed es value loses {{value0}} 1 failed / 6 passed ko puts the clause before the query 1 failed / 6 passed zh ends with the query 1 failed / 6 passed a retired fragment key returns in ja 1 failed / 6 passed Clean: 7 passed. With the rest of the change reverted to main and this file kept: 6 failed / 1 passed. The docblock keeps the reason the shape changed and loses the retelling of it. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- config/scripts/locale-cross-locale-key-overrides.mjs | 5 +++++ config/scripts/locale-ko-key-overrides.json | 3 --- .../src/components/settings/settings-page-renderer.tsx | 7 +++---- src/renderer/src/i18n/locales/en.json | 5 ++--- src/renderer/src/i18n/locales/es.json | 5 ++--- src/renderer/src/i18n/locales/fr.json | 5 ++--- src/renderer/src/i18n/locales/ja.json | 5 ++--- src/renderer/src/i18n/locales/ko.json | 5 ++--- src/renderer/src/i18n/locales/pt.json | 5 ++--- src/renderer/src/i18n/locales/zh.json | 5 ++--- 10 files changed, 22 insertions(+), 28 deletions(-) diff --git a/config/scripts/locale-cross-locale-key-overrides.mjs b/config/scripts/locale-cross-locale-key-overrides.mjs index db056fd2b5e..cc7ac77c713 100644 --- a/config/scripts/locale-cross-locale-key-overrides.mjs +++ b/config/scripts/locale-cross-locale-key-overrides.mjs @@ -40,6 +40,11 @@ export const CROSS_LOCALE_KEY_OVERRIDES = { zh: '/{{value0}}', ja: '/{{value0}}' }, + // ko/zh put the quoted query before the verb phrase; MT tends to move it after. + 'auto.components.settings.Settings.noSettingsFoundForQuery': { + ko: '"{{value0}}"에 대한 설정을 찾을 수 없습니다.', + zh: '找不到“{{value0}}”的设置' + }, 'auto.components.settings.TasksPane.6b23a34f6d': { zh: 'Jira', ja: 'Jira' diff --git a/config/scripts/locale-ko-key-overrides.json b/config/scripts/locale-ko-key-overrides.json index f61fe6c6d72..f7d74894e1f 100644 --- a/config/scripts/locale-ko-key-overrides.json +++ b/config/scripts/locale-ko-key-overrides.json @@ -2645,9 +2645,6 @@ "auto.components.settings.Settings.23931df7e8": { "ko": "원격 호스트" }, - "auto.components.settings.Settings.3c88ec55d6": { - "ko": "\"에 대한 설정을 찾을 수 없습니다." - }, "auto.components.settings.Settings.3d9adfe6a5": { "ko": "전역 터미널, 브라우저, Markdown 탭." }, diff --git a/src/renderer/src/components/settings/settings-page-renderer.tsx b/src/renderer/src/components/settings/settings-page-renderer.tsx index eea2c9bbf8f..7347a11c626 100644 --- a/src/renderer/src/components/settings/settings-page-renderer.tsx +++ b/src/renderer/src/components/settings/settings-page-renderer.tsx @@ -121,11 +121,10 @@ export function renderSettingsPage(context: SettingsRenderContext): React.JSX.El {navigation.visibleNavSections.length === 0 ? (
{translate( - 'auto.components.settings.Settings.3c88ec55d6', - 'No settings found for "' + 'auto.components.settings.Settings.noSettingsFoundForQuery', + 'No settings found for "{{value0}}"', + { value0: model.settingsSearchQuery.trim() } )} - {model.settingsSearchQuery.trim()} - {translate('auto.components.settings.Settings.add3b97ee6', '"')}
) : ( diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 680f643b47f..ce6a1576527 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -9260,8 +9260,6 @@ "ad6c529693": "AI Provider Accounts", "ec1ba547f7": "Manage AI agents, set a default, and customize commands.", "8afa676615": "Agents", - "add3b97ee6": "\"", - "3c88ec55d6": "No settings found for \"", "c7ad095d96": "Loading settings...", "acc7bbdefd": "Press ESC again to exit settings", "43b68e10f0": "You have unsaved AI settings. Leaving will discard them.", @@ -9280,7 +9278,8 @@ "linearTitle": "Linear", "linearDescription": "How Linear works in Orca, setup checklist, agent skill, and example prompts.", "tasksDescription": "Connect providers, install the Linear skill, and choose what appears in Tasks.", - "remoteServersDescription": "Run Orca on another machine and work on it from here." + "remoteServersDescription": "Run Orca on another machine and work on it from here.", + "noSettingsFoundForQuery": "No settings found for \"{{value0}}\"" }, "SettingsFormControls": { "42a4d15a30": "No matching fonts.", diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index 2cb7c036705..9236722b9ae 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -8733,8 +8733,6 @@ "ad6c529693": "Cuentas de proveedores de IA", "ec1ba547f7": "Administra agentes de IA, define uno predeterminado y personaliza comandos.", "8afa676615": "Agentes", - "add3b97ee6": "\"", - "3c88ec55d6": "No se encontraron configuraciones para \"", "c7ad095d96": "Cargando ajustes...", "acc7bbdefd": "Presiona ESC de nuevo para salir de ajustes", "43b68e10f0": "Hay ajustes de IA sin guardar. Se descartarán al salir.", @@ -8753,7 +8751,8 @@ "linearTitle": "Linear", "linearDescription": "Cómo funciona Linear en Orca, lista de configuración, habilidad del agente y ejemplos de prompts.", "tasksDescription": "Conecta proveedores, instala la habilidad de Linear y elige qué aparece en Tareas.", - "remoteServersDescription": "Ejecuta Orca en otra máquina y trabaja en ella desde aquí." + "remoteServersDescription": "Ejecuta Orca en otra máquina y trabaja en ella desde aquí.", + "noSettingsFoundForQuery": "No se encontraron configuraciones para \"{{value0}}\"" }, "SettingsFormControls": { "42a4d15a30": "No hay fuentes coincidentes.", diff --git a/src/renderer/src/i18n/locales/fr.json b/src/renderer/src/i18n/locales/fr.json index 8d93a24ed49..8cec9aba5c9 100644 --- a/src/renderer/src/i18n/locales/fr.json +++ b/src/renderer/src/i18n/locales/fr.json @@ -8938,8 +8938,6 @@ "ad6c529693": "Comptes de fournisseurs d'IA", "ec1ba547f7": "Gérez les agents IA, définissez-en un par défaut et personnalisez les commandes.", "8afa676615": "Agents", - "add3b97ee6": "\"", - "3c88ec55d6": "Aucun paramètre trouvé pour \"", "c7ad095d96": "Chargement des paramètres...", "acc7bbdefd": "Appuyez à nouveau sur ESC pour quitter les paramètres", "43b68e10f0": "Des paramètres IA ne sont pas enregistrés. Ils seront abandonnés en quittant.", @@ -8958,7 +8956,8 @@ "linearTitle": "Linear", "linearDescription": "Fonctionnement de Linear dans Orca, checklist de configuration, skill d'agent et exemples de prompts.", "tasksDescription": "Connectez des fournisseurs, installez le skill Linear et choisissez ce qui apparaît dans Tâches.", - "remoteServersDescription": "Exécutez Orca sur une autre machine et travaillez dessus depuis ici." + "remoteServersDescription": "Exécutez Orca sur une autre machine et travaillez dessus depuis ici.", + "noSettingsFoundForQuery": "Aucun paramètre trouvé pour \"{{value0}}\"" }, "SettingsFormControls": { "42a4d15a30": "Aucune police correspondante.", diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index 812ecff58e2..956cf13968e 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -8801,8 +8801,6 @@ "ad6c529693": "AI プロバイダーアカウント", "ec1ba547f7": "AI Agent を管理し、デフォルトを設定し、コマンドをカスタマイズします。", "8afa676615": "Agent", - "add3b97ee6": "」", - "3c88ec55d6": "検索条件に一致する設定が見つかりませんでした:「", "c7ad095d96": "設定を読み込んでいます…", "acc7bbdefd": "もう一度 ESC を押して設定を終了します", "43b68e10f0": "未保存の AI 設定があります。離れると破棄されます。", @@ -8821,7 +8819,8 @@ "linearTitle": "Linear", "linearDescription": "Orca での Linear の仕組み、セットアップチェックリスト、Agent スキル、プロンプト例。", "tasksDescription": "プロバイダーを接続し、Linear スキルをインストールして、タスクに表示する項目を選択します。", - "remoteServersDescription": "別のマシンで Orca を実行し、ここから作業します。" + "remoteServersDescription": "別のマシンで Orca を実行し、ここから作業します。", + "noSettingsFoundForQuery": "検索条件に一致する設定が見つかりませんでした:「{{value0}}」" }, "SettingsFormControls": { "42a4d15a30": "一致するフォントがありません。", diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index 4c8c3764e45..31abf6a1b3e 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -8702,8 +8702,6 @@ "ad6c529693": "AI 제공업체 계정", "ec1ba547f7": "AI 에이전트를 관리하고, 기본값을 설정하고, 명령을 사용자 지정하세요.", "8afa676615": "에이전트", - "add3b97ee6": "\"", - "3c88ec55d6": "\"에 대한 설정을 찾을 수 없습니다.", "c7ad095d96": "설정 로드 중...", "acc7bbdefd": "설정을 종료하려면 ESC를 다시 누르세요.", "43b68e10f0": "저장하지 않은 AI 설정이 있습니다. 나가면 해당 설정이 버려집니다.", @@ -8722,7 +8720,8 @@ "linearTitle": "Linear", "linearDescription": "Orca에서 Linear가 작동하는 방식, 설정 체크리스트, 에이전트 스킬, 프롬프트 예시입니다.", "tasksDescription": "제공업체를 연결하고 Linear 스킬을 설치한 다음 작업에 표시할 항목을 선택하세요.", - "remoteServersDescription": "다른 컴퓨터에서 Orca를 실행하고 여기에서 작업하세요." + "remoteServersDescription": "다른 컴퓨터에서 Orca를 실행하고 여기에서 작업하세요.", + "noSettingsFoundForQuery": "\"{{value0}}\"에 대한 설정을 찾을 수 없습니다." }, "SettingsFormControls": { "42a4d15a30": "일치하는 글꼴이 없습니다.", diff --git a/src/renderer/src/i18n/locales/pt.json b/src/renderer/src/i18n/locales/pt.json index 54cb9ae8ee9..e3861cea075 100644 --- a/src/renderer/src/i18n/locales/pt.json +++ b/src/renderer/src/i18n/locales/pt.json @@ -4434,8 +4434,6 @@ "ad6c529693": "Contas de Provedores de IA", "ec1ba547f7": "Gerencie agentes de IA, defina um padrão e personalize comandos.", "8afa676615": "Agentes", - "add3b97ee6": "\"", - "3c88ec55d6": "Nenhuma configuração encontrada para \"", "c7ad095d96": "Carregando configurações...", "acc7bbdefd": "Pressione ESC novamente para sair das configurações", "43b68e10f0": "Você tem alterações não salvas do Autor de IA do Git. Sair vai descartá-las.", @@ -4454,7 +4452,8 @@ "linearTitle": "Linear", "linearDescription": "Como o Linear funciona no Orca, checklist de configuração, skill de agente e exemplos de prompts.", "tasksDescription": "Conecte provedores, instale a skill do Linear e escolha o que aparece em Tarefas.", - "remoteServersDescription": "Execute o Orca em outra máquina e trabalhe nela por aqui." + "remoteServersDescription": "Execute o Orca em outra máquina e trabalhe nela por aqui.", + "noSettingsFoundForQuery": "Nenhuma configuração encontrada para \"{{value0}}\"" }, "experimental": { "search": { diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index e2c8c3dd41f..fc0ff876e7c 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -8702,8 +8702,6 @@ "ad6c529693": "AI 提供商账户", "ec1ba547f7": "管理 AI 智能体、设置默认值并自定义命令。", "8afa676615": "智能体", - "add3b97ee6": "”", - "3c88ec55d6": "找不到“的设置", "c7ad095d96": "正在加载设置...", "acc7bbdefd": "再按一次 ESC 退出设置", "43b68e10f0": "你有未保存的 AI 设置。离开后这些设置将被放弃。", @@ -8722,7 +8720,8 @@ "linearTitle": "Linear", "linearDescription": "Linear 在 Orca 中的工作方式、设置清单、智能体技能和提示词示例。", "tasksDescription": "连接提供商、安装 Linear 技能并选择要在任务中显示的内容。", - "remoteServersDescription": "在另一台机器上运行 Orca,并在这里使用它。" + "remoteServersDescription": "在另一台机器上运行 Orca,并在这里使用它。", + "noSettingsFoundForQuery": "找不到“{{value0}}”的设置" }, "SettingsFormControls": { "42a4d15a30": "没有匹配的字体。",