Garde i18n : comparer les variables d'interpolation {{…}} entre fr.json et en.json #480

Open
opened 2026-10-20 00:32:08 +00:00 by maximus · 0 comments
Owner

Contexte

Suivi proposé par la revue indépendante de la PR #468 (#453, commentaire 25409), hors du périmètre de #453. Décision de Max (2026-10-19) : issue de suivi.

La garde src/i18n/locales.keys.test.ts (#453) compare les clés des deux langues, pas leurs valeurs. Une clé où fr.json écrit {{count}} et en.json {{n}} passe la garde et affiche la variable brute dans une langue. Mesuré par le relecteur sur la tête de #468 : aucun écart de variables sur les 1712 clés, donc une telle garde serait verte d'emblée. Aujourd'hui, seuls des tests ciblés vérifient les variables de leurs propres phrases (onboardingPath.locales.test.ts, csvAutoDetect.test.ts, bankSignatures.test.ts, importFormat.test.ts).

Travail

  • Pour chaque clé présente dans les deux fichiers, l'ensemble des variables {{nom}} est le même en FR et en EN ; le message d'échec nomme la clé et les variables en écart.
  • Mutation : renommer une variable dans une seule langue fait échouer la garde.
  • Exceptions éventuelles (une forme _one qui écrit le nombre en toutes lettres, par exemple) décidées sur la base réelle, sans liste ouverte.

Liens : #453, PR #468 (commentaire 25409).

Analyse (/analyze, 2026-10-20, main 45d8493, #453 mergée)

Mesure sur main

Feuilles communes aux deux fichiers : 1689 (aucune clé dans une seule langue, garde #453 verte) ; 117 feuilles avec au moins une variable ; 22 formes plurielles (_one / _other) ; une seule clé avec option de format, onboarding.card.transactions.uncategorized ({{filter, lowercase}}, identique dans les deux langues) ; aucune forme {{- …}} ni $t(…). Zéro écart de variables : la garde sera verte d'emblée et aucune exception n'est nécessaire (les formes _one écrivent {{count}} dans les deux langues).

Conception

  • Dans src/i18n/locales.keys.test.ts (même parcours des feuilles que #453, un describe « locale values: interpolation variables (#480) ») : pour chaque chemin feuille présent dans les deux fichiers, l'ensemble des jetons {{…}} normalisés (contenu sans blancs superflus, option de format comprise : filter, lowercase ≠ filter) est le même ; message d'échec par clé, clé: {{a}}, {{b}} in fr.json ; {{a}}, {{c}} in en.json, sur la liste complète des écarts et non le premier.
  • Comparer le jeton entier plutôt que le nom seul : un formateur oublié dans une langue afficherait le texte brut (Dépenses au lieu de dépenses).
  • Un canari : import.rootFiles.message_one porte count, folder et names des deux côtés, et onboarding.card.transactions.uncategorized porte filter, lowercase ; une lecture vide ferait passer la comparaison sur rien.
  • Tests unitaires sur des arbres synthétiques, même modèle que « locale keys: the comparison (#453) » : variable renommée d'un côté, variable absente d'un côté, option de format différente, mêmes variables dans un autre ordre (passe), même variable répétée (passe), clé sans variable (passe).

Travail à faire

  • Helper pur variablesOf(text) (ensemble des jetons normalisés) et variableGaps(fr, en) à côté de missingKeys et kindGaps.
  • Le describe sur les vrais fichiers, avec le canari.
  • Les tests synthétiques ci-dessus.
  • Mutation (passe de l'auteur, restaurée par git) : renommer {{folder}} en {{dir}} dans en.json seul, et retirer , lowercase d'un côté : la garde rougit et nomme la clé.
  • Pas d'entrée de CHANGELOG (tests seuls) ; docs/architecture.md si la section des gardes de test liste locales.keys.test.ts.

Fichiers concernés

  • src/i18n/locales.keys.test.ts — seul fichier.

Surface de test

  • Existants : locales.keys.test.ts (#453), src/__integration__/i18n-mock-guard.test.ts, et les tests ciblés nommés dans le corps.
  • Régression : non applicable (refactor, garde nouvelle).

Complexité

Simple. Niveau de revue : normal. Prochaine étape : /fix-issue 480.

## Contexte Suivi proposé par la revue indépendante de la PR #468 (#453, commentaire 25409), hors du périmètre de #453. **Décision de Max (2026-10-19)** : issue de suivi. La garde `src/i18n/locales.keys.test.ts` (#453) compare les clés des deux langues, pas leurs valeurs. Une clé où `fr.json` écrit `{{count}}` et `en.json` `{{n}}` passe la garde et affiche la variable brute dans une langue. Mesuré par le relecteur sur la tête de #468 : aucun écart de variables sur les 1712 clés, donc une telle garde serait verte d'emblée. Aujourd'hui, seuls des tests ciblés vérifient les variables de leurs propres phrases (`onboardingPath.locales.test.ts`, `csvAutoDetect.test.ts`, `bankSignatures.test.ts`, `importFormat.test.ts`). ## Travail - [ ] Pour chaque clé présente dans les deux fichiers, l'ensemble des variables `{{nom}}` est le même en FR et en EN ; le message d'échec nomme la clé et les variables en écart. - [ ] Mutation : renommer une variable dans une seule langue fait échouer la garde. - [ ] Exceptions éventuelles (une forme `_one` qui écrit le nombre en toutes lettres, par exemple) décidées sur la base réelle, sans liste ouverte. Liens : #453, PR #468 (commentaire 25409). ## Analyse (`/analyze`, 2026-10-20, `main` `45d8493`, #453 mergée) ### Mesure sur `main` Feuilles communes aux deux fichiers : 1689 (aucune clé dans une seule langue, garde #453 verte) ; 117 feuilles avec au moins une variable ; 22 formes plurielles (`_one` / `_other`) ; une seule clé avec option de format, `onboarding.card.transactions.uncategorized` (`{{filter, lowercase}}`, identique dans les deux langues) ; aucune forme `{{- …}}` ni `$t(…)`. **Zéro écart de variables** : la garde sera verte d'emblée et **aucune exception n'est nécessaire** (les formes `_one` écrivent `{{count}}` dans les deux langues). ### Conception - Dans `src/i18n/locales.keys.test.ts` (même parcours des feuilles que #453, un `describe` « locale values: interpolation variables (#480) ») : pour chaque chemin feuille présent dans les deux fichiers, l'ensemble des jetons `{{…}}` normalisés (contenu sans blancs superflus, option de format comprise : `filter, lowercase` ≠ `filter`) est le même ; message d'échec par clé, `clé: {{a}}, {{b}} in fr.json ; {{a}}, {{c}} in en.json`, sur la liste complète des écarts et non le premier. - Comparer le jeton entier plutôt que le nom seul : un formateur oublié dans une langue afficherait le texte brut (`Dépenses` au lieu de `dépenses`). - Un canari : `import.rootFiles.message_one` porte `count`, `folder` et `names` des deux côtés, et `onboarding.card.transactions.uncategorized` porte `filter, lowercase` ; une lecture vide ferait passer la comparaison sur rien. - Tests unitaires sur des arbres synthétiques, même modèle que « locale keys: the comparison (#453) » : variable renommée d'un côté, variable absente d'un côté, option de format différente, mêmes variables dans un autre ordre (passe), même variable répétée (passe), clé sans variable (passe). ### Travail à faire - [ ] Helper pur `variablesOf(text)` (ensemble des jetons normalisés) et `variableGaps(fr, en)` à côté de `missingKeys` et `kindGaps`. - [ ] Le `describe` sur les vrais fichiers, avec le canari. - [ ] Les tests synthétiques ci-dessus. - [ ] Mutation (passe de l'auteur, restaurée par git) : renommer `{{folder}}` en `{{dir}}` dans `en.json` seul, et retirer `, lowercase` d'un côté : la garde rougit et nomme la clé. - [ ] Pas d'entrée de CHANGELOG (tests seuls) ; `docs/architecture.md` si la section des gardes de test liste `locales.keys.test.ts`. ### Fichiers concernés - `src/i18n/locales.keys.test.ts` — seul fichier. ### Surface de test - Existants : `locales.keys.test.ts` (#453), `src/__integration__/i18n-mock-guard.test.ts`, et les tests ciblés nommés dans le corps. - Régression : non applicable (refactor, garde nouvelle). ### Complexité Simple. Niveau de revue : normal. Prochaine étape : `/fix-issue 480`.
maximus added the
status:triage
type:refactor
source:human
labels 2026-10-20 00:32:08 +00:00
maximus added
status:ready
and removed
status:triage
labels 2026-10-21 01:04:32 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#480
No description provided.