Table des matières
Fichiers de traduction JSON : formats, structure et bonnes pratiques pour l'i18n
Presque toutes les applications web disponibles en plusieurs langues stockent leurs traductions dans des fichiers JSON. Le format est omniprésent, mais les conventions qui l'entourent ne sont pas uniformes. Différents frameworks attendent des structures différentes : un objet clé-valeur plat, un arbre d'espaces de noms profondément imbriqués, un message avec une syntaxe ICU intégrée, ou un manifeste d'extension Chrome avec sa propre structure de descripteur. Choisir le mauvais format au départ ou migrer entre formats ultérieurement engendre des coûts réels.
Ce guide couvre les principaux formats de traduction JSON utilisés aujourd'hui, comment organiser les fichiers de traduction à grande échelle, les conventions de nommage des clés, les modèles de pluralisation, les outils de validation et comment passer de JSON aux formats alternatifs comme XLIFF et PO.
TL;DR / Points clés
- JSON est le format dominant pour l'i18n web car il est natif à JavaScript, lisible par l'homme et fonctionne bien avec le contrôle de version — mais il n'existe pas de "format JSON i18n" unique. Chaque bibliothèque majeure définit ses propres conventions.
- Les variantes les plus courantes sont : clé-valeur plat (simple mais difficile à maintenir à grande échelle), imbriqué/namespace (organisé mais verbeux), i18next (namespace avec suffixes de clé pluriel intégrés), FormatJS/react-intl (ICU MessageFormat dans les valeurs) et chrome.i18n (objets descripteurs avec un champ
messageet unedescriptionoptionnelle). - L'organisation des fichiers est aussi importante que le format : diviser les traductions par namespace ou domaine de fonctionnalité maintient les fichiers petits, réduit les conflits de fusion et permet le chargement différé.
- La syntaxe de pluralisation et d'interpolation de variables varie selon la bibliothèque — utiliser ICU MessageFormat dans les valeurs offre l'option la plus portable et expressive, mais nécessite un runtime compatible.
- La validation en CI — vérification des clés manquantes, du JSON malformé et des chaînes non traduites — est le moyen le plus efficace d'empêcher les traductions cassées d'atteindre la production.
Pourquoi JSON pour les traductions ?
Avant de comparer les formats, il vaut la peine de comprendre pourquoi JSON est devenu le standard pour l'i18n web — et pourquoi ce choix n'est pas toujours évident.
Lisible par l'homme et adapté aux diffs. Un fichier de traduction JSON est lisible sans outil. Un diff dans une pull request montre exactement quelles chaînes ont changé, lesquelles ont été ajoutées et lesquelles ont été supprimées. Comparez cela à XLIFF 2.0, où le même changement est enfoui dans des attributs XML sur plusieurs éléments, ou aux formats binaires compilés où les diffs sont illisibles.
Natif à JavaScript. JSON.parse() est intégré dans chaque runtime JavaScript. Il n'y a pas de dépendance de parsing à installer, pas d'adaptateur de format à configurer. Quand une application Next.js regroupe des traductions pour le navigateur, elle envoie du JSON brut — sans surcharge de sérialisation, sans parser personnalisé.
Facile à générer et à consommer programmatiquement. Chaque langage a une bibliothèque JSON. Générer des fichiers de traduction depuis une base de données, un export de tableur ou une API de système de gestion de traduction est une tâche directe de sérialisation JSON.
Fonctionne bien avec le contrôle de version. Les fichiers JSON sont du texte. Ils fusionnent proprement quand les changements sont dans des clés différentes, ils produisent un historique de blame lisible et fonctionnent avec les outils diff standard.
Alternatives et leurs compromis
| Format | Points forts | Points faibles |
|---|---|---|
| XLIFF 2.0 | Métadonnées riches, notes de traducteur, suivi d'état, standard industriel | XML verbeux, mauvaise lisibilité des diffs, outillage complexe |
| PO / Gettext | Écosystème mature, le modèle msgid/msgstr prend en charge le contexte, formes plurielles intégrées | Nécessite des parsers spécialisés, moins courant en JavaScript |
| YAML | Lisible, prend en charge les chaînes multilignes naturellement | Sensible à l'indentation (source d'erreurs), pas de parser natif dans le navigateur |
| ARB (Application Resource Bundle) | Natif Flutter/Dart, prend en charge les métadonnées par clé | Écosystème spécifique à Dart, outillage web limité |
| JSON | Omniprésent, JavaScript natif, excellent outillage | Pas de métadonnées intégrées, la gestion des pluriels varie selon la bibliothèque |
XLIFF est le bon choix quand les traductions passent par une agence de traduction professionnelle avec des outils CAT. PO convient aux projets qui souhaitent tirer parti de l'écosystème Gettext (Poedit, utilitaires GNU gettext). Pour la plupart des applications web créées en React, Vue, Angular ou Svelte, JSON est le standard pratique.
Formats de traduction JSON courants
Clé-valeur plat
Le fichier de traduction JSON le plus simple possible est un objet à un seul niveau où chaque clé est un identifiant de chaîne et chaque valeur est la chaîne traduite.
{
"welcome_message": "Bienvenue sur notre plateforme",
"login_button": "Se connecter",
"logout_button": "Se déconnecter",
"error_not_found": "Page introuvable",
"error_server": "Une erreur s'est produite. Veuillez réessayer."
}
Ce format n'a aucune courbe d'apprentissage et fonctionne avec n'importe quel parser JSON. Le problème apparaît à grande échelle : un fichier plat avec 500 clés pour une grande application devient impossible à naviguer. Il n'y a pas de regroupement visuel, pas d'indication de l'endroit où une chaîne est utilisée et aucun moyen d'extraire un sous-ensemble de traductions pour le chargement différé.
Idéal pour : Petits projets, prototypes ou applications avec moins de 100 clés de traduction.
JSON imbriqué / avec namespace
Le JSON imbriqué organise les clés dans une hiérarchie qui reflète la structure de l'application.
{
"auth": {
"login": {
"title": "Connectez-vous à votre compte",
"email_label": "Adresse e-mail",
"password_label": "Mot de passe",
"submit_button": "Se connecter",
"forgot_password": "Mot de passe oublié ?"
},
"logout": {
"confirm": "Êtes-vous sûr de vouloir vous déconnecter ?"
}
},
"dashboard": {
"greeting": "Bonjour, {{name}}",
"stats": {
"total_users": "Utilisateurs totaux",
"active_sessions": "Sessions actives"
}
}
}
Les bibliothèques comme vue-i18n et angular/localize prennent en charge le JSON imbriqué nativement. La clé est accessible avec la notation pointée : t('auth.login.title'). Cette structure se mappe naturellement aux hiérarchies de composants et facilite l'identification de l'endroit où chaque chaîne est utilisée.
Le compromis est que les objets profondément imbriqués nécessitent une gestion des clés plus soigneuse et peuvent produire de longs chemins d'accès. La plupart des équipes se fixent sur deux ou trois niveaux d'imbrication comme maximum pratique.
Format i18next
i18next est la bibliothèque i18n la plus utilisée dans l'écosystème JavaScript et possède ses propres conventions construites au-dessus du JSON imbriqué. La plus importante est son système de suffixes de clé pluriel.
{
"common": {
"save": "Enregistrer",
"cancel": "Annuler",
"loading": "Chargement..."
},
"items": {
"count_one": "{{count}} élément",
"count_other": "{{count}} éléments",
"count_zero": "Aucun élément"
},
"notifications": {
"new_one": "Vous avez {{count}} nouvelle notification",
"new_other": "Vous avez {{count}} nouvelles notifications"
}
}
i18next résout les formes plurielles en ajoutant un suffixe à la clé de base. Les suffixes suivent les catégories de règles plurielles CLDR : zero, one, two, few, many, other. Pour le français, seuls one et other s'appliquent. Pour l'arabe ou le russe, l'ensemble complet est important.
i18next prend également en charge le namespace au niveau des fichiers : chaque fichier JSON est un namespace. Quand vous appelez t('common:save'), i18next charge common.json pour la locale active. Cela permet le chargement différé au niveau du namespace dans les applications React utilisant react-i18next.
{
"title": "Bienvenue, {{name}} !",
"description": "Vous avez rejoint le {{date, datetime}}",
"price": "{{price, currency}}"
}
La syntaxe {{value, formatType}} déclenche le pipeline de formatage d'i18next, qui s'intègre avec l'API Intl pour les dates, les nombres et les devises.
Format FormatJS / react-intl
FormatJS (qui alimente react-intl) utilise la syntaxe ICU MessageFormat intégrée directement dans les valeurs de chaînes. Cela place toute la logique de pluralisation et de variables à l'intérieur de la chaîne de message elle-même plutôt que dans les suffixes de clé.
{
"welcome": "Bienvenue, {name} !",
"item_count": "{count, plural, =0 {Aucun élément} one {# élément} other {# éléments}}",
"last_login": "Dernière connexion : {date, date, medium}",
"account_status": "{gender, select, male {Il est} female {Elle est} other {C'est un}} membre vérifié.",
"notification_badge": "{count, plural, =0 {} one {({count})} other {({count})}}"
}
ICU MessageFormat est l'option la plus expressive disponible pour les règles complexes de pluriel et d'accord de genre. Le mot-clé select gère les chaînes conditionnelles, plural gère les formes basées sur le comptage et les types de format (date, number, currency) délèguent à l'API Intl.
Les clés sont généralement des chaînes plates, correspondant souvent au chemin du composant ou à un descripteur sémantique. FormatJS déconseille les structures profondément imbriquées en faveur de clés plates descriptives.
Utilisation avec react-intl :
import { useIntl, FormattedMessage } from 'react-intl';
function ItemList({ count }) {
const intl = useIntl();
return (
<p>
<FormattedMessage id="item_count" values={{ count }} />
</p>
);
}
Format chrome.i18n
Les extensions Chrome utilisent un format JSON spécifique défini par l'API chrome.i18n. Chaque clé correspond à un objet descripteur plutôt qu'à une chaîne simple.
{
"extensionName": {
"message": "Mon Extension",
"description": "Le nom de l'extension, affiché dans le Chrome Web Store."
},
"welcomeMessage": {
"message": "Bonjour, $USER$ !",
"description": "Message d'accueil affiché à l'ouverture de l'extension",
"placeholders": {
"user": {
"content": "$1",
"example": "Alice"
}
}
},
"itemCount": {
"message": "$COUNT$ éléments sélectionnés",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
}
}
Le champ description n'est pas affiché aux utilisateurs finaux — c'est du contexte pour les traducteurs et le processus de révision du Chrome Web Store. Les espaces réservés utilisent une convention $NOM_ESPACE_RESERVE$ avec un objet placeholders séparé définissant le contenu et une valeur d'exemple.
Ce format est incontournable pour les extensions Chrome. Il n'est pas adapté à l'i18n d'applications web à usage général.
Modèles d'organisation des fichiers
Un fichier par locale
L'organisation la plus simple est un fichier JSON par locale contenant toutes les traductions de l'application.
locales/ en.json fr.json de.json ja.json es.json
Cela fonctionne pour les petites applications mais crée des problèmes à grande échelle : les fichiers grossissent, des fonctionnalités sans rapport causent des conflits de fusion dans le même fichier, et vous ne pouvez pas charger de façon différée les traductions pour les sections que l'utilisateur n'a pas visitées.
Division par namespace
Le modèle le plus courant pour les applications moyennes et grandes est de diviser les traductions par namespace — un fichier JSON par zone fonctionnelle par locale.
locales/
en/
common.json
auth.json
dashboard.json
settings.json
errors.json
fr/
common.json
auth.json
dashboard.json
settings.json
errors.json
de/
common.json
auth.json
dashboard.json
settings.json
errors.json
Chaque fichier de namespace est petit et focalisé. Le namespace common contient les chaînes utilisées dans toute l'application (libellés de boutons, libellés de champs de formulaire, messages d'erreur génériques). Les namespaces de fonctionnalité contiennent les chaînes spécifiques à cette fonctionnalité.
i18next et react-i18next utilisent ce modèle nativement : t('auth:login.title') charge auth.json pour la locale active. Les applications Next.js utilisant next-i18next suivent cette structure par convention.
Division basée sur les fonctionnalités
Pour les très grandes applications, ou les monorepos où chaque package possède ses propres traductions, une structure basée sur les fonctionnalités place les fichiers de traduction à côté du code qui les utilise.
src/
features/
auth/
locales/
en.json
fr.json
components/
LoginForm.tsx
SignupForm.tsx
dashboard/
locales/
en.json
fr.json
components/
DashboardHeader.tsx
checkout/
locales/
en.json
fr.json
Ce modèle maximise la cohésion : le fichier de traduction vit à côté du composant qui l'utilise. Le système de build ou le chargeur i18n fusionne les fichiers de namespace au moment de l'exécution ou de la construction. L'inconvénient est que trouver toutes les traductions pour une locale donnée nécessite de parcourir tout l'arbre source, ce qui complique le flux de travail pour les traducteurs et les systèmes de gestion de traduction.
Recommandation : Utilisez la division par namespace pour la plupart des applications. Utilisez la division basée sur les fonctionnalités uniquement si votre équipe est assez grande pour que différentes équipes possèdent différentes fonctionnalités et doivent éviter les conflits de fusion entre fonctionnalités dans les fichiers de traduction.
Tableau comparatif des formats de fichiers de traduction
| Format | Lisibilité | Support des outils | Support des métadonnées | Support ICU | Compatibilité diff |
|---|---|---|---|---|---|
| JSON (plat) | Élevée | Excellent | Aucune | Non (par défaut) | Excellent |
| JSON (imbriqué) | Élevée | Excellent | Aucune | Non (par défaut) | Excellent |
| JSON (FormatJS) | Moyenne | Bon | Aucune | Oui (natif) | Bon |
| XLIFF 2.0 | Faible | Excellent (outils CAT) | Riche (état, notes, traductions alternatives) | Oui | Mauvaise |
| PO / Gettext | Moyenne | Bon (Poedit, Weblate) | Moyenne (commentaires, contexte) | Partiel | Moyenne |
| YAML | Élevée | Moyen | Aucune | Non | Bon |
| ARB | Élevée | Bon (Flutter) | Métadonnées par clé | Non | Bon |
L'avantage des métadonnées de XLIFF est significatif lorsqu'on travaille avec des agences de traduction professionnelles : le format suit l'état de la traduction (nouveau, traduit, révisé, final), prend en charge les traductions alternatives et est le format natif pour la plupart des outils CAT professionnels comme Phrase, memoQ et SDL Trados. Si votre flux de traduction implique des remises à des agences, générer XLIFF depuis votre source JSON (plutôt que d'envoyer du JSON brut) améliore la productivité des traducteurs et réduit les erreurs.
Conventions de nommage des clés
Le nommage cohérent des clés est la différence entre un fichier de traduction facile à maintenir et un fichier qui devient une source de bugs et de confusion.
Notation pointée vs. imbrication
Les clés plates avec des points et les objets genuinement imbriqués représentent tous deux une hiérarchie, mais ils se comportent différemment. Une clé plate avec des points est une seule chaîne — "auth.login.title". Un objet imbriqué est une vraie structure d'objet avec la clé title à l'intérieur de login à l'intérieur de auth. La plupart des bibliothèques prennent en charge les deux, mais mélanger les deux dans le même fichier crée une ambiguïté.
Recommandation : Utilisez l'imbrication genuinement dans vos fichiers JSON et la notation pointée uniquement dans le code lors de l'accès aux clés. N'utilisez pas de points dans les noms de clé au sein du même niveau d'imbrication.
{
"auth": {
"login": {
"title": "Se connecter"
}
}
}
Accessible dans le code comme t('auth.login.title') — la bibliothèque gère le parcours.
snake_case vs. camelCase
Les deux sont courants. snake_case est plus lisible dans les fichiers JSON car les mots ne se confondent pas visuellement. camelCase s'aligne avec les conventions JavaScript et est courant dans les projets FormatJS.
{
"submit_button": "Envoyer",
"error_message": "Une erreur s'est produite"
}
{
"submitButton": "Envoyer",
"errorMessage": "Une erreur s'est produite"
}
Choisissez-en un et appliquez-le avec un linter. L'incohérence au sein d'un projet est pire que n'importe quel choix.
Descriptif vs. concis
Les clés concises sont courtes mais perdent rapidement le contexte :
{
"btn_sub": "S'abonner",
"btn_cncl": "Annuler",
"err_404": "Page introuvable"
}
Les clés descriptives communiquent le but sans lire la valeur :
{
"newsletter_subscribe_button": "S'abonner",
"modal_cancel_button": "Annuler",
"error_page_not_found_title": "Page introuvable"
}
Recommandation : Utilisez des clés descriptives qui incluent le contexte UI (type ou emplacement du composant) et le type de contenu (bouton, titre, description, espace réservé). Cela permet de comprendre comment une clé est utilisée sans lire le code du composant.
Regroupement hiérarchique
Lors de l'utilisation de JSON imbriqué, groupez d'abord par zone UI, puis par composant ou action, puis par type d'élément :
{
"checkout": {
"cart": {
"title": "Votre panier",
"empty_message": "Votre panier est vide",
"item_count_one": "{{count}} article",
"item_count_other": "{{count}} articles"
},
"payment": {
"title": "Détails du paiement",
"card_number_label": "Numéro de carte",
"expiry_label": "Date d'expiration",
"submit_button": "Payer maintenant"
}
}
}
Gestion des pluriels et des variables en JSON
ICU MessageFormat (FormatJS, vue-i18n, autres)
ICU MessageFormat est la syntaxe la plus expressive et portable pour les pluriels et les variables. Elle est prise en charge nativement par FormatJS et peut être configurée dans vue-i18n et d'autres bibliothèques.
{
"file_count": "{count, plural, =0 {Aucun fichier} one {# fichier} other {# fichiers}}",
"upload_progress": "Téléversement de {current} sur {total} fichiers",
"last_seen": "Vu pour la dernière fois {time, date, relative}",
"user_role": "{role, select, admin {Administrateur} editor {Éditeur} other {Lecteur}}"
}
Le symbole # à l'intérieur d'une branche plurielle est remplacé par le compte formaté. Le mot-clé select se ramifie sur une valeur de chaîne plutôt que sur un nombre.
Convention de suffixe pluriel i18next
i18next résout les pluriels en ajoutant un suffixe à la clé. Pour le français :
{
"message_count_one": "{{count}} message",
"message_count_other": "{{count}} messages",
"message_count_zero": "Aucun message"
}
Appelé avec t('message_count', { count: 5 }), i18next sélectionne message_count_other et interpole count. Pour les langues avec plus de formes plurielles (le russe en a quatre), des variantes de suffixes supplémentaires sont définies :
{
"file_one": "{{count}} файл",
"file_few": "{{count}} файла",
"file_many": "{{count}} файлов",
"file_other": "{{count}} файлов"
}
Les catégories de règles plurielles CLDR (zero, one, two, few, many, other) correspondent aux suffixes utilisés par i18next.
Interpolation de variables
Chaque bibliothèque prend en charge une forme d'interpolation de variables. La syntaxe varie :
{
"greeting_i18next": "Bonjour, {{name}} !",
"greeting_icu": "Bonjour, {name} !",
"greeting_vue": "Bonjour, {name} !",
"greeting_angular": "Bonjour, {{ name }} !"
}
i18next utilise des doubles accolades par défaut. ICU utilise des accolades simples. Le $localize d'Angular utilise un littéral de gabarit étiqueté dans le code plutôt qu'une syntaxe d'interpolation au moment de l'exécution dans la valeur JSON.
Ne mélangez pas les syntaxes d'interpolation dans le même projet. Choisissez la syntaxe qui correspond à votre bibliothèque et appliquez-la dans la validation de votre schéma JSON.
Outillage et validation
JSON Schema pour les fichiers de traduction
Une définition JSON Schema vous permet de valider la structure des fichiers de traduction dans les pipelines CI, les éditeurs et les hooks pre-commit. Voici un schéma minimal pour un fichier de traduction clé-valeur plat :
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": {
"type": "string"
},
"minProperties": 1
}
Pour les fichiers imbriqués, le schéma devient récursif. La plupart des équipes utilisent une combinaison de JSON Schema pour la validation structurelle et un outil de linting i18n dédié pour les vérifications sémantiques.
Linting pour les clés manquantes
Le bug i18n de production le plus courant est une clé de traduction manquante — une clé présente en anglais mais absente d'un fichier de locale. Cela provoque un repli sur le nom de la clé lui-même ou une chaîne vide, ce qui casse l'UI.
i18next-parser analyse votre code source pour les appels t('key') et génère ou valide les fichiers de traduction :
npx i18next-parser --config i18next-parser.config.js
eslint-plugin-i18n-json valide directement les fichiers de traduction JSON :
npm install --save-dev eslint-plugin-i18n-json
Une configuration ESLint de base pour la validation des fichiers de traduction :
{
"plugins": ["i18n-json"],
"rules": {
"i18n-json/valid-json": "error",
"i18n-json/sorted-keys": ["warn", { "order": "asc" }],
"i18n-json/identical-keys": [
"error",
{ "filePath": "src/locales/en.json" }
]
}
}
La règle identical-keys vérifie que chaque fichier de locale contient le même ensemble de clés que le fichier de locale de référence (généralement anglais). Elle signale à la fois les clés manquantes et les clés supplémentaires qui ne devraient pas exister.
Vérifications CI pour la complétude
Une étape CI qui bloque les fusions quand un fichier de locale est incomplet prévient l'accumulation de dette de traduction. Un script shell de vérification simple :
#!/usr/bin/env bash
BASE="src/locales/en.json"
LOCALES=("fr" "de" "ja" "es")
for locale in "${LOCALES[@]}"; do
FILE="src/locales/${locale}.json"
BASE_KEYS=$(jq 'keys | length' "$BASE")
LOCALE_KEYS=$(jq 'keys | length' "$FILE")
if [ "$BASE_KEYS" != "$LOCALE_KEYS" ]; then
echo "ERREUR : ${FILE} contient ${LOCALE_KEYS} clés, ${BASE_KEYS} attendues"
exit 1
fi
done
echo "Tous les fichiers de locale sont complets."
Pour les fichiers imbriqués, le parcours de chemin jq est nécessaire. Des plateformes comme Better i18n utilisent JSON comme leur format natif et synchronisent les traductions via CLI, ce qui signifie que la vérification de complétude peut être appliquée côté plateforme avant que les traductions ne soient validées — réduisant le besoin de vérifications au niveau CI sur les fichiers incomplets.
Intégration à l'éditeur
Les extensions VS Code comme "i18n Ally" fournissent des aperçus de traduction en ligne, la mise en évidence des clés manquantes et des suggestions de traduction automatique directement dans l'éditeur. Cela décale la validation vers la gauche — les développeurs voient les traductions manquantes pendant l'écriture du code plutôt que lors du CI.
Migration entre formats
JSON vers XLIFF
XLIFF est nécessaire lors de l'envoi de traductions à une agence professionnelle. La conversion de JSON vers XLIFF 2.0 implique de mapper des paires clé-valeur vers des éléments <unit> avec des enfants <segment>.
L'outil i18next-conv gère la conversion bidirectionnelle :
npm install -g i18next-conv # JSON vers XLIFF i18next-conv -l en -s locales/en.json -t locales/en.xliff # XLIFF vers JSON i18next-conv -l fr -s locales/fr.xliff -t locales/fr.json
Pour les projets FormatJS, @formatjs/cli fournit l'export XLIFF :
npx formatjs compile-folder --ast src/locales/en.json > compiled/en.json
JSON vers PO
Le format PO (Portable Object) est utilisé par l'écosystème Gettext et pris en charge par des outils comme Poedit et Weblate. L'outil i18next-conv prend également en charge PO :
# JSON vers PO i18next-conv -l en -s locales/en.json -t locales/en.po # PO vers JSON i18next-conv -l fr -s locales/fr.po -t locales/fr.json
Pour les projets vue-i18n, le @intlify/vue-i18n-loader prend en charge directement les fichiers .po comme alternative à JSON, ce qui est utile quand votre projet Vue partage de la mémoire de traduction avec une application côté serveur utilisant Gettext.
Outils de conversion courants
| Outil | Convertit | Notes |
|---|---|---|
i18next-conv | JSON ↔ PO, JSON ↔ XLIFF, JSON ↔ CSV | Le plus complet pour le format i18next |
@formatjs/cli | FormatJS JSON → XLIFF, messages extraits → fichiers de locale | Requis pour les projets FormatJS/react-intl |
gettext-converter | PO ↔ JSON (plat) | Simple, sans hypothèses de framework |
xliff-simple-merge | Fusion et division XLIFF | Utile pour les projets Angular utilisant angular/localize |
| Éditeurs XLIFF en ligne | XLIFF ↔ JSON (via UI) | Phrase, Lokalise et Crowdin proposent tous l'import/export |
Lors de la migration entre formats, validez la sortie avant de valider. Les outils de conversion automatisés perdent parfois des chaînes de contexte, suppriment des commentaires ou gèrent incorrectement les formes plurielles pour les langues avec des règles plurielles non standard.
FAQ
Quel format JSON dois-je utiliser pour un nouveau projet React ?
Si vous utilisez react-i18next (qui est le choix le plus courant), commencez avec du JSON imbriqué divisé par namespace en suivant les conventions i18next. Si vous utilisez react-intl ou une configuration basée sur FormatJS, utilisez des clés plates avec la syntaxe ICU MessageFormat dans les valeurs. La bibliothèque que vous choisissez détermine le format — choisissez d'abord la bibliothèque en fonction des exigences de votre projet, puis suivez ses conventions documentées.
Mes clés JSON doivent-elles être la chaîne anglaise elle-même ou un identifiant sémantique ?
Les identifiants sémantiques (comme auth.login.submit_button) sont préférables pour la plupart des applications. Utiliser la chaîne anglaise comme clé (style Gettext : t('Submit')) fonctionne pour les petits projets mais crée des problèmes à grande échelle : vous ne pouvez pas avoir deux boutons "Envoyer" différents avec un contexte différent dans le même namespace, et changer le texte anglais nécessite la mise à jour de toutes les références de clé dans le code.
Comment gérer les traductions manquantes au moment de l'exécution sans casser l'UI ?
Chaque bibliothèque i18n majeure se replie sur une locale par défaut configurée quand une clé est manquante. Configurez votre bibliothèque pour utiliser le fichier de locale anglais comme repli, ce qui signifie qu'une traduction française manquante affichera la chaîne anglaise plutôt que le nom de la clé. Journalisez les clés manquantes en développement (la plupart des bibliothèques prennent en charge un callback missingKeyHandler) afin qu'elles soient visibles lors des tests.
Est-il sûr d'utiliser des commentaires dans les fichiers de traduction JSON ?
Le JSON standard ne prend pas en charge les commentaires. Certains outils prennent en charge JSON5 ou JSONC (JSON avec commentaires) comme extension, mais cela rompt la compatibilité avec les parsers JSON standard. Si vous avez besoin d'annoter des chaînes avec du contexte pour les traducteurs, utilisez un champ de description séparé au niveau de la clé (comme le fait chrome.i18n) ou maintenez un fichier de métadonnées séparé. Une approche plus simple : utilisez des noms de clé descriptifs qui communiquent le contexte sans nécessiter de commentaires en ligne.
Comment gérer les langues de droite à gauche (RTL) dans mes fichiers JSON ?
La structure JSON pour les langues RTL (arabe, hébreu, persan) est identique aux langues LTR — le format de fichier ne change pas. La prise en charge RTL est une préoccupation CSS et de mise en page, pas une préoccupation de fichier de traduction. Votre bibliothèque i18n fournit un moyen de détecter la direction du texte de la locale active (généralement via l'API Intl.Locale ou un objet de métadonnées de locale), et votre application applique dir="rtl" au document ou au composant en conséquence. Conservez le CSS spécifique à RTL dans vos feuilles de style, pas dans vos valeurs de traduction.
Conclusion
Les fichiers de traduction JSON ne suivent pas un seul standard universel — ils suivent les conventions de la bibliothèque qui les lit. Comprendre quel format attend votre bibliothèque et pourquoi elle a été conçue ainsi est plus utile que de chercher une approche "correcte".
Le conseil pratique est le suivant : utilisez du JSON imbriqué avec les conventions i18next si vous créez une application React, Vue ou Node.js et souhaitez le plus grand écosystème d'outils et d'exemples. Utilisez ICU MessageFormat dans vos valeurs si votre application doit gérer des pluriels complexes, des accords de genre ou un formatage riche dans de nombreuses locales et que vous souhaitez que les expressions soient aussi portables que possible. Utilisez des clés plates pour les petits projets ou les prototypes rapides où la surcharge cognitive importe plus que la structure organisationnelle.
L'organisation des fichiers, le nommage des clés et la validation CI sont aussi importants que le choix du format. Un fichier plat avec un nommage cohérent et des vérifications de complétude automatisées servira mieux une petite équipe qu'une structure soigneusement organisée en namespaces sans outillage ni application.
La dette de traduction s'accumule silencieusement — une clé manquante ici, une chaîne obsolète là — jusqu'à ce que les utilisateurs localisés rencontrent des chaînes d'UI cassées. Les équipes qui évitent ce résultat traitent les fichiers de traduction de la même manière que tout autre artefact de code : examinés dans les pull requests, validés en CI et organisés avec les futurs mainteneurs en tête.
Références
- i18next documentation: Plurals
- i18next documentation: Interpolation
- FormatJS: ICU Message Syntax
- react-intl documentation
- vue-i18n documentation
- Chrome Extensions: chrome.i18n API
- XLIFF 2.0 specification (OASIS)
- Unicode CLDR Plural Rules
- i18next-conv: Conversion CLI
- eslint-plugin-i18n-json
- i18n Ally VS Code extension
- ICU Message Format reference (Unicode)
Dernière mise à jour : mars 2026