Formats
Les douze 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. Douze sont pris en charge : quatre variantes JSON, plus XLIFF, YAML, ARB, les properties Java/Spring, le .strings d'Apple, les Xcode String Catalogs (.xcstrings), le strings.xml d'Android et le .po/.pot gettext.
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. - Texte à accolade simple dans les formats à double accolade. Dans
i18next-json,ngx-translate-jsonetyaml, un jeton de la forme{name}est du texte littéral et non de l'interpolation : il n'est donc pas extrait comme placeholder, et une traduction peut le supprimer ou le reformuler. Voir la barrière anti-fabrication pour le seul sens dans lequel il reste contrôlé. - 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.
La barrière anti-fabrication à accolade simple
Disponible à partir de 0.9.0
Sous i18next-json, ngx-translate-json et yaml, un jeton de la forme {name} qui apparaît dans une traduction et n'a jamais figuré dans la source est rejeté comme une fabrication. Cela couvre aussi bien un placeholder inventé de toutes pièces qu'un placeholder altéré en un nom que la source n'a jamais porté. La barrière n'agit que dans ce sens : verbatra n'a aucun réglage pour les interpolation.prefix et interpolation.suffix propres à i18next, donc si tu es passé à des délimiteurs à accolade simple, une traduction qui perd silencieusement l'un de tes placeholders n'est pas détectée.
Dispositions avec espaces de noms
Répartir les chaînes sur plusieurs fichiers d'espace de noms par locale est courant dans les projets i18next, avec common.json, auth.json et les autres côte à côte dans un répertoire de locale. Une configuration verbatra adresse exactement un fichier par locale : files.pattern est un chemin littéral avec {locale} substitué, il n'est jamais développé comme un glob, et il n'existe pas de jeton d'espace de noms. Un motif comme public/locales/{locale}/*.json est cherché comme un fichier nommé littéralement *.json et échoue avec SOURCE_UNREADABLE.
Une disposition à un seul espace de noms fonctionne telle qu'elle est configurée :
files: {
pattern: "public/locales/{locale}/common.json",
},Une configuration par espace de noms
Pour un projet à plusieurs espaces de noms, écris une configuration par espace de noms et lance verbatra une fois par configuration. N'importe quel nom de fichier convient, puisque --config charge un chemin explicite d'après son extension :
verbatra translate --config verbatra.common.config.ts
verbatra translate --config verbatra.auth.config.tsChaque exécution traite son propre espace de noms : les clés absentes d'un fichier cible sont traduites comme d'habitude.
Seul l'espace de noms exécuté en dernier conserve la détection des changements
Toutes les configurations d'un même répertoire de travail partagent un seul verbatra.lock.json, et chaque exécution de translate remplace la référence enregistrée de cette locale par les clés qu'elle vient de traiter. Après la deuxième exécution, le premier espace de noms n'a plus de référence, donc modifier une de ses chaînes source est rapporté comme synchronisé par check et diff et n'est pas retraduit. Changer l'ordre des exécutions n'aide pas ; celle qui passe en dernier efface l'autre. Pour retraduire une chaîne modifiée dans ce montage, supprime cette clé du fichier cible (ou supprime le fichier cible entier) pour qu'elle compte comme manquante plutôt que modifiée.
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, y compris la protection contre les jetons à accolade simple fabriqués décrite plus haut, 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 fins de ligne suivent la destination. Un fichier contenant le moindre CRLF est réécrit entièrement en CRLF, un fichier uniquement en CR est réécrit en CR, et tout le reste, y compris un fichier qui n'existe pas encore, en LF. Un fichier mixte converge donc vers un seul style au lieu d'être conservé ligne par ligne, et un
\rou un\nà l'intérieur d'une valeur reste échappé au lieu d'être émis comme un saut de ligne. Cela garde un changement de traduction sur deux clés à un diff de deux lignes dans les dépôts en CRLF où ces fichiers vivent souvent. - 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.
Apple .strings
Disponible à partir de 0.10.0
Le format apple-strings couvre les fichiers .strings d'Apple pour iOS et macOS : une séquence plate d'instructions "clé" = "valeur";, détectée par l'extension .strings. Les règles de pluriel vivent dans le fichier .stringsdict associé (même répertoire, même nom de base, extension .stringsdict), que verbatra lit et écrit automatiquement avec le fichier .strings, sous le même id de format apple-strings.
- L'encodage est exclusivement UTF-8.
genstringsde Xcode peut produire de l'UTF-16 avec une marque d'ordre des octets. verbatra détecte une marque d'ordre des octets UTF-16, little ou big endian, et la rejette avecINVALID_STRUCTUREplutôt que de la parser en clés corrompues et entrelacées de NUL. Réenregistre le fichier en UTF-8 (Xcode le fait nativement) avant d'exécuter verbatra dessus. - Commentaires et échappements. Un commentaire de bloc
/* ... */placé juste avant une entrée est lu comme sa description : 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. Un commentaire de ligne//est conservé à l'écriture mais ne porte aucune description. Les échappements\",\\,\n,\tet l'échappement unicode\Uà quatre chiffres hexadécimaux sont décodés à la lecture ; à l'écriture, un guillemet, une barre oblique inverse, un saut de ligne et une tabulation sont échappés, et tout autre caractère, y compris le texte non-ASCII, est écrit en UTF-8 brut. - Destination manquante. Contrairement à XLIFF, une destination
.stringsqui n'existe pas encore est synthétisée à partir des entrées plutôt que de faire échouer l'écriture, comme le format properties. - L'ordre, les commentaires et les lignes vides sont préservés. Une écriture relit la destination et la reconstruit à partir de cette structure : chaque clé existante est réécrite sur place avec sa nouvelle valeur, une clé que la destination n'a pas encore est ajoutée dans l'ordre de la source, et une clé retirée des entrées est supprimée de la destination avec son propre commentaire précédent.
- Les placeholders sont de style printf.
%@,%d,%1$@et le littéral échappé%%sont extraits et protégés pendant la traduction, les drapeaux, la largeur, la précision et les modificateurs de longueur (%05.2f,%ld) étant traités comme de la décoration et ne faisant pas partie de l'identité du jeton. Une réorganisation positionnelle comme%1$@ %2$@devenant%2$@ %1$@est acceptée, puisque c'est précisément le rôle des spécificateurs positionnels. Un%isolé suivi de texte ordinaire, comme dans"50% off", n'extrait rien. - Les pluriels vivent dans le
.stringsdictassocié.Localizable.stringsforme une paire avecLocalizable.stringsdictdans le même répertoire ; verbatra le découvre automatiquement et fusionne ses catégories de pluriel dans la même ressource de locale, donc traduire cible toujours un seulfiles.patternpar locale. Chaque catégorie CLDR présente dans une entrée (zero,one,two,few,many,other) devient sa propre entrée traduisible, avec le même suffixe<clé>_<catégorie>quei18next-jsonutilise déjà, par exemplephoto_count_oneetphoto_count_other. Une locale qui ne fournit qu'une partie des catégories, le cas courant puisque la plupart des langues n'ont besoin que deoneetother, fait l'aller-retour avec exactement celles-ci : aucune n'est inventée pour une cible et aucune n'est perdue depuis la source. Les placeholders printf à l'intérieur de la chaîne de format d'une catégorie, comme%ddans"%d photos", sont extraits et protégés de la même façon que dans les valeurs.strings. Un.stringsdictmalformé (XML invalide, une substitution%#@variable@manquante, ou une catégorie de pluriel non prise en charge) déclenche une erreur structurée qui nomme le fichier et la clé. Une destination.stringsdictqui n'existe pas encore est créée de la même façon qu'une destination.strings, répertoire.lprojinclus, et sa structure non traduisible (la clé de format, le nom de la variable de substitution et le type de valeur) est préservée lors d'une réécriture. - Un fichier par locale,
.lprojinclus.files.patternavec{locale}.lproj/Localizable.stringsadresse directement la disposition de bundle par locale d'Apple :{locale}est une substitution littérale de jeton, elle n'a donc besoin d'aucun style de locale particulier, et une écriture crée un répertoire{locale}.lprojmanquant tout comme elle crée n'importe quel autre répertoire de destination manquant.
Xcode String Catalogs (.xcstrings)
Disponible à partir de 0.10.0
Le format apple-xcstrings couvre les fichiers String Catalog de Xcode, .xcstrings, introduits dans Xcode 15 pour remplacer la paire .strings/.stringsdict dans les nouveaux projets : un unique document JSON qui contient les strings, les pluriels et l'état de traduction de toutes les locales ensemble, détecté par l'extension .xcstrings. C'est structurellement différent de tous les autres formats pris en charge par verbatra, qui utilisent chacun un fichier par locale : un catalogue apple-xcstrings est un fichier pour toutes les locales à la fois.
- Un catalogue partagé, pas un fichier par locale.
files.patterna toujours besoin du jeton{locale}, mais pour ce format il se résout vers le même chemin quelle que soit la locale substituée, par exemple{locale}Localizable.xcstringsadresse un unique fichierLocalizable.xcstrings. La locale source et chaque locale cible configurée partagent donc un seul fichier physique. - Les écritures dans un catalogue partagé se sérialisent. Comme l'écriture de chaque locale touche le même fichier, verbatra sérialise entre elles toutes les opérations pouvant l'écrire :
translate, une édition dans Studio, la retraduction d'une seule clé et l'import du classeur. En pratique, un projetapple-xcstringsexécute ces opérations une par une même si--concurrencyest réglé au-dessus de 1 ; tout autre format continue d'exécuter ses appels au fournisseur en parallèle comme configuré. - La clé est le string source. Une clé du catalogue sans entrée
localizationsexplicite pour lasourceLanguagedéclarée par le document lui-même retombe sur le texte de la clé, conformément à la propre convention de Xcode. Une clé sans entrée pour toute autre locale est simplement traitée comme pas encore traduite pour cette locale, exactement comme une clé manquante dans le fichier cible de tout autre format. - Les pluriels vivent dans
variations.plural. Chaque catégorie CLDR (zero,one,two,few,many,other) présente sousvariations.plurald'une locale devient sa propre entrée traduisible, avec le même suffixe<clé>_<catégorie>qu'utilisenti18next-jsonet le support.stringsdictdu format.stringsd'Apple, par exemple%lld photos_oneet%lld photos_other. Une locale qui ne fournit qu'une partie des catégories fait l'aller-retour avec exactement celles-ci : aucune n'est inventée, aucune n'est perdue. - Les placeholders sont de style printf.
%@,%d,%1$@,%lldet le littéral échappé%%sont extraits et protégés pendant la traduction de la même façon que les valeurs.stringsd'Apple ; un modificateur de longueur comme lellde%lldest de la décoration et ne fait pas partie de l'identité du jeton, donc%lldet%dsont le même placeholder. shouldTranslate: falseest respecté. Une clé marquée ainsi n'est jamais envoyée à un fournisseur et n'est jamais réécrite modifiée.- Les écritures corrigent le document, elles ne le reconstruisent pas. Une écriture relit le catalogue actuel et ne met à jour que les localizations qu'elle touche, donc
extractionState, toute autre locale, les entrées non traduisibles, les catégories de pluriel, laversionde premier niveau du catalogue et sasourceLanguagesurvivent toutes intactes. Une valeur que verbatra vient de traduire reçoitstringUnit.state: "translated"; la localization existante d'une valeur inchangée, état inclus, est laissée identique octet pour octet plutôt que réécrite. - Le catalogue de destination doit déjà exister. Contrairement à
.stringsou.properties, verbatra ne crée pas de nouveau catalogue.xcstrings: crée-le d'abord dans Xcode, puis fais pointerfiles.patternvers lui. - Les entrées malformées sont précises. Une
AdapterErrorstructurée nomme le fichier et, quand le problème se situe dans une entrée, la clé et la locale aussi, par exemple une entrée sans champstringUnitnivariations.plural, ou une catégorie de pluriel hors de l'ensemble CLDR.
Android strings.xml
Disponible à partir de 0.10.0
Le format android-xml couvre les fichiers de ressources Android, res/values/strings.xml pour la locale source et res/values-<qualificatif>/strings.xml pour chaque cible, détecté par l'extension .xml. Règle files.localeStyle sur android (voir le fichier de configuration) pour que {locale} dans files.pattern se résolve vers le bon répertoire de qualificatif de ressource plutôt que vers une étiquette BCP-47 littérale.
<string>et<plurals>. Un<string name="key">value</string>est une entrée. Un<plurals name="key">devient une entrée par<item quantity="...">(zero,one,two,few,many,other), avec la clékey[quantity], par exemplecount[one]etcount[other]. Une locale qui ne fournit qu'une partie des catégories aboutit exactement à celles-ci : aucune n'est inventée, aucune n'est supprimée. Chaquenamede ressource est validé contre la grammaire des identifiants Android (une lettre ou un tiret bas, puis des lettres, des chiffres ou des tirets bas) avant de devenir une clé, si bien qu'un nom ne peut pas forger une collision en forme de[quantity]avec un véritable espace de clés de pluriel.translatable="false"est respecté. Un<string>ou<plurals>portant cet attribut n'est jamais envoyé à un fournisseur et reste inchangé sur le disque.formatted="false"est traduit normalement. L'attribut indique seulement aux outils de build propres à Android de ne pas valider les arguments printf ; il ne change rien à ce que fait verbatra. Les marqueurs de style%s/%dsont toujours extraits et protégés pendant la traduction.<string-array>et le balisage en ligne sont laissés tels quels dans cette version. Un<string-array>et un<string>dont le contenu n'est pas du texte brut (un élément en ligne comme<b>,<xliff:g>, ou une sectionCDATA) sont préservés exactement tels quels et n'entrent jamais dans l'ensemble traduisible de verbatra. La traduction au niveau des éléments pour ceux-ci est un ajout futur possible, pas pris en charge aujourd'hui.- L'échappement est décodé à la lecture, ré-encodé à l'écriture.
\',\",\n,\t, ainsi qu'un\@ou\?en tête, sont décodés vers leurs caractères littéraux à la lecture, et ces mêmes caractères (plus un@ou?en tête non échappé) sont ré-échappés à l'écriture ; les entités XML propres&,<et>sont gérées indépendamment par la couche XML sous-jacente, si bien qu'une valeur traduite contenant l'un de ces caractères est réécrite en toute sécurité sans que tu aies à l'échapper toi-même. - Les marqueurs sont de style printf.
%s,%d,%1$set le littéral échappé%%sont extraits et protégés pendant la traduction. Un%isolé suivi de texte ordinaire, comme dans"50% off", n'extrait rien : l'extracteur ne traite pas un espace comme un flag de conversion valide, contrairement au propreString.formatde Java, si bien qu'un signe pourcentage dans une prose ordinaire n'est jamais pris pour un marqueur. - Les écritures mettent à jour les cibles sur place ; une destination absente est synthétisée. Un
res/values-<qualificatif>/strings.xmlexistant est corrigé : une clé traduite est mise à jour, une clé supprimée de la source est effacée, et le répertoire parent est créé s'il n'existe pas encore. Une destination qui n'existe pas encore est créée de toutes pièces, répertoireres/values-<qualificatif>/compris. - Limitation : une clé rétrogradée en lecture seule après traduction est supprimée, pas préservée. Si une clé était déjà traduite dans un fichier cible puis, dans le fichier source, acquiert
translatable="false"ou du balisage en ligne, l'exécution suivante ne peut pas distinguer ce cas d'une clé purement et simplement supprimée, et retire la traduction devenue obsolète du fichier cible. C'est un cas étroit (il ne concerne qu'une clé dont la classification source change après qu'elle a déjà été traduite) et récupérable via le contrôle de version ou une nouvelle exécution de traduction ; il n'affecte pas une clé qui conserve sa classification d'origine, y compris les clés nouvelles, modifiées et supprimées ordinaires. - Limitation :
--prunen'a aucune conscience de la quantité plurielle. La détection des clés orphelines et--prunede verbatra compare les clés à l'ensemble propre des clés de la source, sans cas particulier pour les groupeskey[quantity]. Une locale cible ayant besoin de plus de quantités plurielles que ce que déclare la source (par exemple une langue avec davantage de distinctions grammaticales de nombre) possède des quantités présentes uniquement dans la cible, qu'une exécution avec--prunene peut pas distinguer d'une clé réellement supprimée, et peut les effacer. Désactivé par défaut ; une exécution normale deverbatra translatesans--prunen'est pas concernée. - Les entrées mal formées sont précises. Un XML mal formé déclenche un
AdapterErrorstructuré qui nomme le problème ; un document dont l'élément racine n'est pas<resources>, un nom de ressource qui échoue à la grammaire des identifiants, un élément<plurals>avec une quantité hors de l'ensemble CLDR, ou deux éléments qui se résolvent vers la même clé sont tous signalés nommément plutôt que comme un échec d'analyse générique. Une déclaration DTD ou ENTITY est rejetée d'emblée.
gettext .po/.pot
Disponible à partir de 0.10.0
Le format gettext-po couvre les catalogues .po et .pot de GNU gettext, détectés par l'une ou l'autre extension : une séquence plate d'entrées msgid/msgstr, indexée par leur msgid, jamais éclatée en arbre.
- Désambiguïsation par
msgctxt. Unmsgctxtplacé avant une entrée se combine avec sonmsgiden une seule clé, si bien que deux entrées partageant unmsgidsous des contextes différents n'entrent jamais en collision. La clé composite utilise un point de code à usage privé réservé (U+E000) comme séparateur interne, un caractère qu'aucun fichier.poréel ne contient légitimement ; une chaîne source qui le contiendrait est rejetée avec une erreur structurée plutôt que de corrompre la clé silencieusement. - Les pluriels sont
msgid_plural/msgstr[n], indexés par index, pas par catégorie CLDR. Chaquemsgstr[n]devient sa propre entrée, avec la clékey[n](nl'index décimal brut), par exempleone item[0]etone item[1]. Ce n'est délibérément pas la convention de suffixe<key>_<category>qu'utilisent les formats JSON et le.stringsdictd'Apple : traduire un index gettext en catégorie CLDR nécessiterait d'évaluer l'expression CPlural-Formspropre au fichier, ce que verbatra ne fait pas. L'en-têtePlural-Formsest conservé mot pour mot comme texte intact ; verbatra n'en lit que l'entiernplurals=N, pour vérifier que chaque indexmsgstr[n]est dans les bornes. Un fichier avec des entrées plurielles et sans en-têtePlural-Formsest rejeté, comme l'exigemsgfmt --checklui-même. - Les entrées
fuzzysont lues, pas ignorées. Lemsgstrexistant d'une entrée#, fuzzyest lu comme la valeur actuelle de cette entrée, comme toute autre entrée traduite ; verbatra ne traite pasfuzzycomme signifiant manquant. Le marqueur est conservé mot pour mot à chaque écriture et n'est jamais ajouté ni retiré automatiquement. - Les commentaires et l'en-tête sont conservés intacts. Les commentaires développeur
#.deviennent la description de l'entrée : ils parviennent au fournisseur comme contexte de désambiguïsation et apparaissent dans la colonneContexted'un classeur exporté. Les références#:et les autres marqueurs#,sont conservés à l'écriture mais ne sont pas interprétés autrement. Un bloc obsolète#~est conservé comme texte inerte et ne devient jamais une entrée traduisible. L'entrée d'en-tête (le blocmsgid ""portantContent-Type,Plural-Formset des métadonnées similaires) n'est jamais touchée par une écriture. - Les modèles
.potse lisent sans accroc. Un modèle source.pot, dont les entrées portent unmsgstrvide, se lit sans erreur ; la valeur de chaque entrée est simplement la chaîne vide jusqu'à sa traduction. - Destination manquante. Comme pour les formats properties et Apple
.strings, une destination.poqui n'existe pas encore est synthétisée à partir des entrées plutôt que de faire échouer l'écriture, en-tête minimal inclus. Un fichier synthétisé contenant des entrées plurielles reçoit un en-têtePlural-Formsdimensionné à l'index le plus élevé présent ; pour une ou deux formes, il s'agit de l'expression universelle standard, pour trois ou plus d'une valeur de repli sûre et dans les bornes plutôt que d'une règle linguistique devinée, potentiellement fausse ; amorce d'abord la destination à partir d'un vrai modèle de la langue cible si tu as besoin de la grammaire exacte. - Les paramètres sont au style printf, y compris la forme nommée à la Python.
%s,%d,%1$s, le%(name)sfaçon Python et le littéral échappé%%sont extraits et protégés pendant la traduction. - Les entrées mal formées sont précises. Une
AdapterErrorstructurée nomme lemsgiden cause et la ligne physique, par exemple une chaîne entre guillemets non terminée, une séquence d'échappement inconnue, un indexmsgstr[n]non contigu, ou une entrée plurielle sans en-têtePlural-Forms, plutôt qu'un échec d'analyse générique. - Limitation :
--prunen'a aucune conscience de l'index pluriel. La détection des clés orphelines et--prunede verbatra compare les clés à l'ensemble propre des clés de la source, sans cas particulier pour les groupeskey[n]. Une locale cible ayant besoin de plus de formes plurielles que ce que déclare la source (par exemple une langue avec davantage de distinctions grammaticales de nombre) possède des index présents uniquement dans la cible, qu'une exécution avec--prunene peut pas distinguer d'une clé réellement supprimée, et peut les effacer. Désactivé par défaut ; une exécution normale deverbatra translatesans--prunen'est pas concernée.
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, properties pour les fichiers .properties Java ou Spring, apple-strings pour les fichiers .strings d'Apple, apple-xcstrings pour les fichiers .xcstrings de Xcode String Catalog, android-xml pour le strings.xml d'Android, et gettext-po pour les catalogues .po/.pot gettext.
Fournisseurs
Les six fournisseurs de traduction, leurs options et clés d'API, et le comportement qu'ils partagent tous.
Estimer le coût
Dimensionne une exécution de traduction avant de dépenser : compte les clés avec un dry run, convertis-les en requêtes et en tokens, puis chiffre-les avec les tarifs de ton fournisseur.