Table des matières
Les traductions manquantes sont le type de bug qui passe à travers chaque étape de votre pipeline. Les tests unitaires passent car ils ne vérifient pas les fichiers de traduction. Les tests d'intégration passent car ils s'exécutent dans la langue par défaut. Le QA passe car les tests manuels couvrent rarement les douze langues. Et puis un utilisateur au Brésil voit checkout.confirm_button là où devrait apparaître le libellé d'un bouton, et vous recevez un rapport de bug qui donne l'impression que votre équipe est négligente.
Le problème n'est pas que les équipes oublient les traductions. C'est qu'il n'existe aucune vérification automatisée pour détecter les lacunes de traduction, de la même façon qu'un vérificateur de types détecte les erreurs de types ou qu'un linter détecte les problèmes de style de code. Votre code dispose d'ESLint, Prettier, TypeScript et d'un pipeline CI complet. Vos traductions ont... un fichier JSON que quelqu'un a, espérons-le, pensé à mettre à jour.
Cet article explique comment mettre en place des contrôles de santé i18n automatisés qui détectent les traductions manquantes, les incohérences de variables, les clés orphelines et les chaînes codées en dur avant qu'elles n'atteignent la production.
Que vérifie réellement un contrôle de santé i18n ?
Un contrôle de santé i18n complet évalue quatre dimensions de votre configuration de traduction :
1. Couverture : toutes les clés sont-elles traduites ?
La couverture est la vérification la plus directe et la plus impactante. Pour chaque clé de traduction utilisée dans votre code source, existe-t-il une traduction dans chaque langue cible ?
Références dans le code source : 1 247 clés Anglais (source) : 1 247/1 247 (100 %) Espagnol : 1 235/1 247 (99 %) Français : 1 198/1 247 (96 %) Japonais : 1 150/1 247 (92 %) Coréen : 1 089/1 247 (87 %)
Un contrôle de couverture détecte le scénario le plus courant : un développeur ajoute une nouvelle fonctionnalité, écrit les chaînes en anglais, et passe à la tâche suivante. Les clés sont ajoutées au fichier JSON anglais mais ne sont jamais envoyées pour traduction. Sans contrôle de couverture, la lacune reste invisible jusqu'à ce qu'un utilisateur la rencontre.
Les contrôles de couverture détectent également les incohérences de namespace. Si votre code référence t('checkout.confirm') mais que le namespace checkout n'existe pas pour le coréen, il s'agit d'une lacune de couverture qui affichera une clé brute aux utilisateurs coréens.
2. Qualité : les traductions sont-elles structurellement correctes ?
La couverture vous indique seulement si une traduction existe. La qualité vous indique si elle fonctionnera correctement au moment de l'exécution.
Le contrôle de qualité le plus critique est la validation des variables. Si votre chaîne anglaise est :
"You have {count} items in your cart, {name}."
Alors chaque traduction de cette chaîne doit contenir exactement {count} et {name}. Un traducteur français qui écrit {nombre} au lieu de {count} crée un bug à l'exécution — le moteur d'interpolation ne trouvera pas de valeur pour {nombre} et affichera soit la variable brute, soit une erreur.
D'autres contrôles de qualité incluent :
- Valeurs vides : clés présentes dans un fichier de langue mais avec des chaînes vides. Elles indiquent généralement une création programmatique de clés sans traduction réelle.
- Chaînes identiques à la source : traductions identiques caractère par caractère à la langue source. Certaines chaînes (noms de marque, URLs) sont légitimement identiques, mais un nombre élevé signifie généralement du contenu non traduit.
- Longueur excessive : traductions significativement plus longues que la source, ce qui peut déborder les conteneurs de l'interface. Les traductions allemandes sont notoirement 30 à 40 % plus longues que l'anglais.
3. Structure : les fichiers de traduction sont-ils propres ?
Les contrôles de structure évaluent l'organisation et l'hygiène de vos fichiers de traduction :
- Clés orphelines : clés présentes dans les fichiers de traduction mais jamais référencées dans le code source. Elles s'accumulent lorsque des fonctionnalités sont supprimées mais que les fichiers de traduction ne sont pas nettoyés. Elles gaspillent l'effort des traducteurs et créent de la confusion.
- Clés dupliquées : la même clé définie deux fois dans un seul fichier. JSON n'émet pas d'erreur sur les clés dupliquées — il utilise silencieusement la dernière, ce qui peut entraîner des comportements déroutants.
- Incohérence de nommage : si 90 % de vos clés utilisent le
snake_casemais que quelques-unes utilisent lecamelCase, l'incohérence rend les clés plus difficiles à trouver et à maintenir.
4. Code : les chaînes sont-elles correctement internationalisées ?
L'analyse de code utilise l'analyse AST pour trouver les chaînes codées en dur dans vos fichiers source qui devraient être encapsulées dans des fonctions de traduction.
// Signalé : chaîne codée en dur visible par l'utilisateur
<h1>Welcome to our app</h1>
// Non signalé : correctement internationalisé
<h1>{t('home.welcome_title')}</h1>
// Non signalé : non visible par l'utilisateur (classe CSS, attribut data)
<div className="container" data-testid="home">
Ce contrôle détecte la dette i18n à la source. Les nouveaux développeurs qui ne sont pas familiers avec votre configuration i18n écrivent des chaînes codées en dur. Sans vérification automatisée, ces chaînes persistent jusqu'à ce que quelqu'un les remarque lors d'un audit de traduction.
Le score de santé : réduire la complexité à un chiffre
Les contrôles individuels produisent des rapports détaillés, mais pour l'intégration CI et le suivi des tendances, vous avez besoin d'un seul chiffre : le score de santé.
Un score de santé bien conçu pondère les catégories selon leur impact utilisateur :
| Catégorie | Poids | Justification |
|---|---|---|
| Couverture | 40 % | Les traductions manquantes affectent directement les utilisateurs |
| Qualité | 30 % | Les bugs de variables causent des erreurs à l'exécution |
| Structure | 20 % | Les clés orphelines gaspillent l'effort sans casser l'UX |
| Code | 10 % | Les chaînes codées en dur sont une dette, pas une rupture immédiate |
Un projet avec un score de 87/100 pourrait se décomposer ainsi :
Global : 87/100 RÉUSSI Couverture 92/100 ████████████████████ 3 clés manquantes Qualité 85/100 █████████████████░░░ 2 incohérences de variables Structure 78/100 ███████████████░░░░░ 12 clés orphelines Code 90/100 ██████████████████░░ 4 chaînes codées en dur
Le seuil de réussite/échec est configurable. Un seuil de 80 est pratique pour la plupart des équipes — assez strict pour détecter les vrais problèmes, assez souple pour que les avertissements mineurs ne bloquent pas les déploiements.
Mise en place des contrôles de santé i18n dans CI/CD
La vraie valeur des contrôles de santé vient de leur exécution automatique sur chaque pull request. Voici comment configurer un workflow GitHub Actions :
# .github/workflows/i18n-doctor.yml
name: i18n Health Check
on:
pull_request:
paths:
- "locales/**"
- "src/**"
- "messages/**"
jobs:
doctor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install
- name: Run i18n Doctor
run: bunx @better-i18n/cli doctor --ci --threshold 80
env:
BETTER_I18N_API_KEY: ${{ secrets.BETTER_I18N_API_KEY }}
Ce que fait le flag --ci
Le flag --ci modifie le comportement de Doctor pour les environnements CI :
- Code de sortie : retourne le code de sortie 1 si l'analyse échoue, ce qui fait échouer le job GitHub Actions
- Annotations GitHub : produit les problèmes au format d'annotation GitHub Actions, afin qu'ils apparaissent comme des commentaires en ligne sur le diff de la PR
- Résumé : produit un résumé structuré pour la sortie du contrôle GitHub Actions
- Non interactif : supprime les barres de progression et la sortie colorée
Les filtres de chemin sont importants
Le filtre paths dans la configuration du workflow est important pour les performances. Sans lui, le contrôle de santé s'exécute sur chaque PR, y compris les PR qui ne modifient que la documentation ou le code backend sans impact sur les traductions. Filtrez vers vos répertoires de fichiers de traduction et vos répertoires de code source.
Rapporter les résultats à la plateforme
Ajoutez le flag --report pour soumettre les résultats à votre plateforme de gestion des traductions :
- name: Run i18n Doctor
run: bunx @better-i18n/cli doctor --ci --report --threshold 80
env:
BETTER_I18N_API_KEY: ${{ secrets.BETTER_I18N_API_KEY }}
Les rapports incluent le SHA du commit, le nom de la branche, le nombre de fichiers et le nombre de clés. Au fil du temps, cela construit un historique de votre santé i18n que vous pouvez utiliser pour suivre les améliorations, détecter les régressions et définir des objectifs d'équipe.
Workflows générés automatiquement
Si la configuration manuelle de GitHub Actions semble être une friction inutile, certaines plateformes de traduction (dont Better i18n) peuvent créer le fichier de workflow pour vous. La plateforme utilise l'API GitHub pour ouvrir une PR sur votre dépôt avec un fichier de workflow préconfiguré. Vous le relisez, le fusionnez, et le contrôle de santé est actif.
Que se passe-t-il lorsqu'un contrôle échoue ?
Un contrôle de santé en échec doit fournir des informations exploitables, pas seulement une croix rouge. Voici à quoi ressemble un échec utile :
Clés de traduction manquantes
Erreur : 12 clés manquantes dans les langues cibles
checkout.confirm_order
Manquantes dans : fr, de, ja, ko
Ajoutées dans le commit : abc1234 (il y a 2 jours)
Fichier : src/pages/Checkout.tsx:45
checkout.payment_method
Manquantes dans : fr, de, ja, ko
Ajoutées dans le commit : abc1234 (il y a 2 jours)
Fichier : src/pages/Checkout.tsx:52
Le développeur voit exactement quelles clés manquent, dans quelles langues, quand elles ont été ajoutées et où elles sont utilisées. La correction est claire : demander des traductions pour ces clés avant de fusionner.
Incohérences de variables
Erreur : Incohérence de variable dans notifications.new_messages (de)
Source : "You have {count} new messages from {sender}"
Cible : "Sie haben {anzahl} neue Nachrichten von {sender}"
Manquant : {count}
Superflu : {anzahl}
Le développeur ou le traducteur voit l'incohérence exacte et peut corriger la traduction allemande pour utiliser {count} au lieu de {anzahl}.
Chaînes codées en dur
Avertissement : Chaîne codée en dur dans JSX (src/components/Header.tsx:23)
<h1>Welcome back!</h1>
Suggestion : <h1>{t('header.welcome_back')}</h1>
Il s'agit d'un avertissement, pas d'une erreur — il ne bloquera pas la PR par défaut. Mais il apparaît dans le rapport et contribue au score d'analyse de code.
Impact concret : avant et après
Avant : le processus manuel
- Le développeur ajoute une nouvelle fonctionnalité avec 30 nouvelles clés
- Le développeur ajoute les traductions en anglais
- Le développeur ouvre une PR, qui est relue et fusionnée
- Deux semaines plus tard, le QA teste la fonctionnalité en français — trouve 30 clés brutes
- Le QA dépose un rapport de bug
- Le développeur crée un ticket pour les traductions
- Le traducteur fournit les traductions françaises
- Le développeur commit le fichier de traduction, ouvre une nouvelle PR
- Répéter pour l'allemand, le japonais, le coréen, etc.
Délai entre la fusion du code et la fonctionnalité entièrement traduite : 3 à 6 semaines.
Après : contrôles de santé automatisés
- Le développeur ajoute une nouvelle fonctionnalité avec 30 nouvelles clés
- Le développeur ajoute les traductions en anglais
- Le développeur ouvre une PR
- Le CI exécute i18n Doctor — échoue avec « 30 clés manquantes dans fr, de, ja, ko »
- Le développeur demande des traductions via la plateforme
- Les traductions arrivent (générées par IA en quelques minutes, relues par un humain en quelques heures)
- Le développeur ajoute les traductions à la PR
- Le CI s'exécute à nouveau — réussit
- La PR est fusionnée avec toutes les langues complètes
Délai entre la fusion du code et la fonctionnalité entièrement traduite : le jour même.
La différence n'est pas seulement une question de vitesse — il s'agit de détecter le problème au bon endroit. Un contrôle CI détecte les traductions manquantes dans la même PR où les clés ont été ajoutées, quand le développeur a encore tout le contexte de la fonctionnalité. Un rapport de bug trois semaines plus tard oblige le développeur à changer de contexte pour revenir sur une fonctionnalité qu'il a déjà mise de côté.
Suivre la santé dans le temps
Un seul score de santé est utile pour le contrôle de passage/échec. Un historique des scores de santé est utile pour comprendre les tendances.
Lorsque vous soumettez des rapports Doctor à un tableau de bord de plateforme, vous pouvez suivre :
- Trajectoire du score : votre santé i18n s'améliore-t-elle, est-elle stable ou se dégrade-t-elle ?
- Tendances par catégorie : peut-être que votre couverture est excellente mais que les clés orphelines s'accumulent. La décomposition par catégorie montre où concentrer les efforts de nettoyage.
- Comparaison par branche : les branches de fonctionnalités ont souvent des scores plus bas (nouvelles clés sans traductions). La branche principale devrait maintenir un score constamment élevé.
- Comparaison inter-projets : pour les organisations avec plusieurs produits, comparez la santé i18n entre les projets pour identifier ceux qui nécessitent de l'attention.
Définir des objectifs d'équipe
Les scores de santé permettent de définir des objectifs i18n mesurables :
- « Maintenir un score de santé de 90+ sur la branche principale » — un standard de qualité
- « Réduire les clés orphelines de 200 à 50 d'ici la fin du trimestre » — une initiative de nettoyage
- « Zéro incohérence de variables » — un objectif zéro défaut pour le contrôle le plus critique
Objections courantes et réponses
« Nous n'avons que deux langues, nous n'en avons pas besoin. » Deux langues suffisent pour que les lacunes de couverture et les incohérences de variables causent des bugs visibles par les utilisateurs. Le contrôle de santé est léger — il ajoute des secondes à votre pipeline CI, pas des minutes.
« Nos traducteurs gèrent la qualité. » Les traducteurs assurent la qualité linguistique. Les contrôles de santé assurent la qualité technique — exactitude des variables, couverture des clés, structure des fichiers. Ce sont des préoccupations différentes. Un traducteur ne peut pas savoir si une clé est référencée dans votre code source.
« Nous ajouterons ça plus tard quand nous aurons plus de langues. » La dette i18n s'accumule. Les clés orphelines, les chaînes codées en dur et le nommage incohérent que vous accumulez avec deux langues deviennent beaucoup plus difficiles à corriger lorsque vous ajoutez une troisième, quatrième et cinquième langue. Commencer les contrôles de santé tôt est moins coûteux que de les mettre en place après coup.
« Notre CI est déjà lent. »
Une analyse Doctor d'un projet de 10 000 clés avec 8 langues prend moins de 10 secondes. Utilisez --skip-code pour supprimer l'analyse AST et réduire ça à moins de 3 secondes. Le filtre de chemin dans la configuration GitHub Actions garantit que le contrôle ne s'exécute que sur les PR qui touchent des fichiers liés aux traductions.
Démarrer
Si vous utilisez Better i18n, la commande Doctor est intégrée au CLI :
# Installer le CLI bun add -g @better-i18n/cli # Exécuter votre premier contrôle de santé bi18n doctor # Exécuter en mode CI avec rapport bi18n doctor --ci --report --threshold 80
Si vous n'utilisez pas Better i18n, les principes de cet article s'appliquent à toute configuration de traduction. Vous pouvez créer des contrôles similaires avec des scripts personnalisés qui :
- Analysent votre code source pour les références aux clés de traduction
- Comparent les clés référencées avec vos fichiers de traduction
- Valident la cohérence des variables
- Produisent les résultats au format d'annotation de votre système CI
L'important n'est pas l'outil que vous utilisez. C'est que les traductions manquantes cessent d'être une surprise découverte par les utilisateurs et deviennent un contrôle CI découvert par les développeurs.
Les traductions manquantes sont des bugs évitables. Commencez à les détecter dans le CI — configurez Better i18n Doctor et exécutez votre premier contrôle de santé aujourd'hui.