Docs / Konzepte
Maschinell übersetzte Seite
Die Lock-Datei und die Herkunft
Was verbatra.lock.json und verbatra.provenance.json festhalten, wie Drift erkannt wird, wie parallele Läufe serialisiert werden und warum du beide committest.
verbatra.lock.json ist die Baseline, gegen die jeder Lauf vergleicht, sodass ein Lauf Aktuelles
überspringen und Abgedriftetes neu übersetzen kann. Daneben hält
verbatra.provenance.json fest, wer oder was jeden
Wert geschrieben hat.
Was sie festhält
Für jede Ziel-Locale einen Hash pro übersetztem Key, gebildet aus dem Quelleintrag hinter der
aktuellen Übersetzung, plus ein Feld version: keine Übersetzungen, keine Secrets. Der Hash deckt
den Quellwert samt Beschreibung, Bedeutung, Plural-Flag und Platzhaltern ab, eine geänderte
Beschreibung macht den Key also ebenfalls veraltet. Er normalisiert Unicode auf NFC und Zeilenenden
auf LF, ein erneutes Speichern einer Quelldatei mit CRLF-Zeilenenden ändert also nichts.
Wie Drift erkannt wird
Ein Quell-Key, der im Ziel fehlt, ist missing. Bei einem vorhandenen Key wird der aktuelle Quell-Hash mit dem festgehaltenen verglichen: Ein Unterschied heißt, die Quelle hat sich geändert und der Key wird neu übersetzt; eine Übereinstimmung heißt, er wird nie gesendet, ein zweiter Lauf ohne Änderungen an der Quelle kostet also nichts. Die ganze Pipeline steht unter Wie ein Lauf funktioniert.
Geschützte Keys
Die Ausnahme ist ein geänderter Key, dessen Wert ein Mensch geschrieben oder importiert hat: Er ist standardmäßig geschützt und bleibt veraltet, statt neu übersetzt zu werden.
Ein bestehendes Projekt übernehmen
Locale-Dateien, die schon reviewte Übersetzungen enthalten, werden nicht neu übersetzt. Beim ersten Lauf gibt es keine Lock-Datei, also kann nichts veraltet sein: Ein Key, den das Ziel hat, behält seinen Wert, nur fehlende Keys werden übersetzt, und der Lauf hält jeden Quell-Hash als Baseline fest, ohne Provider-Kosten.
Die Übernahme richtet sich nach dem Vorhandensein eines Keys, nie nach seinem Wert, und das hat zwei Folgen:
- Ein leerer oder unübersetzter Wert zählt als übersetzt. Lösch den Key (ihn zu leeren reicht nicht), und der nächste Lauf übersetzt ihn.
- Eine veraltete Übersetzung wird als aktuell festgehalten. Korrigiere oder lösch sie vor dem ersten Lauf.
Dieselbe Regel behält handgeschriebene Pluralformen bei, generatePlurals ist bei der Übernahme also
sicher. Um all das vorab zu sehen, führ verbatra diff oder verbatra translate --dry-run aus.
Wie sie aktualisiert wird
- Ein vollständiger Lauf (
translate,watchoder ein Import) ersetzt die Einträge einer Locale durch das Ergebnis des Laufs. - Eine Aktion für einen einzelnen Key, etwa ein Retranslate aus Studio, mergt nur den Eintrag dieses Keys.
In beiden Fällen behält ein Key, der in diesem Lauf zurückgehalten wurde (eine gescheiterte Integritätsprüfung oder ein gescheiterter Provider-Aufruf, eine Quelle mit ungültigem ICU), seinen bisherigen Hash, sodass der nächste Lauf ihn erneut versucht. Verwaiste Keys bekommen keinen Eintrag, und sortierte Keys halten die Diffs klein.
Die Schreibsperre
Zwei Läufe, die gleichzeitig dieselbe Locale anfassen, könnten beide gegen eine veraltete Baseline
vergleichen und doppelt bezahlen, deshalb hält jeder Schreibvorgang eine prozessübergreifende
Sperre für diese Locale unter .verbatra-local/. Ein zweiter Schreiber wartet und vergleicht dann
gegen eine Baseline, die das Ergebnis des ersten enthält. Verschiedene Locales blockieren sich nie
gegenseitig.
Was die Sperre garantiert:
- Ein Timeout kostet nichts.
--lock-timeoutbegrenzt nur das Warten vor jedem Provider-Aufruf, eine Locale, die aufgibt, hat also nichts ausgegeben und nichts geschrieben; das Festhalten einer geschriebenen Datei wartet die vollen zehn Minuten des Standards. - Verwaiste Sperren blockieren dich nicht. Eine Sperre, deren Prozess auf diesem Rechner nicht mehr existiert, wird sofort übernommen, und eine, die 30 Sekunden lang nicht aufgefrischt wurde (Halter frischen alle 10 auf), gilt als verwaist.
- Ein Abbruch gibt die Sperren frei. Ctrl-C oder SIGTERM während
translateoderimportund der zweite Abbruch, derwatchzwangsweise beendet, geben jede Sperre frei, bevor der Prozess endet. - Eine verlorene Sperre stoppt den Schreibvorgang. Jede Sperre trägt ein zufälliges Token, das
vor jedem Schreibvorgang geprüft wird; hat ein anderer Lauf die Sperre übernommen,
stoppt der Schreibvorgang mit
LOCK_, und nichts wird geschrieben.CONTENDED
Was sie nicht abdeckt:
- Eine Sperre von einem anderen Rechner (ein geteiltes Netzlaufwerk) oder von einer verbatra-Version vor 0.12.0 wird nie automatisch übernommen; wie du sie entfernst, steht unter Fehlerbehebung.
- Eine lange Pause zwischen Prüfung und Schreiben. Ein Lauf, der direkt nach der Token-Prüfung pausiert (ein schlafender Rechner, ein angehaltener Prozess), kann nach dem Fortsetzen noch einmal schreiben.
- Hosts mit gleichem Namen. Außerhalb von Linux ist der Hostname die einzige Rechneridentität,
zwei Container mit einem Hostnamen, die sich
.verbatra-local/teilen, können also die lebende Sperre des anderen für verwaist halten. Gib jedem seinen eigenen Hostnamen oder seine eigene Arbeitskopie.
Ein umgeschriebener Locale-Code
Die Lock-Datei, der Cache und die Herkunftsdatei ordnen ihren Zustand nach dem Locale-Code deiner
Konfiguration. Schreibst du einen um, etwa pt_ zu pt-BR, überträgt der nächste Lauf von
translate oder watch den alten Zustand einmalig und meldet
LOCALE_. Eine Quelländerung vor
der Umbenennung wird trotzdem neu übersetzt, und gecachte Übersetzungen werden weiter
wiederverwendet.
Die Übertragung passiert nur, wenn eindeutig: pt-BR hat keinen eigenen Zustand, und die
Datei hält Zustand unter genau einer Unterstrich-Schreibweise davon (oder seiner gettext-Schreibweise,
etwa sr@latin für sr-Latn), ohne Beachtung der Groß- und Kleinschreibung. Zustand, den pt-BR
schon hat, wird nie überschrieben. Lässt sich die Übertragung nicht schreiben, läuft diese Locale
nicht und scheitert mit
LOCALE_, sodass der
nächste Lauf es erneut versucht; die anderen Locales laufen wie gewohnt.
Bis dahin behandelt jedes Lesen den alten Zustand als den von pt-BR, ohne zu schreiben, ein
veralteter Key wird also als veraltet gemeldet. Ein Schreibvorgang für einen einzelnen Key (eine Bearbeitung, ein
Retranslate, eine Review-Entscheidung) und verbatra import übertragen den Zustand vorher auf
dieselbe Weise. Die Prüfung locale-state von verbatra doctor nennt
zurückgebliebenen Zustand.
Fehlend oder beschädigt
Eine fehlende Lock-Datei ist ein erster Lauf, kein Fehler.
Eine, die sich nicht parsen lässt, strukturell falsch, zu groß
oder in einer nicht unterstützten Version ist, lässt den Lauf mit
LOCK_ scheitern, statt überschrieben zu werden,
sodass du sie wiederherstellen kannst, statt die Baseline zu verlieren.
Herkunft: wer welchen Wert geschrieben hat
verbatra.provenance.json hält fest, welcher Schreibpfad jeden Wert erzeugt hat, der jetzt in der
Locale-Datei steht, und ob ihn jemand reviewt hat. Eine ältere verbatra-Version, etwa eine in CI
gepinnte, ignoriert sie.
| Herkunft | Geschrieben von |
|---|---|
machine | einer Provider-Antwort in translate, watch oder einem Retranslate eines einzelnen Keys, mit der id des Providers und, wenn bekannt, dem Modell |
memory | einem exakten Cache-Treffer, einschließlich jedes Werts, den ein reiner Handarbeits-Lauf (Provider none) füllt |
fuzzy | einem Treffer der unscharfen Wiederverwendung |
human | der Bearbeitung eines Menschen über editEntry aus dem SDK, wie sie der Bearbeitungsdialog in Studio macht |
agent | der Bearbeitung eines KI-Agenten über editEntry mit actor: "agent" |
import | einer angenommenen Zeile aus verbatra import |
unknown | einer Review-Entscheidung zu einem Wert ohne Eintrag, oder einer Herkunft, die dieses Release nicht kennt |
Zwei weitere werden beim Lesen abgeleitet: unrecorded ist ein Wert ohne Eintrag, wie jeder Key
nach einem Upgrade; external passt nicht mehr zum Hash seines Eintrags, weil ihn etwas außerhalb
von verbatra geändert hat, etwa der Pull Request eines Übersetzers, ein älteres verbatra oder ein Merge. Die Felder, die jedes Lesen liefert,
stehen in der SDK-Referenz.
Was die Datei garantiert:
- Stabile Diffs. Kein übersetzter Text und keine Zeitstempel, ein sortierter Eintrag pro Zeile,
ein Lauf, der nichts ändert, lässt die Datei also unverändert. Bei einem Merge-Konflikt nimm die
Seite, die zur behaltenen Locale-Datei passt: Ein abweichender Eintrag liest sich als
external, was den Wert vor Neuübersetzung schützt. - Frische Einträge für neue Werte. Ein Schreibvorgang, der einen Wert ändert, ersetzt seinen Eintrag durch einen neuen, nicht reviewten; einer, der Wert und Quelle unverändert lässt, behält ihn.
- Kein stilles Überschreiben. Eine beschädigte Datei stoppt jeden Schreibvorgang mit
PROVENANCE_, bevor sich eine Locale-Datei ändert; Berichte lassen ihre Herkunftsfelder stattdessen weg. Eine Datei von einer neueren verbatra-Version bleibt unangetastet, und eine, die zu groß zum Zurücklesen würde, wird nicht geschrieben (FILE_ INVALID PROVENANCE_).FILE_ TOO_ LARGE
Sie ist nicht fälschungssicher; um daraus einen Bericht zu machen, siehe Nachweis maschineller Übersetzungen festhalten.
Review-Entscheidungen
Ein Eintrag kann eine Review-Entscheidung tragen, approved oder rejected, mit einem optionalen
Namen unter reviewer. Studios Review-Seite, die Review-Funktionen des SDK und die
MCP-Review-Tools schreiben sie; die MCP-Tools geben die Entscheidung eines Menschen
weiter und verlangen dessen Namen. Eine Entscheidung gilt für genau
den Wert, den der Reviewer gesehen hat, und wird abgelehnt, wenn er sich geändert hat.
- Eine Freigabe ändert nur die Herkunftsdatei und liest sich wieder als nicht reviewt, sobald sich der Quelltext ändert.
- Eine Ablehnung entfernt den Wert und seinen Lock-Eintrag, sodass der Key als missing gilt, bis
der nächste Lauf von
translateoder ein Mensch einen neuen Wert schreibt. Der Eintrag behält einen Hash des entfernten Texts und der Cache-Eintrag wird verworfen, damit ein Lauf nicht denselben Text zurückbringt. XLIFF kann keine einzelne Übersetzung weglassen, eine Ablehnung wird dort also mitREVIEW_abgelehnt.REJECT_ UNSUPPORTED
Nur Werte der Maschinenklasse landen in der Review-Warteschlange und im --require-reviewed-Gate. Die byReviewState-Zähler in check und lock.state erfassen jeden Wert nach seiner aufgezeichneten Entscheidung, gleich welcher Herkunft: Ein von einer Person geschriebener oder importierter Wert ohne Entscheidung zählt dort als unreviewed, ohne in der Warteschlange zu stehen. Lies sie zusammen mit byOrigin.
Die Entscheidungen stehen in dieser committeten Datei, also sehen die Review-Warteschlange und
verbatra check --require-reviewed auf
jedem Rechner denselben Zustand, und der Name unter reviewer ist öffentlich; verbatra trägt ihn
nie ein.
Committe sie
Committe verbatra.lock.json und verbatra.provenance.json mit deinen Locale-Dateien und
bearbeite sie nie von Hand: sie sind die Baseline, gegen die dein Team und deine CI vergleichen, und das, was ein Rollback wiederherstellt.