Die Lock-Datei
Was verbatra.lock.json festhält, wie Drift erkannt wird, wie parallele Läufe serialisiert werden und warum du die Datei committest.
Maschinell übersetzte Seite
Die Lock-Datei, verbatra.lock.json, existiert, damit ein Lauf erkennen kann, was schon übersetzt
wurde, und es überspringt. Diese Datei ist die Baseline, mit der jeder Lauf vergleicht, und sie
macht verbatra inkrementell. Diese Seite behandelt, was sie speichert, wie sie sich ändert und was
passiert, wenn sie umkämpft, fehlend oder beschädigt ist.
Was sie festhält
Für jede Ziel-Locale speichert die Lock-Datei einen Content-Hash pro übersetztem Key, berechnet
aus dem Quellwert, aus dem die bestehende Übersetzung entstanden ist. Die Datei enthält keine
Übersetzungen und keine Geheimnisse: nur ein version-Feld und Hashes. Der Hash normalisiert
Unicode zu NFC und Zeilenenden zu LF, sodass das erneute Speichern einer Quelldatei mit anderer
Normalisierung oder mit CRLF-Enden nichts als geändert markiert.
Wie Drift erkannt wird
Wenn ein Lauf eine Ziel-Locale vergleicht, gilt ein Quell-Key, der im Ziel nicht vorkommt, als fehlend. Für einen Key, den das Ziel hat, wird der aktuelle Quell-Hash mit dem Hash verglichen, den die Lock-Datei aufgezeichnet hat: Ein Unterschied bedeutet, dass die Quelle seit der letzten Übersetzung des Keys gedriftet ist, er gilt also als geändert und wird neu übersetzt; eine Übereinstimmung bedeutet, dass er unverändert ist und nie an den Provider geht. Deshalb ruft ein zweiter Lauf ohne Quelländerungen den Provider für nichts auf, und deshalb können sich veraltete Übersetzungen nicht hinter einem Key verstecken, der bloß existiert. Die vollständige Pipeline steht auf Wie es funktioniert.
Ein bestehendes Projekt übernehmen
verbatra auf ein Repository zu richten, dessen Locale-Dateien schon geprüfte Übersetzungen enthalten, übersetzt diese nicht neu. Beim ersten Lauf gibt es keine Lock-Datei, also kann kein Key als veraltet erkannt werden: Ein Quell-Key, den die Zieldatei schon hat, gilt als unverändert, geht nie an den Provider und behält seinen bestehenden Wert. Nur Keys, die die Zieldatei nicht hat, sind fehlend, und nur die werden übersetzt. Wurde für eine Locale keine Übersetzung angenommen, kein Key entfernt und keine Form generiert, wird ihre bestehende Zieldatei gar nicht neu geschrieben.
Der Lauf hält trotzdem für jeden Key, den das Ziel enthält, den aktuellen Quell-Hash fest; der erste Lauf ist also der Übernahmeschritt selbst: Er legt die Baseline ohne einen einzigen Provider-Aufruf an, und ab dem zweiten Lauf tauchen Quelländerungen ganz normal als Drift auf.
Ob ein Key als übernommen gilt, entscheidet allein seine Anwesenheit, nie sein Wert. Daraus folgen zwei Dinge, die du vor diesem ersten Lauf kennen solltest:
- Ein leerer oder unübersetzter Wert zählt als übersetzt. Ein Zielwert, der ein leerer String ist oder noch der unübersetzte Quelltext, ist ein Key, der existiert, gilt also als unverändert und wird nie gefüllt. Scaffolding-Tools, die Locale-Dateien mit leeren Strings vorab anlegen, laufen genau da hinein. Die Lösung ist, den Key aus der Zieldatei zu löschen: den Wert zu leeren hilft nicht, denn ein leerer String ist weiterhin ein Eintrag. Ist der Key weg, sieht ihn der nächste Lauf als fehlend und übersetzt ihn.
- Eine schon vorher veraltete Übersetzung wird als aktuell verbucht. Die Lock-Datei nimmt den Quell-Hash so, wie er jetzt ist; eine Übersetzung, die schon vor der Übernahme von der Quelle abgedriftet war, gilt damit als aktuell und wird nicht noch einmal angefasst. Korrigiere oder lösche solche Keys vor dem ersten Lauf.
Die Plural-Generierung folgt derselben Übernahmeregel. Eine Pluralform, die die Zieldatei schon
enthält und die verbatra nicht selbst generiert hat, bleibt so, wie sie ist: Sie wird weder neu
generiert noch an den Provider geschickt (eine Form, die die Lock-Datei bereits führt, wird sehr
wohl neu generiert, sobald sich ihre Quelle ändert). generatePlurals kannst du also gefahrlos
anlassen, während du ein Projekt mit handgeschriebenen Pluralformen übernimmst; synthetisiert
werden nur Formen, die im Ziel wirklich fehlen.
Das alles kannst du dir ansehen, bevor du etwas ausgibst: verbatra diff listet pro Locale genau
die fehlenden und geänderten Keys, verbatra check meldet dasselbe als Zahlen, und
verbatra translate --dry-run gibt dir die vollständige Lauf-Zusammenfassung. Keiner der drei ruft
einen Provider auf, schreibt eine Locale-Datei oder schreibt die Lock-Datei.
Wie sie aktualisiert wird
Die Lock-Datei wird pro Locale aktualisiert, und wie, hängt davon ab, was gelaufen ist:
- Ein vollständiger Lauf (translate, watch oder ein Arbeitsmappen-Import) ersetzt die Einträge dieser Locale im Ganzen durch das maßgebliche Ergebnis des Laufs.
- Eine Einzel-Key-Aktion (etwa ein Retranslate aus Studio) mergt nur den Eintrag dieses Keys und lässt jeden anderen aufgezeichneten Key unangetastet.
In beiden Fällen gilt eine Ausnahme: Ein in diesem Lauf zurückgehaltener Key (eine fehlgeschlagene Integritätsprüfung, ein fehlgeschlagener Provider-Aufruf oder eine Quelle mit ungültigem ICU) behält seinen vorherigen Hash, damit der nächste Lauf ihn weiterhin als arbeitsbedürftig sieht und erneut versucht, statt ihn als erledigt zu verbuchen. Verwaiste Keys bekommen keinen Eintrag. Die Datei wird mit sortierten Keys serialisiert, damit ihre Diffs stabil und gut zu reviewen bleiben.
Die Schreibsperre
Zwei Läufe, die gleichzeitig dieselbe Locale anfassen (ein zweites Terminal, ein CI-Job, eine Studio-Aktion), könnten sonst beide mit einer veralteten Baseline vergleichen und beide denselben Provider-Aufruf bezahlen. Um das zu verhindern, passiert jeder Schreibvorgang an einer Locale und ihren Lock-Einträgen unter einer prozessübergreifenden Schreibsperre für genau diese eine Locale; ein zweiter Schreiber für dieselbe Locale wartet, liest die Lock-Datei dann frisch neu ein und vergleicht mit einer Baseline, die das Ergebnis des ersten Schreibers schon enthält. Verschiedene Locales blockieren einander nicht.
Übersetzt ein Lauf mehrere Locales gleichzeitig und trifft auf einen Fehler des gesamten Laufs (in der Praxis eine beschädigte Lock-Datei), beansprucht er keine neuen Locales mehr und wartet, bis die bereits laufenden fertig sind; so wird jede Sperre, die der Lauf genommen hat, freigegeben, bevor der Befehl endet. Nach dem Fehlschlag des Laufs wird kein Locale mehr gestartet, und der Fehlschlag selbst lässt keine Sperre verwaist zurück.
Kann eine Sperre nicht erworben werden, schlägt der Lauf mit LOCK_CONTENDED fehl und nennt den
Pfad der Sperrdatei (im gitignorierten Verzeichnis .verbatra-local/). Läuft gerade kein
verbatra-Prozess, wurde diese Datei von einem abgeschossenen Prozess zurückgelassen: Lösche sie
und versuche es erneut.
Fehlend oder beschädigt
Eine fehlende Lock-Datei ist kein Fehler: Es ist ein erster Lauf, und ohne Baseline kann nichts als
veraltet erkannt werden. Quell-Keys, die die Zieldatei nicht hat, sind fehlend und werden übersetzt;
Keys, die sie hat, gelten als unverändert und bleiben unangetastet, wie oben bei der Übernahme
beschrieben. Eine Lock-Datei, die vorhanden, aber nicht parsebar, strukturell falsch, zu groß oder
auf einer nicht unterstützten Version ist, lässt den Lauf mit LOCK_FILE_INVALID fehlschlagen,
statt still überschrieben zu werden, damit du sie untersuchen oder wiederherstellen kannst, statt
die Baseline zu verlieren.
Committe sie
Committe verbatra.lock.json zusammen mit deinen Locale-Dateien. Diese Datei ist die gemeinsame
Baseline, mit der deine Teamkollegen und deine CI vergleichen; sie in der Versionskontrolle zu
halten macht inkrementelle Läufe über Maschinen hinweg reproduzierbar. Bearbeite sie nie von Hand.
Beide zu committen ist auch das, was ein Rollback möglich macht. Weil die Lock-Datei Quell-Hashes festhält und nichts über die übersetzten Werte, behauptet sie nach einem Zurücksetzen deiner Locale-Dateien ohne sie weiterhin, die zurückgesetzten Übersetzungen seien aktuell, und nichts übersetzt sie neu. Siehe Wiederherstellung und Rollback.
Edit on GitHub