Formate
Die zwölf unterstützten Formate, wie jedes seine Dateien liest und schreibt, und die Garantie der Dokumentreihenfolge der Keys.
Maschinell übersetzte Seite
verbatra arbeitet über einen Format-Adapter auf deinen Locale-Dateien. Jeder Adapter liest eine Datei in eine formatneutrale Form, auf der Vergleich, Hashing und Integritätsprüfungen laufen, und schreibt sie dann in der ursprünglichen Form der Datei zurück. Du wählst das Format über das format-Feld in deiner Konfiguration. Zwölf werden unterstützt: vier JSON-Varianten plus XLIFF, YAML, ARB, Java/Spring-Properties, Apple-.strings, Xcode String Catalogs (.xcstrings), Android strings.xml und gettext .po/.pot.
Die vier JSON-Formate
format | Für | Platzhalter | Plurale | ICU |
|---|---|---|---|---|
i18next-json | i18next | {{name}} und $t(...)-Verschachtelungsreferenzen | CLDR-Plural-Suffix am Key | nein |
vue-i18n-json | vue-i18n | {name}, {0} | Pipe im Wert | nein |
next-intl-json | next-intl | ICU-Argument- und Tag-Namen | ICU plural oder selectordinal | ja |
ngx-translate-json | ngx-translate | {{name}} | keine | nein |
Alle vier lesen verschachtelte JSON-Objekte mit String-Blättern. Die Unterschiede liegen in der Nachrichtensyntax:
- i18next nutzt
{{double-brace}}-Interpolation und leitet den Plural aus dem CLDR-Suffix am Key ab (_zero,_one,_two,_few,_many,_other). Zusätzlich extrahiert und schützt es$t()-Verschachtelungsreferenzen (die den Inhalt eines anderen Keys in den Wert einfügen), zum Beispiel$t(common.foo)und$t(common.foo, { options }), als Platzhalter, sodass eine Übersetzung, die eine davon verwirft oder verändert, die Integritätsprüfung nicht besteht. Zwei Einschränkungen: Verschachtelte Klammern innerhalb der$t()-Optionen werden nicht unterstützt, und nur das Standard-Präfix$t(wird erkannt. - Einzelklammer-Text in den Doppelklammer-Formaten. In
i18next-json,ngx-translate-jsonundyamlist ein Token der Form{name}Literaltext und keine Interpolation. Es wird deshalb nicht als Platzhalter extrahiert, und eine Übersetzung darf es fallen lassen oder umformulieren. Siehe die Erfindungs-Schranke für die eine Richtung, in der trotzdem geprüft wird. - vue-i18n nutzt Einfach-Klammer-Tokens
{name}und{0}und leitet den Plural aus einer Pipe im Wert ab. - next-intl-Werte sind ICU MessageFormat: Die Platzhalter sind die ICU-Argument- und Rich-Text-Tag-Namen, der Plural folgt einem ICU-plural- oder selectordinal-Argument, und der ICU-Körper wird wortgetreu durch die Pipeline getragen. Ein Wert, der nicht als ICU parst, wird als ungültig gemeldet und übersprungen, nie geworfen.
- ngx-translate teilt i18nexts
{{double-brace}}-Interpolation, hat aber kein$t()-Nesting, keinen eingebauten Plural und kein ICU. Seine Dateien dürfen flach (gepunktete Keys) oder verschachtelt sein, und verbatra erhält beim Schreiben den Stil, den die Datei verwendet; eine neue Zieldatei wird verschachtelt geschrieben. Einzigartig: Eine Datei, die flache gepunktete Keys mit verschachtelten Objekten mischt, lässt das Lesen mitMIXED_STRUCTUREfehlschlagen, weil so eine Datei mehrdeutig statt erratbar ist.
Die Erfindungs-Schranke für Einzelklammern
Verfügbar ab 0.9.0
Unter i18next-json, ngx-translate-json und yaml wird ein {name}-förmiges Token, das in einer Übersetzung auftaucht und in der Quelle nie vorkam, als Erfindung abgelehnt. Das deckt sowohl einen frei erfundenen Platzhalter ab als auch einen, der in einen Namen verändert wurde, den die Quelle nie hatte. Die Schranke wirkt nur in diese Richtung: verbatra hat keine Einstellung für i18nexts eigene interpolation.prefix und interpolation.suffix. Wenn du also auf Einzelklammer-Delimiter umgestellt hast, wird eine Übersetzung, die einen deiner Platzhalter stillschweigend fallen lässt, nicht erkannt.
Namespace-Layouts
Strings über mehrere Namespace-Dateien pro Locale zu verteilen, ist in i18next-Projekten üblich: common.json, auth.json und so weiter liegen nebeneinander in einem Locale-Verzeichnis. Eine verbatra-Konfiguration adressiert genau eine Datei pro Locale: files.pattern ist ein wörtlicher Pfad mit eingesetztem {locale}, er wird nie als Glob expandiert, und es gibt kein Namespace-Token. Ein Muster wie public/locales/{locale}/*.json wird als Datei mit dem wörtlichen Namen *.json gesucht und schlägt mit SOURCE_UNREADABLE fehl.
Ein Layout mit einem einzigen Namespace funktioniert wie konfiguriert:
files: {
pattern: "public/locales/{locale}/common.json",
},Eine Konfiguration pro Namespace
Schreibe für ein Projekt mit mehreren Namespaces eine Konfiguration pro Namespace und starte verbatra einmal pro Konfiguration. Jeder Dateiname funktioniert, da --config einen expliziten Pfad anhand seiner Endung lädt:
verbatra translate --config verbatra.common.config.ts
verbatra translate --config verbatra.auth.config.tsJeder Lauf behandelt seinen eigenen Namespace: Keys, die in einer Zieldatei fehlen, werden wie gewohnt übersetzt.
Nur der zuletzt gelaufene Namespace behält die Änderungserkennung
Alle Konfigurationen im selben Arbeitsverzeichnis teilen sich eine verbatra.lock.json, und jeder translate-Lauf ersetzt die aufgezeichnete Baseline dieser Locale durch die Keys, die er gerade verarbeitet hat. Nach dem zweiten Lauf hat der erste Namespace keine Baseline mehr, eine Änderung an einem seiner Quellstrings gilt für check und diff also als synchron und wird nicht neu übersetzt. Eine andere Reihenfolge der Läufe hilft nicht; wer zuletzt läuft, überschreibt den anderen. Um einen geänderten String in diesem Aufbau neu zu übersetzen, lösche diesen Key aus der Zieldatei (oder lösche die ganze Zieldatei), damit er als fehlend statt als geändert zählt.
XLIFF
Das xliff-Format deckt .xlf- und .xliff-Dateien ab, XLIFF 1.2 (file/body/trans-unit) und 2.0 (file/unit/segment). Anders als die Baum-Formate ist ein XLIFF-Dokument eine flache Liste von Trans-Units.
- Keys. Jeder Eintrag wird über die
idseiner Trans-Unit identifiziert, mitresnameals Rückfallebene. Eine Unit ohne beides fällt auf einen Positions-Key zurück, der sich verschiebt, wenn frühere Units hinzukommen oder wegfallen, gib also jeder Unit eine stabileid. Zwei Units, die zum selben Key auflösen (typischerweise eine doppelteid), lassen das Lesen mitINVALID_STRUCTUREfehlschlagen, statt still eine zu behalten. - Werte. Der Wert kommt aus
<target>, wenn vorhanden, sonst aus<source>. - Schreiben aktualisiert Targets an Ort und Stelle. verbatra schreibt jeden Wert in sein
<target>und lässt<source>, Attribute und<note>-Elemente unangetastet, damit das Dokument den Roundtrip übersteht. Weil eine flache Key/Wert-Zuordnung kein XLIFF-Dokument rekonstruieren kann, muss die Zieldatei bereits existieren: verbatra aktualisiert Targets in einer vorbereiteten Zieldatei (der Standard-XLIFF-Workflow) und legt keine fehlende an; ein fehlendes Ziel schlägt mitINVALID_STRUCTUREfehl. - Inline-Markup. Inline-Platzhalterelemente (
x,g,bx,ex,ph,it,mrk) und Einfach-Klammer-{name}-Interpolation werden als Platzhalter extrahiert und über die Übersetzung hinweg geschützt. Beim Schreiben überleben nur diese per Allowlist zugelassenen Elemente (mit ihren eigenen minimalen, nicht ausführbaren Attributen) als lebendiges Markup in<target>; alles andere in einem übersetzten Wert, einschließlich eines unerwarteten Elements oder eines Namespace-Konflikts, wird stattdessen als reiner Text geschrieben. - Notes als Kontext. Die
<note>einer Trans-Unit (in 2.0 die<notes><note>der Unit, geteilt von jedem Segment der Unit) wird als Entwicklerkontext gelesen: Der Inhalt erreicht den Provider als Kontext zur Begriffsklärung und erscheint in derContext-Spalte einer exportierten Arbeitsmappe. Er ist schreibgeschützt und wird nie zurückgeschrieben.
YAML
Das yaml-Format deckt .yml- und .yaml-Dateien ab: ein verschachtelter Baum in YAML-Syntax, dieselbe Form wie eine verschachtelte JSON-Datei, verarbeitet von derselben Baum-Pipeline. Es nimmt i18next-kompatible {{double-brace}}-Interpolation an, einschließlich des oben beschriebenen Schutzes gegen erfundene Einzelklammer-Token, und erkennt nur über die Dateiendung.
- YAML-Kommentare überstehen einen Schreibvorgang nicht, so wie JSON kein Kommentarkonzept hat.
- Skalare Nicht-String-Keys behalten ihre String-Form (
1:wird als"1"gelesen,true:als"true"). - Ein zusammengesetzter Key (eine Map oder Sequenz als Mapping-Key) hat keine treue String-Form, das Lesen schlägt also mit
INVALID_STRUCTUREfehl, statt ihn still zu Text zu verflachen. - Fehlerhafte Syntax wird als
INVALID_YAMLgemeldet, und die Anker-Alias-Expansion ist begrenzt, ein bösartiges Dokument kann das Parsen also nicht sprengen.
ARB
Das arb-Format deckt Flutters .arb-Dateien ab: JSON mit einem flachen Objekt aus Nachrichten-Keys neben @-präfixierten Metadaten (@key-Metadaten pro Nachricht und @@-präfixierte globale Einträge wie @@locale).
- Metadaten werden erhalten, nie übersetzt.
@-präfixierte Keys werden vor der Übersetzung entfernt und beim Schreiben an ihrer Dokumentposition wieder eingefügt. Eine Zieldatei, die existiert, aber beschädigt ist, lässt den Schreibvorgang fehlschlagen, statt ihre Metadaten still zu löschen. - Nachrichten sind ICU. Platzhalter, Plural-Behandlung und ICU-Validierung funktionieren genau wie bei
next-intl-json. - Beschreibungen werden Kontext. Jede
@key.descriptionwird als Entwicklerkontext für diese Nachricht gelesen: Die Beschreibung erreicht den Provider als Kontext zur Begriffsklärung (nie als zu übersetzender Text) und erscheint in derContext-Spalte einer exportierten Arbeitsmappe. Auch sie ist schreibgeschützt und wird nie zurückgeschrieben.
Properties
Das properties-Format deckt Javas und Springs .properties-Dateien ab, erkannt an der Endung .properties: eine flache Liste von Key/Wert-Zeilen. Keys bleiben als flache Keys wortgetreu erhalten und werden nie in einen Baum aufgeteilt.
- Trennzeichen und Kommentare. Ein Key wird von seinem Wert durch
=,:oder Whitespace getrennt, wobei Leerzeichen rund um das Trennzeichen ignoriert werden, wie beijava.util.Properties. Eine Zeile, deren erstes Nicht-Leerzeichen#oder!ist, ist ein Kommentar. - Fortsetzungen und Escapes. Eine Zeile, die auf einen Backslash endet, wird auf der nächsten fortgesetzt. Die Standard-Escapes (
\t,\n,\r,\f,\\, ein escaptes Trenn- oder Kommentarzeichen) und\uXXXXwerden beim Lesen dekodiert. Die Eingabe wird als UTF-8 gelesen; beim Schreiben wird jedes Nicht-ASCII-Zeichen als ASCII-sicheres\uXXXX-Escape ausgegeben, damit die Datei auch unter einem alten ISO-8859-1-Reader lädt. - Reihenfolge, Kommentare und Leerzeilen bleiben erhalten. Ein Schreibvorgang liest das Ziel erneut ein und behält dessen Key-Reihenfolge, Kommentare und Leerzeilen: Jede vorhandene Key-Zeile wird an Ort und Stelle mit ihrem neuen Wert neu geschrieben, und ein Key, den die Datei noch nicht hat, wird in Quellreihenfolge angehängt. Ein doppelter Key behält seine erste Position und nimmt den letzten Wert, wie
Properties.load. - Zeilenenden folgen dem Ziel. Eine Datei, die irgendwo CRLF enthält, wird komplett mit CRLF zurückgeschrieben, eine Datei nur mit CR mit CR, und alles andere, auch eine noch nicht existierende Datei, mit LF. Eine gemischte Datei läuft damit auf einen Stil zusammen, statt zeilenweise erhalten zu bleiben, und ein
\roder\ninnerhalb eines Werts wird weiterhin escapt statt als Zeilenumbruch ausgegeben. So bleibt eine Übersetzungsänderung an zwei Keys ein Diff über zwei Zeilen, auch in den CRLF-Repositories, in denen diese Dateien oft liegen. - Platzhalter sind MessageFormat. Werte werden als
java.text.MessageFormatgelesen, sodass{0}, die typisierte Form{0,number}, die stilisierte Form{0,number,integer}und benannte Argumente wie{count}extrahiert und über die Übersetzung hinweg geschützt werden. Unternachrichten-Argumente (plural,select,selectordinal,choice) werden erkannt, sodass das Übersetzen des Zweigtexts eine Übereinstimmung bleibt, das Entfernen oder Umbenennen eines Arguments jedoch nicht. - Einschränkung: Einfache Anführungszeichen werden nicht interpretiert. Die Single-Quote-Maskierung von MessageFormat wird nicht beachtet, sodass ein maskiertes Literal wie
'{0}'weiterhin als Platzhalter gelesen wird. Das ist Absicht, damit ein gewöhnlicher Apostroph im übersetzten Text nie einen folgenden Platzhalter verschluckt.
Apple .strings
Verfügbar ab 0.10.0
Das apple-strings-Format deckt Apples .strings-Dateien für iOS und macOS ab: eine flache Folge von "key" = "value";-Anweisungen, erkannt an der Endung .strings. Pluralregeln liegen in der begleitenden .stringsdict-Datei (gleiches Verzeichnis, gleicher Basisname, Endung .stringsdict), die verbatra automatisch zusammen mit der .strings-Datei liest und schreibt, unter derselben apple-strings-Format-ID.
- Kodierung ist ausschließlich UTF-8. Xcodes
genstringskann UTF-16 mit einem Byte-Order-Mark ausgeben. verbatra erkennt ein UTF-16-Byte-Order-Mark, little oder big endian, und weist es mitINVALID_STRUCTUREzurück, statt es in korrupte, NUL-durchsetzte Keys zu parsen. Speichere die Datei vor dem Lauf als UTF-8 (Xcode kann das nativ). - Kommentare und Escapes. Ein
/* ... */-Blockkommentar unmittelbar vor einem Eintrag wird als dessen Beschreibung gelesen: Er erreicht den Provider als Kontext zur Begriffsklärung und erscheint in derContext-Spalte einer exportierten Arbeitsmappe. Er ist nur lesbar und wird nie zurückgeschrieben. Ein//-Zeilenkommentar bleibt beim Schreiben erhalten, trägt aber keine Beschreibung. Die Escapes\",\\,\n,\tund das vierstellige Hex-Unicode-Escape\Uwerden beim Lesen dekodiert; beim Schreiben werden Anführungszeichen, Backslash, Zeilenumbruch und Tabulator escapt, und jedes andere Zeichen, auch Nicht-ASCII-Text, wird als rohes UTF-8 geschrieben. - Fehlendes Ziel. Anders als bei XLIFF wird ein noch nicht existierendes
.strings-Ziel aus den Einträgen synthetisiert, statt den Schreibvorgang scheitern zu lassen, wie beim Properties-Format. - Reihenfolge, Kommentare und Leerzeilen bleiben erhalten. Ein Schreibvorgang liest das Ziel erneut ein und baut es aus dieser Struktur wieder auf: Jeder vorhandene Key wird an Ort und Stelle mit seinem neuen Wert neu geschrieben, ein Key, den das Ziel noch nicht hat, wird in Quellreihenfolge angehängt, und ein aus den Einträgen entfernter Key wird zusammen mit seinem eigenen vorangehenden Kommentar aus dem Ziel entfernt.
- Platzhalter sind im printf-Stil.
%@,%d,%1$@und das escapte Literal%%werden extrahiert und über die Übersetzung hinweg geschützt, wobei Flags, Breite, Präzision und Längenmodifikatoren (%05.2f,%ld) als Dekoration gelten und nicht zur Identität des Tokens gehören. Ein positionelles Vertauschen wie%1$@ %2$@zu%2$@ %1$@wird akzeptiert, denn genau dafür gibt es positionelle Spezifizierer. Ein bloßes%, gefolgt von gewöhnlichem Text, wie in"50% off", extrahiert nichts. - Plurale liegen in der begleitenden
.stringsdict.Localizable.stringsbildet ein Paar mitLocalizable.stringsdictim selben Verzeichnis; verbatra findet sie automatisch und führt ihre Plural-Kategorien in derselben Locale-Ressource zusammen, sodass die Übersetzung weiterhin genau einfiles.patternpro Locale anspricht. Jede in einem Eintrag vorhandene CLDR-Kategorie (zero,one,two,few,many,other) wird zu einem eigenen übersetzbaren Eintrag, mit demselben<key>_<Kategorie>-Suffix, den auchi18next-jsonverwendet, zum Beispielphoto_count_oneundphoto_count_other. Eine Locale, die nur einen Teil der Kategorien liefert - der Regelfall, da die meisten Sprachen nuroneundotherbrauchen - rundet exakt mit diesen: Für ein Ziel wird keine erfunden, und aus der Quelle wird keine verworfen. Printf-Platzhalter innerhalb einer Kategorie-Formatzeichenkette, etwa%din"%d photos", werden genauso extrahiert und geschützt wie in.strings-Werten. Eine fehlerhafte.stringsdict(ungültiges XML, eine fehlende%#@variable@-Substitution oder eine nicht unterstützte Plural-Kategorie) wirft einen strukturierten Fehler, der Datei und Key benennt. Ein noch nicht existierendes.stringsdict-Ziel wird genauso angelegt wie ein.strings-Ziel,.lproj-Verzeichnis inklusive, und seine nicht übersetzbare Struktur (der Format-Key, der Substitutionsvariablenname und der Werttyp) bleibt bei einem erneuten Schreiben erhalten. - Eine Datei pro Locale,
.lprojinklusive.files.patternmit{locale}.lproj/Localizable.stringsadressiert Apples Bundle-Layout pro Locale direkt:{locale}ist eine wörtliche Token-Ersetzung, braucht also keinen eigenen Locale-Style, und ein Schreibvorgang legt ein fehlendes{locale}.lproj-Verzeichnis genauso an wie jedes andere fehlende Zielverzeichnis.
Xcode String Catalogs (.xcstrings)
Verfügbar ab 0.10.0
Das apple-xcstrings-Format deckt Xcodes String-Catalog-Dateien ab, .xcstrings, eingeführt in Xcode 15 als Ersatz für das Paar .strings/.stringsdict in neuen Projekten: ein einziges JSON-Dokument, das die Strings, Plurale und den Übersetzungsstatus aller Locales gemeinsam enthält, erkannt an der Endung .xcstrings. Das unterscheidet sich strukturell von jedem anderen von verbatra unterstützten Format, die alle eine Datei pro Locale verwenden: Ein apple-xcstrings-Katalog ist eine Datei für alle Locales zugleich.
- Ein gemeinsamer Katalog statt einer Datei pro Locale.
files.patternbraucht weiterhin das{locale}-Token, aber für dieses Format wird es unabhängig von der eingesetzten Locale zum selben Pfad aufgelöst, zum Beispiel adressiert{locale}Localizable.xcstringseine einzige DateiLocalizable.xcstrings. Die Quell-Locale und jede konfigurierte Ziel-Locale teilen sich also eine physische Datei. - Schreibvorgänge in einen gemeinsamen Katalog laufen seriell. Da jeder Schreibvorgang pro Locale dieselbe Datei berührt, serialisiert verbatra jede Operation, die sie schreiben kann -
translate, eine Studio-Bearbeitung, eine Einzelkey-Neuübersetzung und den Workbook-Import - gegeneinander. In der Praxis heißt das: Einapple-xcstrings-Projekt führt diese Operationen nacheinander aus, selbst wenn--concurrencyüber 1 gesetzt ist; jedes andere Format führt seine Provider-Aufrufe weiterhin wie konfiguriert parallel aus. - Der Key ist der Quell-String. Ein Katalog-Key ohne expliziten
localizations-Eintrag für die im Dokument selbst angegebenesourceLanguagefällt auf den Key-Text selbst zurück, passend zu Xcodes eigener Konvention. Ein Key ohne Eintrag für jede andere Locale gilt für diese Locale einfach als noch nicht übersetzt, genau wie ein fehlender Key in der Zieldatei jedes anderen Formats. - Plurale liegen in
variations.plural. Jede untervariations.pluraleiner Locale vorhandene CLDR-Kategorie (zero,one,two,few,many,other) wird zu einem eigenen übersetzbaren Eintrag, mit demselben<key>_<Kategorie>-Suffix, den auchi18next-jsonund die.stringsdict-Unterstützung des Apple-.strings-Formats verwenden, zum Beispiel%lld photos_oneund%lld photos_other. Eine Locale, die nur einen Teil der Kategorien liefert, rundet exakt mit diesen: Keine wird erfunden, keine wird verworfen. - Platzhalter sind im printf-Stil.
%@,%d,%1$@,%lldund das escapte Literal%%werden extrahiert und über die Übersetzung hinweg geschützt, genau wie bei Apple-.strings-Werten; ein Längenmodifikator wie dasllin%lldist Dekoration und nicht Teil der Identität des Tokens, also sind%lldund%dderselbe Platzhalter. shouldTranslate: falsewird respektiert. Ein so markierter Key wird nie an einen Provider gesendet und nie geändert zurückgeschrieben.- Schreibvorgänge patchen das Dokument, statt es neu aufzubauen. Ein Schreibvorgang liest den aktuellen Katalog erneut ein und aktualisiert nur die berührten Localizations, sodass
extractionState, jede andere Locale, nicht übersetzbare Einträge, Plural-Kategorien, die obersteversiondes Katalogs und seinesourceLanguageunverändert erhalten bleiben. Ein gerade übersetzter Wert erhältstringUnit.state: "translated"; die bestehende Localization eines unveränderten Werts, Status inklusive, bleibt byteidentisch statt neu geschrieben zu werden. - Der Zielkatalog muss bereits existieren. Anders als bei
.stringsoder.propertieslegt verbatra keinen neuen.xcstrings-Katalog an: Erstelle ihn zuerst in Xcode und richtefiles.patterndann darauf aus. - Fehlerhafte Eingaben sind spezifisch. Ein strukturierter
AdapterErrorbenennt die Datei und, wenn das Problem innerhalb eines Eintrags liegt, auch Key und Locale, zum Beispiel bei einem Eintrag ohnestringUnit- und ohnevariations.plural-Feld oder bei einer Plural-Kategorie außerhalb der CLDR-Menge.
Android strings.xml
Verfügbar ab 0.10.0
Das android-xml-Format deckt Androids Ressourcendateien ab, res/values/strings.xml für die Quell-Locale und res/values-<Qualifier>/strings.xml für jedes Ziel, erkannt an der Endung .xml. Setze files.localeStyle auf android (siehe die Konfigurationsdatei), damit sich {locale} in files.pattern zum richtigen Ressourcen-Qualifier-Verzeichnis statt zu einem wörtlichen BCP-47-Tag auflöst.
<string>und<plurals>. Ein<string name="key">value</string>ist ein Eintrag. Ein<plurals name="key">wird zu einem eigenen Eintrag pro<item quantity="...">(zero,one,two,few,many,other), mit dem Keykey[quantity], zum Beispielcount[one]undcount[other]. Eine Locale, die nur einen Teil der Kategorien liefert, rundet exakt mit diesen: Keine wird erfunden, keine wird verworfen. Jeder Ressourcennamenamewird gegen Androids Bezeichnergrammatik geprüft (ein Buchstabe oder Unterstrich, dann Buchstaben, Ziffern oder Unterstriche), bevor er zum Key wird, sodass ein Name keinen Zusammenstoß mit[quantity]-förmigem echtem Plural-Key-Raum fälschen kann.translatable="false"wird respektiert. Ein<string>oder<plurals>mit diesem Attribut wird nie an einen Provider gesendet und bleibt auf der Festplatte unverändert.formatted="false"wird normal übersetzt. Das Attribut sagt nur Androids eigenem Build-Werkzeug, keine printf-Argumente zu prüfen; es ändert nichts an dem, was verbatra tut. Platzhalter im Stil%s/%dwerden weiterhin extrahiert und über die Übersetzung hinweg geschützt.<string-array>und Inline-Markup sind in dieser Version durchgereicht. Ein<string-array>und ein<string>, dessen Inhalt kein reiner Text ist (ein Inline-Element wie<b>,<xliff:g>oder einCDATA-Abschnitt), bleiben exakt so erhalten, wie sie sind, und gehen nie in verbatras übersetzbare Menge ein. Übersetzung auf Item-Ebene für diese ist eine mögliche künftige Erweiterung, heute aber nicht unterstützt.- Escaping wird beim Lesen dekodiert, beim Schreiben neu kodiert.
\',\",\n,\tund ein führendes\@oder\?werden beim Lesen zu ihren wörtlichen Zeichen dekodiert, und dieselben Zeichen (plus ein führendes, nicht escaptes@oder?) werden beim Schreiben wieder escapt; XMLs eigene Entities&,<und>werden unabhängig davon von der XML-Schicht darunter behandelt, sodass ein übersetzter Wert mit einem dieser Zeichen sicher zurückgeschrieben wird, ohne dass du selbst escapen musst. - Platzhalter sind im printf-Stil.
%s,%d,%1$sund das escapte Literal%%werden extrahiert und über die Übersetzung hinweg geschützt. Ein bloßes%gefolgt von gewöhnlichem Text, wie in"50% off", extrahiert nichts: Der Extraktor behandelt ein Leerzeichen nicht als gültiges Konvertierungsflag, anders als Javas eigenesString.format, sodass ein Prozentzeichen in gewöhnlichem Fließtext nie für einen Platzhalter gehalten wird. - Schreibvorgänge aktualisieren Ziele an Ort und Stelle; eine fehlende Zieldatei wird neu erzeugt. Eine bestehende
res/values-<Qualifier>/strings.xmlwird gepatcht: Ein übersetzter Key wird aktualisiert, ein aus der Quelle entfernter Key wird gelöscht, und das übergeordnete Verzeichnis wird angelegt, falls es noch nicht existiert. Eine noch nicht existierende Zieldatei wird von Grund auf neu erzeugt, das Verzeichnisres/values-<Qualifier>/eingeschlossen. - Einschränkung: Ein zu Durchreichen degradierter Key wird nach der Übersetzung entfernt, nicht erhalten. Wenn ein Key bereits in einer Zieldatei übersetzt war und dann in der Quelldatei
translatable="false"oder Inline-Markup erhält, kann der nächste Lauf das nicht von einer echten Löschung des Keys unterscheiden und entfernt die veraltete Übersetzung aus der Zieldatei. Das ist eng begrenzt (es betrifft nur einen Key, dessen Quellklassifikation sich ändert, nachdem er bereits übersetzt wurde) und über Versionskontrolle oder einen erneuten Übersetzungslauf wiederherstellbar; es betrifft keinen Key, der seine ursprüngliche Klassifikation behält, einschließlich gewöhnlicher neuer, geänderter und entfernter Keys. - Einschränkung:
--prunehat kein Bewusstsein für Plural-Quantitäten. verbatras Erkennung verwaister Keys und--prunevergleicht Keys gegen die eigene Key-Menge der Quelle, ohne Sonderfall fürkey[quantity]-Gruppen. Eine Ziel-Locale, die mehr Plural-Quantitäten braucht als die Quelle deklariert (zum Beispiel eine Sprache mit mehr grammatischen Numerus-Unterscheidungen), hat nur im Ziel vorhandene Quantitäten, die ein--prune-Lauf nicht von einem echt entfernten Key unterscheiden kann, und kann sie löschen. Standardmäßig deaktiviert; ein gewöhnlicherverbatra translate-Lauf ohne--pruneist davon nicht betroffen. - Fehlerhafte Eingaben sind spezifisch. Fehlerhaftes XML löst einen strukturierten
AdapterErroraus, der das Problem benennt; ein Dokument, dessen Wurzelelement nicht<resources>ist, ein Ressourcenname, der die Bezeichnergrammatik verletzt, ein<plurals>-Item mit einer Quantität außerhalb der CLDR-Menge oder zwei Elemente, die sich zum selben Key auflösen, werden alle namentlich gemeldet statt als generischer Parse-Fehler. Eine DTD- oder Entity-Deklaration wird rundweg abgelehnt.
gettext .po/.pot
Verfügbar ab 0.10.0
Das gettext-po-Format deckt GNU gettexts .po- und .pot-Kataloge ab, erkannt an beiden Endungen: eine flache Folge von msgid/msgstr-Einträgen, mit der msgid als Key, nie in einen Baum aufgespalten.
msgctxt-Disambiguierung. Einmsgctxtvor einem Eintrag setzt sich mit dessenmsgidzu einem Key zusammen, sodass zwei Einträge mit derselbenmsgidunter verschiedenen Kontexten nie kollidieren. Das zusammengesetzte Format nutzt einen reservierten Private-Use-Codepoint (U+E000) als internen Trenner, ein Zeichen, das keine echte.po-Datei legitim enthält; ein Quelltext, der es doch enthält, wird mit einem strukturierten Fehler abgelehnt statt den Key still zu beschädigen.- Plurale sind
msgid_plural/msgstr[n], nach Index geschlüsselt, nicht nach CLDR-Kategorie. Jedesmsgstr[n]wird zu einem eigenen Eintrag, mit dem Keykey[n](nder rohe Dezimalindex), zum Beispielone item[0]undone item[1]. Das ist bewusst nicht die<key>_<category>-Suffixkonvention, die die JSON-Formate und Apples.stringsdictverwenden: Einen gettext-Index in eine CLDR-Kategorie zu übersetzen würde bedeuten, denPlural-Forms-C-Ausdruck der Datei selbst auszuwerten, was verbatra nicht tut. DerPlural-Forms-Header wird wörtlich als unangetasteter Text erhalten; verbatra liest daraus nur die Ganzzahlnplurals=N, um jedenmsgstr[n]-Index auf Gültigkeit zu prüfen. Eine Datei mit Plural-Einträgen und ohnePlural-Forms-Header wird abgelehnt, genau wiemsgfmt --checkes selbst durchsetzt. fuzzy-Einträge werden gelesen, nicht übersprungen. Das bestehendemsgstreines#, fuzzy-Eintrags wird als aktueller Wert dieses Eintrags gelesen, genau wie bei jedem anderen übersetzten Eintrag; verbatra behandeltfuzzynicht als fehlend. Das Flag bleibt bei jedem Schreibvorgang wörtlich erhalten und wird nie automatisch gesetzt oder entfernt.- Kommentare und der Header bleiben unangetastet erhalten.
#.-Entwicklerkommentare werden zur Beschreibung des Eintrags: Sie erreichen den Provider als Kontext zur Disambiguierung und erscheinen in derKontext-Spalte einer exportierten Arbeitsmappe.#:-Quellverweise und andere#,-Flags bleiben beim Schreiben erhalten, werden aber nicht weiter interpretiert. Ein#~-obsoleter Block bleibt als inerter Text erhalten und wird nie zu einem übersetzbaren Eintrag. Der Header-Eintrag (dermsgid ""-Block mitContent-Type,Plural-Formsund ähnlichen Metadaten) wird von einem Schreibvorgang nie angefasst. .pot-Vorlagen werden sauber gelesen. Eine.pot-Quellvorlage, deren Einträge ein leeresmsgstrtragen, wird ohne Fehler gelesen; der Wert jedes Eintrags ist einfach die leere Zeichenkette, bis er übersetzt wird.- Fehlende Zieldatei. Wie bei den Formaten properties und Apple
.stringswird eine noch nicht existierende.po-Zieldatei aus den Einträgen heraus neu erzeugt statt den Schreibvorgang scheitern zu lassen, einschließlich eines minimalen Headers. Eine neu erzeugte Datei mit Plural-Einträgen erhält einenPlural-Forms-Header, der auf den höchsten vorhandenen Index zugeschnitten ist; für eine oder zwei Formen ist das der universelle Standardausdruck, für drei oder mehr ein sicherer, im gültigen Bereich liegender Ersatzwert statt einer geratenen, möglicherweise falschen sprachlichen Regel; säe die Zieldatei zuerst aus einer echten zielsprachlichen Vorlage vor, wenn du die exakte Grammatik brauchst. - Platzhalter sind im printf-Stil, einschließlich Pythons benannter Form.
%s,%d,%1$s, das Python-Style%(name)sund das escapte Literal%%werden extrahiert und über die Übersetzung hinweg geschützt. - Fehlerhafte Eingaben sind spezifisch. Ein strukturierter
AdapterErrorbenennt die betroffenemsgidund die physische Zeile, zum Beispiel eine unterminierte gequotete Zeichenkette, eine unbekannte Escape-Sequenz, einen nicht zusammenhängendenmsgstr[n]-Index oder einen Plural-Eintrag ohnePlural-Forms-Header, statt eines generischen Parse-Fehlers. - Einschränkung:
--prunehat kein Bewusstsein für Plural-Indizes. verbatras Erkennung verwaister Keys und--prunevergleicht Keys gegen die eigene Key-Menge der Quelle, ohne Sonderfall fürkey[n]-Gruppen. Eine Ziel-Locale, die mehr Plural-Formen braucht als die Quelle deklariert (zum Beispiel eine Sprache mit mehr grammatischen Numerus-Unterscheidungen), hat nur im Ziel vorhandene Indizes, die ein--prune-Lauf nicht von einem echt entfernten Key unterscheiden kann, und kann sie löschen. Standardmäßig deaktiviert; ein gewöhnlicherverbatra translate-Lauf ohne--pruneist davon nicht betroffen.
Dokumentreihenfolge der Keys
Schreibvorgänge erhalten die Key-Reihenfolge deines Dokuments. Die JSON-Familie, YAML und ARB tragen Keys exakt in Dokumentreihenfolge durch den Roundtrip:
- Ein ganzzahlartiger Key wie
"2","10"oder"404"behält seine Position, statt nach vorn gehoben und neu sortiert zu werden, eine Datei mit numerischen Ids, HTTP-Statuscodes oder Jahreszahlen als Keys bleibt also in ihrer eigenen Reihenfolge. - Ein Key, den ein
translate-Lauf einer Zieldatei hinzufügt, wird nach den bestehenden Keys des Ziels angehängt, in der Reihenfolge des Quelldokuments, statt alphabetisch einsortiert zu werden. - ARB-Metadatenblöcke überstehen den Roundtrip ebenfalls an ihrer Dokumentposition.
XLIFF ist nicht betroffen: Es aktualisiert bestehende <target>-Elemente an Ort und Stelle, die Reihenfolge des Dokuments wurde also nie neu aufgebaut.
Gepunktete Keys und Kollisionen
Für i18next-json, vue-i18n-json und next-intl-json übersteht ein wörtliches gepunktetes Blatt (ein Key wie "foo.bar" als einzelnes Blatt) den Roundtrip verlustfrei: verbatra liest ihn und schreibt ihn mit seiner Form auf der Platte zurück, nicht neu verschachtelt in foo und dann bar. Echte verschachtelte Pfade bleiben verschachtelt.
Der eine Fall, der bewusst fehlschlägt, ist eine echte Kollision, bei der eine Datei denselben effektiven Pfad sowohl als wörtliches gepunktetes Blatt als auch als echten verschachtelten Pfad ausdrückt (zum Beispiel "foo.bar" neben "foo": { "bar": ... }). Dieses Lesen schlägt mit INVALID_STRUCTURE fehl, statt zu raten oder Daten zu beschädigen.
ngx-translate-json behandelt einen gepunkteten Key als verschachtelten Pfad statt als wörtliches Blatt, es gibt also keine Mehrdeutigkeit zwischen gepunktet und wörtlich zu erhalten, aber es bekommt dieselbe Kollisionssicherheit: Ein gepunkteter Key, dessen Pfad mit einem echten verschachtelten Pfad kollidiert, auch wenn einer der Vorfahr des anderen ist, schlägt mit INVALID_STRUCTURE fehl, statt still einen Wert zu überschreiben.
Wie Dateien gelesen und geschrieben werden
verbatra begrenzt beim Lesen Eingabegröße und Verschachtelungstiefe und widersteht einer Datei, die sich unter ihm ändert. Es schreibt atomar: erst in eine temporäre Datei, dann per Umbenennen an den Zielort, ein unterbrochener Schreibvorgang hinterlässt also nie eine halbfertige Locale-Datei. Wenn verbatra eine Datei nicht verarbeiten kann, erzeugt es einen strukturierten, geheimnisfreien Fehler mit stabilem Code statt eines rohen: INVALID_JSON, INVALID_YAML oder INVALID_XML für fehlerhafte Syntax, INVALID_STRUCTURE für eine parsebare Datei der falschen Form, MAX_DEPTH_EXCEEDED und INPUT_TOO_LARGE für die Obergrenzen und MIXED_STRUCTURE für ngx-translates Mischfall.
Eine baumbasierte Locale-Datei (die JSON-Familie, YAML und ARB) kann ein Blatt tragen, das kein String ist, zum Beispiel ein count: 5 oder enabled: true neben den übersetzbaren Keys. verbatra akzeptiert das: Ein Blatt darf String, Zahl, Boolean oder null sein, und nur ein Blatt eines anderen Typs, etwa ein Array, schlägt mit INVALID_STRUCTURE fehl. Ein Nicht-String-Blatt ist vom übersetzbaren Bestand ausgeschlossen: Es wird nie übersetzt, gehasht, verglichen oder auf Platzhalter oder ICU geprüft. Ausschluss ist keine Erhaltung: Schreibt verbatra später dieselbe Locale-Datei, wird der Schreibvorgang aus den Strings aufgebaut, die es verwaltet, ein beim Lesen vorhandenes Nicht-String-Blatt wird also nicht in die Ausgabe übernommen. Muss so ein Wert einen Neuschrieb überleben, halte ihn aus den Dateien heraus, in die verbatra schreibt. XLIFF-Trans-Unit-Werte und .properties-Werte sind immer Strings, dort gilt das also nicht.
Warum das Format wichtig ist
Das Format sagt verbatra zwei Dinge, die es für einen sicheren Lauf braucht. Erstens die Platzhaltersyntax, damit die Platzhalter-Integritätsprüfung weiß, was sie vor und nach der Übersetzung vergleichen soll. Zweitens, für die ICU-Formate, welche Werte zu validieren sind, damit ein Quell-Key mit ungültigem ICU übersprungen statt in kaputtem Zustand gesendet wird. Das falsche Format vergleicht die falschen Tokens, wähle es also passend zu deiner i18n-Bibliothek: i18next-json für i18next, vue-i18n-json für vue-i18n, next-intl-json für next-intl, ngx-translate-json für ngx-translate, xliff für XLIFF-Dateien, yaml für YAML-basierte i18n, arb für Flutter, properties für Java- oder Spring-.properties-Dateien, apple-strings für Apple-.strings-Dateien, apple-xcstrings für Xcode-String-Catalog-.xcstrings-Dateien, android-xml für Android strings.xml und gettext-po für gettext-.po/.pot-Kataloge.
Provider
Die sechs Übersetzungs-Provider, ihre Optionen und API-Schlüssel und das Verhalten, das sie alle teilen.
Kosten abschätzen
Schätze den Umfang eines Übersetzungslaufs ab, bevor du Geld ausgibst: zähle die Keys mit einem Dry Run, rechne sie in Requests und Tokens um und bepreise sie mit den Raten deines Providers.