fix(i18n): repair French locale drift breaking static analysis

The French UI locale landed with two catalog drifts that fail `static
analysis` on every PR in the repo:

- `fr.json` carried 15 keys absent from `en.json` (and from every other
  locale), so `verify:localization-catalog` rejected it. They are stale
  entries generated against an older `en.json` snapshot; none is
  referenced anywhere in the source.
- `settings.appearance.language.french` had no call site supplying a
  literal default, which promotes it to a boot-bundle-required entry
  that `en-runtime-required.json` does not ship, so
  `verify:localization-runtime-catalog` rejected it.

Registering the key in settings search alongside its siblings fixes the
runtime-catalog failure at its source and closes the real gap the drift
exposed: French was the only supported language not findable in settings
search.

`en-runtime-required.json` is deliberately untouched — the sync script
regenerates it wholesale and would drop 925 entries the check itself
documents as harmless.
This commit is contained in:
Neil
2026-09-03 17:44:19 -07:00
parent 963839aa4f
commit 24be6aedac
4 changed files with 16 additions and 19 deletions
@@ -55,6 +55,13 @@
"dynamic": false,
"count": 1
},
{
"filePath": "src/renderer/src/components/settings/appearance-search.ts",
"kind": "object-property:keywords",
"text": "Langue",
"dynamic": false,
"count": 1
},
{
"filePath": "src/renderer/src/components/settings/terminal-advanced-platform-search.ts",
"kind": "object-property:keywords",
@@ -7,14 +7,14 @@ import { matchesSettingsSearch } from './settings-search'
// Native word for "language" in each supported UI language. These must be
// findable no matter which locale the interface is currently rendered in, so a
// speaker can locate (and switch to) their language from any starting point.
const NATIVE_LANGUAGE_WORDS = ['语言', '語言', '언어', '言語', 'Idioma']
const NATIVE_LANGUAGE_WORDS = ['语言', '語言', '언어', '言語', 'Idioma', 'Langue']
describe('getLanguageEntries', () => {
afterEach(async () => {
await i18n.changeLanguage('en')
})
it.each(['en', 'zh', 'ko', 'ja', 'es'])(
it.each(['en', 'zh', 'ko', 'ja', 'es', 'fr'])(
'indexes every native word for "language" under the %s UI locale',
async (locale) => {
await i18n.changeLanguage(locale)
@@ -29,4 +29,9 @@ describe('getLanguageEntries', () => {
await i18n.changeLanguage('en')
expect(matchesSettingsSearch('Español', getLanguageEntries()[0])).toBe(true)
})
it('matches the French native language name in English UI', async () => {
await i18n.changeLanguage('en')
expect(matchesSettingsSearch('Français', getLanguageEntries()[0])).toBe(true)
})
})
@@ -50,6 +50,7 @@ export const getLanguageEntries = createLocalizedCatalog((): SettingsSearchEntry
...translateSearchKeyword('settings.appearance.language.korean', '한국어'),
...translateSearchKeyword('settings.appearance.language.japanese', '日本語'),
...translateSearchKeyword('settings.appearance.language.spanish', 'Español'),
...translateSearchKeyword('settings.appearance.language.french', 'Français'),
// Why: the native word for "language" only reaches search via the localized
// title in its own UI locale — index each here so speakers can find (and
// switch to) their language whatever the current interface locale is.
@@ -58,6 +59,7 @@ export const getLanguageEntries = createLocalizedCatalog((): SettingsSearchEntry
'언어', // Korean
'言語', // Japanese
'Idioma', // Spanish
'Langue', // French
...translateSearchKeyword(
'auto.components.settings.appearance.search.language.locale',
'locale'
-17
View File
@@ -2934,7 +2934,6 @@
"a7e2fd2699": "signaler un problème",
"5c8ce20be6": "Si le problème persiste, veuillez",
"cc6d997c65": "Redémarrez le daemon de terminal depuis ici pour effacer un état de daemon obsolète.",
"7ee11bc0db": "Orca n'a pas pu confirmer si la session précédente de ce terminal tourne encore ; il a donc laissé la session intacte. Rouvrez ce volet pour réessayer.",
"e16012e31e": "Le daemon de terminal propriétaire de cette session s'est arrêté ; la session et son historique de défilement n'ont pas pu être récupérés. Ouvrez un nouveau terminal pour continuer.",
"sessionUnavailable": "Orca n'a pas pu se rattacher à la session de terminal de ce volet sur l'hôte. Ouvrez un nouveau terminal pour continuer."
},
@@ -3228,7 +3227,6 @@
"25dc1cd653": "Ouvrir le fichier",
"7cdf8ee0c8": "Ouvrir une URL",
"b27864279e": "Lancer un agent",
"0e5b7a3f16": "Rechercher parmi les onglets ouverts, fichiers, URL et agents…",
"8f0a1c4d92": "Basculer vers l'onglet",
"2c38630a01": "L'espace de travail n'existe plus",
"4f0d9a71c2": "L'onglet n'existe plus",
@@ -3274,7 +3272,6 @@
"classifier": {
"42e6262ae9": "Aucune action disponible.",
"097a982ee0": "Chargement des fichiers...",
"c41f8d20b7": "Rechercher parmi les onglets ouverts, fichiers, URL et agents…",
"90eb94dc48": "Saisissez une URL http:// ou https://.",
"5553b283ce": "Saisissez une URL ou un chemin de fichier.",
"queryTooLarge": "Le texte recherché est trop long.",
@@ -6999,12 +6996,6 @@
"compareBaseRepositoryDefault": "Valeur par défaut du dépôt",
"compareBaseBranchUpstream": "Amont de la branche"
},
"HiddenExperimentalGroup": {
"d0f914a528": "Bascule fictive",
"1014ddbfaf": "Sans effet aujourd'hui. Réservée comme premier emplacement pour les options expérimentales masquées.",
"232cf83de8": "Bascules non répertoriées pour les tests internes. Rien ici n'est pris en charge.",
"3e9e827ca5": "Expérimental masqué"
},
"InputPane": {
"db15068196": "Activé par défaut sur Linux et macOS. Linux utilise le presse-papiers de sélection du système ; les autres plateformes utilisent un tampon privé.",
"ad31c3c5fb": "Collage de la sélection au clic milieu"
@@ -11832,10 +11823,6 @@
"b3c8f1a902": "Filtrer les fichiers par nom",
"d4f8c2a901": "Effacer et fermer le filtre",
"e8a1c4b203": "vs",
"f9b2441bb6": "1 commit d'avance sur {{value0}}",
"b715ef615b": "{{value0}} commits d'avance sur {{value1}}",
"c1a8f3e204": "1 commit de retard sur {{value0}}",
"d2b9g4f315": "{{value0}} commits de retard sur {{value1}}",
"4b4a7de138": "Ouvrir la page de revue dans le navigateur",
"createPrIntentCommitBlockedSummary": "Commit bloqué : {{value0}} Corrigez le problème, puis réessayez Créer une PR.",
"pushRecovery": {
@@ -11858,7 +11845,6 @@
"a4e93c21d7": "Branche actuelle : {{value0}}",
"c7d4e2f801": "Modifier la ref de base : {{value0}}",
"f3a1b8c204": "upstream",
"createPrIntentEmptyGeneratedBody": "Les détails de revue générés n'incluent pas de description. Réessayez Créer une PR.",
"createPrIntentGenerateDetailsFailed": "Impossible de générer les détails de revue. Réessayez Créer une PR."
},
"SourceControlAgentActionDialog": {
@@ -14038,8 +14024,6 @@
"7e7ca60816": "fichiers modifiés",
"b6c3b84476": "Afficher l'arborescence des fichiers",
"39f8007549": "Examiner les conflits",
"39e73e7181": "ont été exclus de cette vue de diff.",
"689b99f8ad": "conflit non résolu",
"820ec01f24": "Les fichiers en conflit sont examinés séparément",
"fd8892b120": "Aucune modification à afficher",
"eb5f40e49c": "Cette vue de diff exclut les conflits non résolus, car le pipeline de diff bidirectionnel habituel n'est pas conçu pour gérer les conflits.",
@@ -15793,7 +15777,6 @@
},
"LinuxPackageInstallRecoveryCard": {
"e3de29c86a": "Afficher le paquet",
"3da99454c6": "Réessayer l'installation automatique",
"55c86654b7": "Copier la commande d'installation",
"53e1559f99": "Échec de l'installation automatique",
"a7ac6ec78b": "Orca a téléchargé la mise à jour mais n'a pas pu installer le paquet système automatiquement.",