Documentation — Multi-langue
Structure des dictionnaires, interpolation de variables, pluriels, formats de dates et de nombres par locale, et stratégie de repli sur la langue de référence.
Structure des dictionnaires
Un dictionnaire par langue, à clés plates et hiérarchiques (domaine.section.cle). Le français est la langue de référence : il doit être complet ; les autres langues peuvent être partielles, le repli comble les trous. Les clés couvrent l'UI (titres, navigation, colonnes), les statuts métier, les actions et les messages.
{
"fr": {
"app.titre": "Suivi des commandes",
"nav.commandes": "Commandes",
"commandes.statut.expediee": "Expédiée",
"commandes.total": "Total des commandes",
"action.valider": "Valider la commande",
"message.bienvenue": "Bonjour, {prenom}",
"commandes.nombre": "{count} commande|{count} commandes"
},
"en": { "app.titre": "Order tracking", "...": "..." },
"es": { "app.titre": "Seguimiento de pedidos", "...": "..." }
}Interpolation
Les valeurs peuvent contenir des variables entre accolades, remplacées au rendu : t("message.bienvenue", { prenom: "Camille" }) donne « Bonjour, Camille » en FR et « Welcome, Camille » en EN. Les variables doivent être conservées telles quelles dans chaque langue (l'ordre des mots peut changer, pas le nom de la variable).
function applyVars(raw: string, vars: Record<string, string>): string {
let out = raw;
for (const [name, value] of Object.entries(vars)) {
out = out.split(`{${name}}`).join(value);
}
return out;
}Pluriels
Les clés plurielles stockent les formes one|other séparées par « | ». La forme est choisie par Intl.PluralRules(locale).select(count) — ce qui gère correctement les règles de chaque langue (en français, 0 et 1 sont au singulier ; en anglais et en espagnol, seul 1 l'est). {count} est ensuite formaté avec Intl.NumberFormat.
// "commandes.nombre": "{count} commande|{count} commandes"
const rule = new Intl.PluralRules("fr-FR").select(3); // "other"
const [one, other] = raw.split("|");
const text = (rule === "one" ? one : other).replace("{count}", "3");
// → "3 commandes" (FR) / "3 orders" (EN) / "3 pedidos" (ES)Formats de dates et de nombres par locale
Les montants et les dates ne sont jamais traduits : ils sont formatés par les API Intl avec la locale active. Le même montant 1234.56 € et la même date ISO donnent :
new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" }).format(1234.56)
// → "1 234,56 €"
new Intl.NumberFormat("en-US", { style: "currency", currency: "EUR" }).format(1234.56)
// → "€1,234.56"
new Intl.NumberFormat("es-ES", { style: "currency", currency: "EUR" }).format(1234.56)
// → "1234,56 €"
const d = new Date("2026-06-10T09:30:00"); // littéral ISO figé → déterministe
new Intl.DateTimeFormat("fr-FR", { dateStyle: "long" }).format(d) // "10 juin 2026"
new Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(d) // "June 10, 2026"
new Intl.DateTimeFormat("es-ES", { dateStyle: "long" }).format(d) // "10 de junio de 2026"Repli (fallback) sur la langue de référence
- Résolution — la clé est cherchée dans la langue active ; si absente, la valeur française est utilisée ; si la clé n'existe nulle part, la clé brute est affichée (jamais de texte vide).
- Signalement — les valeurs repliées sont soulignées en pointillé dans l'aperçu et listées dans le panneau « Couverture des traductions » avec une barre de progression par langue.
- Correction — chaque clé manquante propose un bouton « Traduire » qui ouvre l'éditeur ; la traduction ajoutée est immédiatement visible dans l'aperçu et fait monter la couverture.
- Persistance — le choix de langue est mémorisé en localStorage et relu au montage (rendu initial en français pour rester compatible SSR).
Intégration en production
Le simulateur fonctionne en local (dictionnaires seedés, état React). En production : stocker les dictionnaires en base ou en fichiers JSON par locale, exposer la couverture par langue dans un back-office de traduction, et négocier la langue initiale via Accept-Language ou le profil utilisateur — en conservant la même résolution clé → langue active → langue de référence.