Traduire une application sans casser la mise en page
Pluriels, genres, formats de date et chaînes intraduisibles : ce qui casse une interface traduite, et comment l'éviter.
Traduire une interface avec un modèle donne un résultat correct en quelques minutes. C'est ce qui rend l'exercice trompeur : le texte est bon, et pourtant l'application est cassée. Un bouton déborde de son cadre, une phrase à trous donne « 1 résultats », une date affiche 03/04 alors qu'on est le 4 mars, et le nom du produit s'est fait traduire en cours de route.
Aucun de ces problèmes ne vient de la qualité de la traduction. Ils viennent de ce qu'une interface n'est pas un texte : c'est un assemblage de fragments, dans des contenants de taille fixe, avec des variables au milieu et des règles de grammaire qui changent d'une langue à l'autre.
Ce guide traite ces mécanismes-là. La traduction en elle-même est la partie facile.
Avant de commencer
- Une application dont les chaînes sont déjà extraites dans des fichiers, pas écrites en dur
- La liste des langues cibles, décidée avant de commencer
- Quelqu'un capable de relire chaque langue, même rapidement
1Séparer ce qui se traduit de ce qui ne se traduit pas
Avant toute traduction, il faut poser une liste de ce qui doit rester intact. C'est le travail que personne ne fait et qui produit le plus de dégâts.
Ne se traduisent pas :
- Les noms propres. Nom du produit, nom de l'entreprise, noms de fonctionnalités déposées.
- Les identifiants techniques. Clés, codes d'erreur, noms de champs d'API, valeurs d'énumération.
- Les termes que tes utilisateurs emploient en anglais. Dans beaucoup de métiers, « commit », « dashboard » ou « workflow » se disent tels quels. Les traduire donne un texte plus juste et moins compréhensible.
- Les unités et les formats de code. Un exemple de requête, un extrait de configuration.
Écris cette liste dans un fichier, et donne-la au traducteur, humain ou modèle, en même temps que le texte.
Traduis ces chaines de [LANGUE] vers [LANGUE]. Ne traduis jamais les termes
de cette liste : [LISTE]. Conserve a l'identique toutes les variables entre
accolades, y compris leur nom. Ne modifie pas la ponctuation des chaines qui
n'en contiennent pas. Si une chaine est ambigue hors contexte, ne la traduis
pas et signale-la.
Les variables sont ce qui casse en premier
Une variable renommée, traduite ou déplacée hors de son emplacement produit une erreur d'exécution ou un texte tronqué. Vérifie mécaniquement, après chaque traduction, que chaque chaîne cible contient exactement les mêmes variables que la source. C'est un test, pas une relecture.
2Ne jamais assembler une phrase par morceaux
C'est la règle la plus importante et la plus violée. Concaténer « Vous avez » + nombre + « nouveaux messages » fonctionne en français et casse partout ailleurs, parce que l'ordre des mots change, parce que l'accord change, et parce que le traducteur ne voit jamais la phrase entière.
La bonne unité de traduction est la phrase complète, avec ses variables à l'intérieur. Le format ICU MessageFormat, employé par la plupart des bibliothèques d'internationalisation, sert exactement à ça.
{num_guests, plural,
=0 {{host} does not give a party.}
=1 {{host} invites {guest} to her party.}
other {{host} invites {guest} and # other people to her party.}}
Deux éléments à retenir : le # est remplacé par la valeur numérique, et la
branche other est obligatoire, elle sert de repli.
Le même format gère les variantes de genre avec select, dont les mots-clés sont
fixés :
{gender_of_host, select,
female {{host} gives a party.}
male {{host} gives a party.}
other {{host} gives a party.}}
La documentation d'ICU recommande, quand on imbrique les deux, de placer le
select à l'extérieur et le plural à l'intérieur.
3Comprendre les catégories de pluriel
Une langue n'a pas forcément deux formes de pluriel, et surtout, elles ne se
répartissent pas comme en français. Le système CLDR définit six catégories :
zero, one, two, few, many et other. Toutes les langues ne les
utilisent pas.
Intl.PluralRules permet de vérifier n'importe quelle langue en une ligne, sans
supposer :
const regles = new Intl.PluralRules("fr-FR");
console.log(regles.select(0)); // "one"
console.log(regles.select(1)); // "one"
console.log(regles.select(2)); // "other"
Le premier résultat surprend souvent, et il est correct : en français, la règle
CLDR range 0 et 1 dans la même catégorie one, alors que l'anglais range 0 dans
other. Une chaîne écrite avec deux branches « singulier / pluriel » en pensant
anglais produit donc « 0 résultat » ou « 0 résultats » selon la langue, et l'une
des deux est fausse.
En russe et en polonais, 0 tombe dans many, et la catégorie few existe. Un
fichier de traduction qui ne prévoit que deux branches y est structurellement
faux.
Le constructeur accepte aussi une option type, valant cardinal par défaut ou
ordinal pour les rangs.
4Formater les dates, les nombres et les monnaies avec Intl
Un format de date écrit à la main est un bug qui attend son heure. 03/04/2026
se lit 3 avril en France et 4 mars aux États-Unis, et rien dans la chaîne ne dit
laquelle des deux lectures est la bonne.
Intl.DateTimeFormat résout le problème en déléguant la mise en forme à la
locale. Les options dateStyle et timeStyle acceptent full, long, medium
et short, et timeZone prend un identifiant IANA.
const date = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));
new Intl.DateTimeFormat("en-US").format(date); // "12/20/2020"
new Intl.DateTimeFormat(["ban", "id"]).format(date); // "20/12/2020"
Le même raisonnement vaut pour les nombres : séparateur de milliers, séparateur décimal, position du symbole monétaire et espace insécable avant l'euro sont des règles de locale, pas des choix de mise en forme.
Le fuseau horaire est une donnée, pas un détail d'affichage
Stocke les instants en UTC et convertis à l'affichage. Une date stockée dans le fuseau du serveur devient fausse dès que quelqu'un consulte l'application depuis ailleurs, et le bug ne se manifeste que sur certains horaires.
5Vérifier que la mise en page tient
La traduction change la longueur du texte, souvent beaucoup. L'allemand allonge les libellés courts, le japonais les raccourcit, l'arabe et l'hébreu inversent le sens de lecture.
Quatre vérifications concrètes, à faire sur l'interface réelle et pas sur le fichier de traduction :
- Les libellés de boutons et d'onglets. Ce sont les contenants les plus contraints. Un bouton dont le texte double de longueur casse une barre d'outils.
- Les colonnes de tableau à largeur fixe. Elles tronquent en silence.
- Les mots longs sans espace. Ils débordent au lieu de passer à la ligne, sauf si la mise en page le prévoit.
- Le sens de lecture. Pour l'arabe ou l'hébreu, ce n'est pas seulement le texte qui s'inverse : les icônes directionnelles, l'ordre des colonnes et la position des menus aussi.
Ouvre [URL] en [LANGUE]. Liste les elements dont le texte deborde de son
conteneur ou est tronque, avec leur selecteur et le texte concerne.
Compare aussi la longueur de chaque libelle de bouton avec sa version
[LANGUE SOURCE] et signale ceux qui augmentent de plus de 50 %.
6Faire relire par quelqu'un qui parle la langue
Un modèle produit une traduction fluide et parfois complètement à côté du registre. Il tutoie une interface bancaire, il emploie un terme correct mais jamais utilisé dans le métier, il traduit un mot conservé en anglais par l'usage local.
Ces erreurs sont invisibles pour qui ne parle pas la langue, et elles ne se détectent par aucun test. Une relecture rapide par un locuteur, même non professionnel, en attrape la grande majorité. Donne-lui les chaînes dans leur contexte, avec une capture de l'écran concerné, pas une liste hors sol.
Quelques prompts pour aller plus loin
| Objectif | Prompt à adapter |
|---|---|
| Audit de concaténation | Cherche dans le projet les endroits ou une phrase affichee est construite par concatenation de fragments traduits. Liste-les avec le fichier et la ligne. |
| Cohérence des variables | Compare le fichier source et le fichier [LANGUE] : liste les cles dont les variables entre accolades different, manquent ou ont ete renommees. |
| Pluriels | Pour chaque chaine contenant un nombre, verifie que toutes les categories de pluriel requises par [LANGUE] sont presentes. Liste les cles incompletes. |
| Glossaire | A partir de ces chaines, propose un glossaire des termes qui ne doivent pas etre traduits, avec une justification par terme. |
| Formats codés en dur | Trouve les dates, heures et nombres formates a la main dans le code, et propose l'equivalent avec Intl. |
| Débordements | Ouvre [URL] en [LANGUE] et liste les elements dont le texte est tronque ou deborde, avec leur selecteur. |
| Registre | Relis ces traductions en [LANGUE] et signale les ecarts de registre : tutoiement, formulations trop familieres ou trop administratives. |
Tu as d’autres ressources comme ça ?
Ce que tu viens de lire est entièrement gratuit. Une nouvelle ressource part chaque semaine dans la newsletter : guides, modèles à copier et liens triés, sans compte à créer.
Me contacter
Une question, un projet, une envie de collaborer ? Écris-moi.
Cette page est en accès libre, n’hésite pas à la partager.