ConfigurationFormats

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

Cette page a été traduite automatiquement, elle peut donc contenir des erreurs ou sonner un peu bizarrement. La version anglaise est la référence. Lire l'original en anglais.

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

formatPourPlaceholdersPlurielsICU
i18next-jsoni18next{{name}} et références d'imbrication $t(...)suffixe de pluriel CLDR sur la clénon
vue-i18n-jsonvue-i18n{name}, {0}pipe dans la valeurnon
next-intl-jsonnext-intlnoms d'arguments et de balises ICUplural ou selectordinal ICUoui
ngx-translate-jsonngx-translate{{name}}aucunnon

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-json et yaml, 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 avec MIXED_STRUCTURE, puisqu'un tel fichier est ambigu plutôt que devinable.

La barrière anti-fabrication à accolade simple

Disponible à partir de 0.9.0

Ceci nécessite verbatra 0.9.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

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.ts

Chaque 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'id de sa trans-unit, avec repli sur resname. 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é un id stable. Deux unités qui se résolvent vers la même clé (typiquement un id dupliqué) font échouer la lecture avec INVALID_STRUCTURE plutô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 avec INVALID_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 colonne Context d'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_STRUCTURE au 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.description est 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 colonne Context d'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, comme java.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 \uXXXX sont 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 \uXXXX sû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 \r ou 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

Ceci nécessite verbatra 0.10.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

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. genstrings de 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 avec INVALID_STRUCTURE plutô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 colonne Context d'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, \t et 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 .strings qui 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 .stringsdict associé. Localizable.strings forme une paire avec Localizable.stringsdict dans 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 seul files.pattern par 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> que i18next-json utilise déjà, par exemple photo_count_one et photo_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 de one et other, 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 %d dans "%d photos", sont extraits et protégés de la même façon que dans les valeurs .strings. Un .stringsdict malformé (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 .stringsdict qui n'existe pas encore est créée de la même façon qu'une destination .strings, répertoire .lproj inclus, 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, .lproj inclus. files.pattern avec {locale}.lproj/Localizable.strings adresse 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}.lproj manquant tout comme elle crée n'importe quel autre répertoire de destination manquant.

Xcode String Catalogs (.xcstrings)

Disponible à partir de 0.10.0

Ceci nécessite verbatra 0.10.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

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.pattern a 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.xcstrings adresse un unique fichier Localizable.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 projet apple-xcstrings exécute ces opérations une par une même si --concurrency est 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 localizations explicite pour la sourceLanguage dé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 sous variations.plural d'une locale devient sa propre entrée traduisible, avec le même suffixe <clé>_<catégorie> qu'utilisent i18next-json et le support .stringsdict du format .strings d'Apple, par exemple %lld photos_one et %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$@, %lld et le littéral échappé %% sont extraits et protégés pendant la traduction de la même façon que les valeurs .strings d'Apple ; un modificateur de longueur comme le ll de %lld est de la décoration et ne fait pas partie de l'identité du jeton, donc %lld et %d sont le même placeholder.
  • shouldTranslate: false est 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, la version de premier niveau du catalogue et sa sourceLanguage survivent toutes intactes. Une valeur que verbatra vient de traduire reçoit stringUnit.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 à .strings ou .properties, verbatra ne crée pas de nouveau catalogue .xcstrings : crée-le d'abord dans Xcode, puis fais pointer files.pattern vers lui.
  • Les entrées malformées sont précises. Une AdapterError structuré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 champ stringUnit ni variations.plural, ou une catégorie de pluriel hors de l'ensemble CLDR.

Android strings.xml

Disponible à partir de 0.10.0

Ceci nécessite verbatra 0.10.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

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 exemple count[one] et count[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. Chaque name de 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/%d sont 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 section CDATA) 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$s et 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 propre String.format de 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.xml existant 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épertoire res/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 : --prune n'a aucune conscience de la quantité plurielle. La détection des clés orphelines et --prune de verbatra compare les clés à l'ensemble propre des clés de la source, sans cas particulier pour les groupes key[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 --prune ne peut pas distinguer d'une clé réellement supprimée, et peut les effacer. Désactivé par défaut ; une exécution normale de verbatra translate sans --prune n'est pas concernée.
  • Les entrées mal formées sont précises. Un XML mal formé déclenche un AdapterError structuré 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

Ceci nécessite verbatra 0.10.0 ou plus récent. Les versions antérieures ne l'ont pas, alors vérifie ta version installée avec verbatra --version et mets à jour si elle est plus ancienne.

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. Un msgctxt placé avant une entrée se combine avec son msgid en une seule clé, si bien que deux entrées partageant un msgid sous 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 .po ré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. Chaque msgstr[n] devient sa propre entrée, avec la clé key[n] (n l'index décimal brut), par exemple one item[0] et one item[1]. Ce n'est délibérément pas la convention de suffixe <key>_<category> qu'utilisent les formats JSON et le .stringsdict d'Apple : traduire un index gettext en catégorie CLDR nécessiterait d'évaluer l'expression C Plural-Forms propre au fichier, ce que verbatra ne fait pas. L'en-tête Plural-Forms est conservé mot pour mot comme texte intact ; verbatra n'en lit que l'entier nplurals=N, pour vérifier que chaque index msgstr[n] est dans les bornes. Un fichier avec des entrées plurielles et sans en-tête Plural-Forms est rejeté, comme l'exige msgfmt --check lui-même.
  • Les entrées fuzzy sont lues, pas ignorées. Le msgstr existant d'une entrée #, fuzzy est lu comme la valeur actuelle de cette entrée, comme toute autre entrée traduite ; verbatra ne traite pas fuzzy comme 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 colonne Contexte d'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 bloc msgid "" portant Content-Type, Plural-Forms et des métadonnées similaires) n'est jamais touchée par une écriture.
  • Les modèles .pot se lisent sans accroc. Un modèle source .pot, dont les entrées portent un msgstr vide, 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 .po qui 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ête Plural-Forms dimensionné à 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)s faç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 AdapterError structurée nomme le msgid en cause et la ligne physique, par exemple une chaîne entre guillemets non terminée, une séquence d'échappement inconnue, un index msgstr[n] non contigu, ou une entrée plurielle sans en-tête Plural-Forms, plutôt qu'un échec d'analyse générique.
  • Limitation : --prune n'a aucune conscience de l'index pluriel. La détection des clés orphelines et --prune de verbatra compare les clés à l'ensemble propre des clés de la source, sans cas particulier pour les groupes key[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 --prune ne peut pas distinguer d'une clé réellement supprimée, et peut les effacer. Désactivé par défaut ; une exécution normale de verbatra translate sans --prune n'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 translate ajoute à 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.

Edit on GitHub