Formats
Les huit formats pris en charge, comment chacun lit et écrit ses fichiers, et la garantie d'ordre des clés du document.
Page traduite automatiquement
verbatra travaille sur tes fichiers de locale via un adaptateur de format. Chaque adaptateur lit un fichier vers une forme neutre au format, sur laquelle tournent la comparaison, le hachage et les contrôles d'intégrité, puis le réécrit dans la forme d'origine du fichier. Tu choisis le format avec le champ format de ta configuration. Huit sont pris en charge : quatre variantes JSON, plus XLIFF, YAML, ARB et les properties Java/Spring.
Les quatre formats JSON
format | Pour | Placeholders | Pluriels | ICU |
|---|---|---|---|---|
i18next-json | i18next | {{name}} et références d'imbrication $t(...) | suffixe de pluriel CLDR sur la clé | non |
vue-i18n-json | vue-i18n | {name}, {0} | pipe dans la valeur | non |
next-intl-json | next-intl | noms d'arguments et de balises ICU | plural ou selectordinal ICU | oui |
ngx-translate-json | ngx-translate | {{name}} | aucun | non |
Les quatre lisent des objets JSON imbriqués dont les feuilles sont des chaînes. Leurs différences tiennent à la syntaxe de message :
- i18next utilise l'interpolation
{{double-brace}}et décide du pluriel d'après le suffixe CLDR sur la clé (_zero,_one,_two,_few,_many,_other). Il extrait et protège en plus les références d'imbrication$t()(qui insèrent le contenu d'une autre clé dans la valeur), par exemple$t(common.foo)et$t(common.foo, { options }), comme des placeholders, donc une traduction qui en perd ou en altère une échoue au contrôle d'intégrité. Deux limitations : les parenthèses imbriquées à l'intérieur des options de$t()ne sont pas prises en charge, et seul le préfixe par défaut$t(est reconnu. - vue-i18n utilise des jetons à simple accolade
{name}et{0}et décide du pluriel d'après un pipe dans la valeur. - next-intl : les valeurs sont du ICU MessageFormat : les placeholders sont les noms d'arguments ICU et de balises rich-text, le pluriel suit un argument plural ou selectordinal ICU, et le corps ICU traverse le pipeline tel quel. Une valeur qui échoue à s'analyser comme ICU est rapportée comme invalide et sautée, jamais levée en erreur.
- ngx-translate partage l'interpolation
{{double-brace}}d'i18next mais n'a ni imbrication$t(), ni pluriel intégré, ni ICU. Ses fichiers peuvent être plats (clés à points) ou imbriqués, et verbatra préserve à l'écriture le style que le fichier utilise ; un nouveau fichier cible est écrit imbriqué. Fait unique, un fichier qui mélange clés à points plates et objets imbriqués échoue à la lecture avecMIXED_STRUCTURE, puisqu'un tel fichier est ambigu plutôt que devinable.
XLIFF
Le format xliff couvre les fichiers .xlf et .xliff, XLIFF 1.2 (file/body/trans-unit) et 2.0 (file/unit/segment). Contrairement aux formats en arbre, un document XLIFF est une liste plate de trans-units.
- Clés. Chaque entrée est indexée par l'
idde sa trans-unit, avec repli surresname. Une unité sans l'un ni l'autre se replie sur une clé positionnelle, qui se décale quand des unités antérieures sont ajoutées ou supprimées, donc donne à chaque unité unidstable. Deux unités qui se résolvent vers la même clé (typiquement uniddupliqué) font échouer la lecture avecINVALID_STRUCTUREplutôt que d'en garder une en silence. - Valeurs. La valeur vient de
<target>quand il est présent, sinon de<source>. - Les écritures mettent à jour les cibles en place. verbatra écrit chaque valeur dans son
<target>et laisse<source>, les attributs et les éléments<note>intacts, donc le document fait l'aller-retour. Parce qu'une carte plate clé/valeur ne peut pas reconstruire un document XLIFF, le fichier de destination doit déjà exister : verbatra met à jour les cibles dans un fichier cible pré-amorcé (le flux de travail XLIFF standard) et n'en crée pas un manquant ; une destination absente échoue avecINVALID_STRUCTURE. - Balisage en ligne. Les éléments de placeholder en ligne (
x,g,bx,ex,ph,it,mrk) et l'interpolation à simple accolade{name}sont extraits comme placeholders et protégés à travers la traduction. À l'écriture, seuls ces éléments de la liste d'autorisation (avec leurs propres attributs minimaux, non exécutables) survivent comme balisage vivant dans<target>; tout le reste dans une valeur traduite, y compris un élément inattendu ou un désaccord d'espace de noms, est écrit comme du texte brut à la place. - Les notes comme contexte. Le
<note>d'une trans-unit (en 2.0, le<notes><note>de l'unité, partagé par chaque segment de l'unité) est lu comme du contexte développeur : il atteint le fournisseur comme contexte de désambiguïsation et apparaît dans la colonneContextd'un classeur exporté. Il est en lecture seule et n'est jamais réécrit.
YAML
Le format yaml couvre les fichiers .yml et .yaml : un arbre imbriqué en syntaxe YAML, la même forme qu'un fichier JSON imbriqué, géré par le même pipeline d'arbre. Il suppose une interpolation {{double-brace}} compatible i18next et ne détecte que par extension.
- Les commentaires YAML ne survivent pas à une écriture, de la même façon que JSON n'a pas de notion de commentaire.
- Les clés scalaires qui ne sont pas des chaînes gardent leur forme de chaîne (
1:se lit comme"1",true:comme"true"). - Une clé composite (une map ou une séquence utilisée comme clé de mapping) n'a pas de forme de chaîne fidèle, donc la lecture échoue avec
INVALID_STRUCTUREau lieu de la réduire en texte en silence. - Une syntaxe malformée est rapportée comme
INVALID_YAML, et l'expansion des ancres et alias est bornée, donc un document hostile ne peut pas faire exploser l'analyse.
ARB
Le format arb couvre les fichiers .arb de Flutter : du JSON avec un objet plat de clés de message accompagné de métadonnées préfixées par @ (métadonnées par message @key et globales préfixées @@ comme @@locale).
- Les métadonnées sont préservées, jamais traduites. Les clés préfixées
@sont retirées avant la traduction et refusionnées à l'écriture à leur position dans le document. Un fichier de destination qui existe mais est corrompu fait échouer l'écriture plutôt que d'effacer ses métadonnées en silence. - Les messages sont de l'ICU. Les placeholders, la gestion du pluriel et la validation ICU fonctionnent exactement comme pour
next-intl-json. - Les descriptions deviennent du contexte. Chaque
@key.descriptionest lue comme du contexte développeur pour ce message : elle atteint le fournisseur comme contexte de désambiguïsation (jamais comme du texte à traduire) et apparaît dans la colonneContextd'un classeur exporté. Elle est en lecture seule et n'est jamais réécrite.
Properties
Le format properties couvre les fichiers .properties de Java et Spring, détectés par l'extension .properties : une liste plate de lignes clé/valeur. Les clés sont conservées telles quelles comme clés plates, jamais découpées en arbre.
- Séparateurs et commentaires. Une clé est séparée de sa valeur par
=,:ou une espace, les espaces autour du séparateur étant ignorées, commejava.util.Properties. Une ligne dont le premier caractère non vide est#ou!est un commentaire. - Continuations et échappements. Une ligne qui se termine par une barre oblique inverse se poursuit sur la suivante. Les échappements standard (
\t,\n,\r,\f,\\, un séparateur ou un caractère de commentaire échappé) et\uXXXXsont décodés à la lecture. L'entrée est lue en UTF-8 ; à l'écriture, chaque caractère non-ASCII est émis comme un échappement\uXXXXsûr en ASCII, pour que le fichier se charge encore avec un ancien lecteur ISO-8859-1. - L'ordre, les commentaires et les lignes vides sont préservés. Une écriture relit la destination et conserve son ordre de clés, ses commentaires et ses lignes vides : chaque ligne de clé existante est réécrite sur place avec sa nouvelle valeur, et une clé que le fichier n'a pas encore est ajoutée dans l'ordre de la source. Une clé en double garde sa première position et prend la dernière valeur, comme
Properties.load. - Les placeholders sont du MessageFormat. Les valeurs sont lues comme du
java.text.MessageFormat, donc{0}, la forme typée{0,number}, la forme stylée{0,number,integer}et les arguments nommés comme{count}sont extraits et protégés pendant la traduction. Les arguments de sous-message (plural,select,selectordinal,choice) sont reconnus, donc traduire le texte de la branche reste une correspondance, mais supprimer ou renommer un argument non. - Limite : les guillemets simples ne sont pas interprétés. L'échappement par guillemet simple de MessageFormat n'est pas honoré, donc un littéral entre guillemets comme
'{0}'est toujours lu comme un placeholder. C'est volontaire, pour qu'une apostrophe ordinaire dans le texte traduit n'avale jamais un placeholder qui la suit.
Ordre des clés du document
Les écritures préservent l'ordre des clés de ton document. La famille JSON, YAML et ARB font l'aller-retour des clés exactement dans l'ordre du document :
- Une clé de type entier comme
"2","10"ou"404"garde sa position au lieu d'être remontée en tête et retriée, donc un fichier indexé par ids numériques, codes de statut HTTP ou années reste dans son propre ordre. - Une clé qu'une exécution de
translateajoute à un fichier cible s'ajoute après les clés existantes de la cible, en suivant l'ordre du document source, plutôt que d'être insérée alphabétiquement. - Les blocs de métadonnées ARB font aussi l'aller-retour à leur position dans le document.
XLIFF n'est pas concerné : il met à jour les éléments <target> existants en place, donc l'ordre du document n'a jamais été reconstruit.
Clés à points et collisions
Pour i18next-json, vue-i18n-json et next-intl-json, une feuille littérale à points (une clé comme "foo.bar" utilisée comme feuille unique) fait l'aller-retour sans perte : verbatra la lit et la réécrit avec sa forme sur disque préservée, sans la réimbriquer en foo puis bar. Les vrais chemins imbriqués restent imbriqués.
Le seul cas qui échoue par conception est une vraie collision, où un fichier exprime le même chemin effectif à la fois comme feuille littérale à points et comme vrai chemin imbriqué (par exemple "foo.bar" à côté de "foo": { "bar": ... }). Cette lecture échoue avec INVALID_STRUCTURE plutôt que de deviner ou de corrompre des données.
ngx-translate-json traite une clé à points comme un chemin imbriqué plutôt que comme une feuille littérale, donc il n'y a pas d'ambiguïté points-contre-littéral à préserver, mais il reçoit la même protection contre les collisions : une clé à points dont le chemin entre en collision avec un vrai chemin imbriqué, y compris quand l'un est un ancêtre de l'autre, échoue avec INVALID_STRUCTURE au lieu d'écraser une valeur en silence.
Comment les fichiers sont lus et écrits
verbatra plafonne la taille d'entrée et la profondeur d'imbrication à la lecture, et résiste à un fichier qui change sous lui. Il écrit de façon atomique : il écrit vers un fichier temporaire, puis le renomme en place, donc une écriture interrompue ne laisse jamais un fichier de locale à moitié fini. Quand verbatra ne peut pas gérer un fichier, il lève une erreur structurée sans secret avec un code stable plutôt qu'une erreur brute : INVALID_JSON, INVALID_YAML ou INVALID_XML pour une syntaxe malformée, INVALID_STRUCTURE pour un fichier analysable mais de mauvaise forme, MAX_DEPTH_EXCEEDED et INPUT_TOO_LARGE pour les plafonds, et MIXED_STRUCTURE pour le cas des styles mélangés de ngx-translate.
Un fichier de locale en arbre (la famille JSON, YAML et ARB) peut porter une feuille qui n'est pas une chaîne, par exemple une valeur count: 5 ou enabled: true à côté des clés traduisibles. verbatra les accepte : une feuille peut être une chaîne, un nombre, un booléen ou null, et seule une feuille d'un autre type, comme un tableau, échoue avec INVALID_STRUCTURE. Une feuille qui n'est pas une chaîne est exclue de l'ensemble traduisible : elle n'est jamais traduite, hachée, comparée, ni contrôlée pour les placeholders ou l'ICU. Exclusion n'est pas préservation : si verbatra réécrit plus tard ce même fichier de locale, l'écriture est reconstruite à partir des chaînes qu'il gère, donc une telle feuille présente à la lecture n'est pas reportée dans la sortie. Si une telle valeur doit survivre à une réécriture, garde-la hors des fichiers dans lesquels verbatra écrit. Les valeurs de trans-unit XLIFF et les valeurs .properties sont toujours des chaînes, donc cela ne s'applique pas là.
Pourquoi le format compte
Le format dit à verbatra deux choses dont il a besoin pour une exécution sûre. D'abord, la syntaxe des placeholders, pour que le contrôle d'intégrité des placeholders sache quoi comparer avant et après la traduction. Ensuite, pour les formats ICU, quelles valeurs valider, pour qu'une clé source à l'ICU invalide soit sautée plutôt qu'envoyée dans un état cassé. Le mauvais format compare les mauvais jetons, donc fais-le correspondre à ta bibliothèque i18n : i18next-json pour i18next, vue-i18n-json pour vue-i18n, next-intl-json pour next-intl, ngx-translate-json pour ngx-translate, xliff pour les fichiers XLIFF, yaml pour l'i18n basée sur YAML, arb pour Flutter, et properties pour les fichiers .properties Java ou Spring.