SDK-Referenz
Jeder Einstiegspunkt von @verbatra/sdk, gruppiert nach Aufgabe, mit dem Fehlermodell und der Anatomie der RunSummary.
Maschinell übersetzte Seite
@verbatra/sdk ist der Motor, auf dem der Befehl verbatra läuft. Die CLI ist ein dünner Wrapper;
was die Kommandozeile kann, kannst du also auch im Code. Diese Seite katalogisiert die gesamte
öffentliche Oberfläche, gruppiert nach der Aufgabe jedes Einstiegspunkts. End-to-End-Beispiele
stehen in SDK-Rezepte.
Installation
pnpm add -D @verbatra/sdk
# npm
npm install -D @verbatra/sdk
# yarn
yarn add -D @verbatra/sdkBenötigt Node.js >=22.14.0.
API-Keys und die Umgebung
Das SDK liest, hält oder akzeptiert nie einen API-Key. Der Provider liest seinen Key aus der
Umgebung (zum Beispiel ANTHROPIC_API_KEY), wenn er konstruiert wird. Anders als die CLI lädt das
SDK keine .env-Dateien: setze die Variable in deinem eigenen Skript selbst, zum Beispiel mit
node --env-file=.env script.js.
Jeder Einstiegspunkt nimmt ein Eingabeobjekt, dessen erstes Feld die validierte config (aus
loadConfig) ist, außer wo anders vermerkt. Die meisten akzeptieren zusätzlich ein optionales
zweites deps-Argument, das für Tests eine Registry, einen Provider-Builder oder ein Dateisystem
injiziert; im normalen Gebrauch kannst du es ignorieren.
Übersetzungen ausführen
translate
Der Einmal-Flow: die Quelle lesen, jedes Ziel-Locale mit der Lock-Baseline vergleichen, die fehlenden und geänderten Keys an den Provider schicken, die Platzhalter- und ICU-Integritätsprüfungen ausführen, die Locale-Dateien schreiben und das Lock aktualisieren. Nutze es für Skripte, Build-Schritte und CI-Jobs.
Eingabe: { config, cwd?, dryRun?, prune?, generatePlurals?, concurrency?, cache?, onProgress?, onLockWait?, lockAcquireTimeoutMs? }.
dryRunliest, vergleicht und meldet, ohne den Provider zu konstruieren oder aufzurufen und ohne irgendetwas zu schreiben.pruneentfernt verwaiste Keys (Ziel-Keys ohne Gegenstück in der Quelle) aus der geschriebenen Datei und dem Lock.generatePluralssynthetisiert fehlende CLDR-Pluralformen (nur i18next-JSON mit einem LLM-Provider). Beide sind standardmäßig aus; wenn gesetzt, übersteuert jedes die passende Konfigurationsoption für diesen Lauf.concurrencyübersetzt bis zu so viele Ziel-Locales gleichzeitig (Standard 1, streng seriell). Ein Wert unter 1 wirftCONCURRENCY_INVALID; bei einem Live-Lauf wirft ein Wert über 1 mit gesetztemmaxTokenseinenCONCURRENCY_BUDGET_CONFLICT(ein Dry-Run ist ausgenommen).cacheist standardmäßig true und verwendet den lokalen Translation-Memory-Cache wieder; setze ihn auf false, um den Cache für den Lauf zu umgehen (das--no-cacheder CLI).onProgresswird aufgerufen, während der Lauf fortschreitet (pro Locale-Start und -Ende sowie pro Provider-Sub-Batch), undonLockWaitfeuert, während die Schreibsperre eines Locales umkämpft ist. Beides sind Benachrichtigungs-Callbacks; das SDK gibt selbst nichts aus.lockAcquireTimeoutMsübersteuert, wie lange eine umkämpfte Schreibsperre erneut versucht, bevor sie mitLOCK_CONTENDEDfehlschlägt.maxBatchSize,maxTokensundbudgetBehaviorsind nur über die Konfiguration steuerbar; es gibt keine Übersteuerung pro Lauf.
Gibt eine RunSummary zurück (siehe ihre Anatomie unten).
Probleme des gesamten Laufs werfen einen SdkError; ein einzelnes fehlschlagendes Locale wirft
nie, sondern landet als status: "failed" auf dem Eintrag dieses Locales, während der Lauf
weitergeht.
watch
Beobachtet die Quell-Locale-Datei und führt translate bei jeder entprellten Änderung neu aus. Es
feuert beim Start sofort einen initialen Lauf, danach einen Lauf pro beruhigter Änderung. Läufe
sind serialisiert: Änderungen während eines Laufs fallen zu einem einzigen Folgelauf zusammen.
Eingabe: { config, cwd?, debounceMs?, onRun, concurrency?, cache?, onProgress?, onLockWait?, lockAcquireTimeoutMs? }.
debounceMs ist standardmäßig 300. onRun wird einmal pro Lauf mit einem WatchRunResult
aufgerufen: { status: "succeeded", summary } oder { status: "failed", error: { code, message } }.
Das SDK loggt nichts; onRun ist die einzige Ausgabe. concurrency, cache, onProgress,
onLockWait und lockAcquireTimeoutMs werden an jeden Lauf durchgereicht und verhalten sich genau
wie bei translate (ein budgetierter Watch mit concurrency über 1 scheitert bei jedem Lauf mit
CONCURRENCY_BUDGET_CONFLICT).
Gibt einen WatchController mit einer Methode zurück, stop(), die den Watcher schließt und den
laufenden Lauf abwartet. Eine fehlende Quelldatei wirft beim Start SOURCE_UNREADABLE; jeder
Fehlschlag danach kommt über onRun an, und das Beobachten geht weiter.
Zustand inspizieren, ohne zu schreiben
Keine dieser Funktionen ruft einen Provider auf, schreibt eine Datei oder verändert das Lock.
check
Meldet die Drift pro Locale als Zähler: missing (in der Quelle, im Ziel fehlend), stale
(Quelle seit der letzten Übersetzung geändert) und upToDate. Nutze es als CI-Gate.
Eingabe: { config, cwd?, locales? }. Gibt eine CheckSummary zurück, deren inSync genau dann
true ist, wenn jedes geprüfte Locale nichts Fehlendes und nichts Veraltetes hat.
diff
Das detaillierte Geschwister von check: dieselbe Berechnung, aber es gibt die Key-Listen pro
Locale zurück (missing, changed, orphaned) statt Zähler. Verwaiste Keys sind reine Meldung
und kippen nie hasPendingChanges, da ein Standardlauf nicht prunt.
Eingabe: { config, cwd?, locales? }. Gibt eine DiffSummary zurück.
keyIntegrity
Meldet für die geänderten Keys jedes Locales, ob der aktuelle Zielwert noch zu den Platzhaltern
der Quelle passt und ob er gültiges ICU ist. Jeder Eintrag trägt key, hasPlaceholders,
matches, bei einer Abweichung die missing- und extra-Platzhalter-Tokens sowie icuValid.
Einträge tragen nie einen Quell- oder Zielstring-Wert. Das ist der Integritätsbericht pro Key, den
Studio anzeigt.
Eingabe: { config, cwd?, locales?, keys? }. keys engt die Prüfung ein; geprüft werden immer
nur Keys, die für ein Locale "geändert" sind. Gibt ein LocaleKeyIntegrity pro geprüftem Locale
zurück.
lockState
Meldet Existenz, Version und Drift pro Locale der Lock-Datei (Baseline-Key-Anzahl plus Zähler für
fehlend, veraltet und aktuell). exists stammt aus einer expliziten Prüfung, sodass "noch keine
Lock-Datei" und "eine leere, aber vorhandene Lock-Datei" unterscheidbar bleiben. Fehlt die Datei,
ist das Ergebnis { exists: false } und nichts weiter wird gelesen.
Eingabe: { config, cwd?, locales? }. Gibt ein LockStateResult zurück.
loadLockFile
Liest die Lock-Datei selbst (verbatra.lock.json, auch als LOCK_FILE_NAME exportiert) und gibt
ihre geparste Form zurück: { version, locales }, wobei jedes Locale Keys auf den Hash des
Quellinhalts abbildet, aus dem sie zuletzt übersetzt wurden. Eine fehlende Datei degradiert zu
einem leeren Lock, dasselbe Erstlauf-Verhalten, auf das sich translate verlässt; nutze
lockState, wenn du Abwesenheit unterscheiden musst.
Eingabe: { cwd? }. Keine Konfiguration nötig. Gibt ein LockFile zurück.
runStatus
Liest den Schnappschuss aus Review-Flags und Token-Verbrauch, den der letzte translate- oder
watch-Lauf ohne Dry-Run nach .verbatra-local/run-status.json persistiert hat. Wirft nie: eine
fehlende, korrupte oder unbekannte Datei degradiert zu { available: false }. Diese Datei ist
Best-Effort-Telemetrie, keine Korrektheits-Baseline.
Eingabe: { cwd? }. Keine Konfiguration nötig. Gibt { available: false } oder
{ available: true, version, generatedAt, usage?, budget?, locales } zurück.
Operationen auf einzelnen Keys
Das sind die Nahtstellen, die Verbatra Studio antreibt; nutze sie, um dein eigenes Review-Tooling
zu bauen. Alle drei lösen locale und key bei jedem Aufruf frisch auf und werfen
UNKNOWN_LOCALE oder UNKNOWN_KEY, wenn eines von beiden nicht existiert.
keyValue
Liest den aktuellen Quellwert eines Keys und, falls vorhanden, seinen aktuellen Zielwert für ein Locale. Schreibgeschützt.
Eingabe: { config, cwd?, locale, key }. Gibt { source, target? } zurück; target fehlt genau
dann, wenn der Key in diesem Locale noch nicht existiert.
editEntry
Schreibt eine von Hand getippte Korrektur für einen Key und ein Locale. Der Kandidatenwert durchläuft dasselbe Platzhalter- und ICU-Gate wie eine Provider-Übersetzung, bevor irgendetwas die Platte erreicht; bei Annahme werden die Locale-Datei und der Lock-Eintrag für diesen Key innerhalb des Schreib-Locks des Locales aktualisiert. Ruft nie einen Provider auf.
Eingabe: { config, cwd?, locale, key, value }. Gibt ein zweiarmiges Ergebnis zurück:
{ accepted: true, value } oder { accepted: false, reason: "placeholder" | "icu", value },
wobei nichts geschrieben wird.
retranslateEntry
Lässt den Provider für genau einen Key und ein Locale neu laufen: ein Einzeleintrag-Aufruf durch
dieselbe Provider-Registry, die translate nutzt, abgesichert durch dieselben
Integritätsprüfungen. Bei Annahme schreibt es die Locale-Datei und den Lock-Eintrag nur für diesen
Key.
Eingabe: { config, cwd?, locale, key }. Gibt { accepted: true, value, reviewReasons } zurück
(die Review-Grund-Codes, falls vorhanden, die auf den neuen Wert zutreffen) oder
{ accepted: false, reason: "placeholder" | "icu", value }. Anders als bei translate wirft ein
Provider-Fehlschlag hier: ein ProviderError aus @verbatra/ai-providers mit einem stabilen Code
wie RATE_LIMITED oder AUTH_FAILED.
Locale-Datei-Schnappschüsse
Die Bausteine eines Live-Refresh-Watchers wie dem von Studio: den Zustand einer Locale-Datei erfassen und dann zählen, was sich seitdem geändert hat.
readLocaleFileSnapshot
Liest eine Locale-Datei (das Quell-Locale oder ein beliebiges Ziel-Locale) und reduziert sie auf einen Inhalts-Hash pro Key. Eine noch nicht existierende Datei liest sich als leerer Schnappschuss, statt zu werfen.
Eingabe: { config, locale, cwd? }. Gibt { locale, hashes } zurück.
diffLocaleSnapshots
Vergleicht zwei Schnappschüsse derselben Datei aus verschiedenen Zeitpunkten und zählt die
zwischen ihnen hinzugefügten, geänderten und entfernten Keys. Eine schlichte synchrone Funktion:
diffLocaleSnapshots(previous, current) gibt { added, changed, removed } zurück. Nur Zähler,
nie Key-Namen.
Das Arbeitsmappen-Paar
Die Excel-Übergabe für menschliche Übersetzerinnen; siehe Menschliche Übersetzung.
exportWorkbook
Schreibt die noch zu übersetzenden Strings (fehlende und geänderte Keys pro Locale; unveränderte
kommen mit includeUnchanged dazu) in eine formatierte .xlsx-Arbeitsmappe. Die Zeilen tragen
dasselbe Review-Flag-Signal, das ein translate-Lauf berechnet. Kein Provider-Aufruf, kein
Lock-Schreiben.
Eingabe: { config, cwd?, out?, locales?, includeUnchanged? }. out ist standardmäßig
DEFAULT_WORKBOOK_PATH (verbatra-translations.xlsx), als Konstante exportiert. Gibt
{ path, locales } zurück: den absoluten geschriebenen Pfad und eine Zeilenzahl pro Locale.
importWorkbook
Liest eine ausgefüllte Arbeitsmappe zurück in die Locale-Dateien und führt dieselben Prüfungen auf
Quelldrift, Platzhalter und ICU aus wie translate. Nur akzeptierte Zeilen rücken ihre
Lock-Baseline vor; eine leere oder abgelehnte Zeile wird weiter exportiert, bis sie wirklich
erledigt ist.
Eingabe: { config, workbook, cwd?, dryRun? }. Gibt dieselbe RunSummary-Form zurück wie
translate (mit needsReview immer leer, da kein Provider beteiligt ist). Ein Blatt für ein
Locale, das kein konfiguriertes Ziel ist, lässt dieses Locale mit CONFIG_INVALID als Daten auf
der Zusammenfassung fehlschlagen, kein Wurf.
Konfiguration
loadConfig
Findet, lädt und validiert die Projektkonfiguration und gibt eine VerbatraConfig zurück.
Optionen: { cwd?, configPath?, configOverride? }, mit der Vorrangfolge configOverride (ein
Objekt im Speicher validieren) vor configPath (eine explizite Datei laden) vor der Suche. Die
Suche beginnt bei cwd und deckt verbatra.config.ts (auch .js/.cjs), die
.verbatrarc-Familie (.json, .yaml, .yml, .js, .cjs, .ts) und eine
"verbatra"-Eigenschaft in package.json ab. Ein als Dateipfad angegebenes glossary wird hier
gelesen und validiert, sodass nachgelagerter Code immer einen einfachen Record sieht.
Wirft CONFIG_NOT_FOUND, wenn nichts gefunden wird, CONFIG_INVALID, wenn eine Konfiguration
gefunden, aber ungültig ist. Das Schema steht in Konfigurationsdatei.
loadConfigWithMeta
Dasselbe Laden, plus Herkunft: gibt { config, source, glossary } zurück, wobei source sagt, ob
die Konfiguration aus einem Suchtreffer, einem expliziten Pfad oder einer Übersteuerung im
Speicher kam (mit dem absoluten filepath, wenn es einen gibt), und glossary festhält, ob das
Glossar fehlte, inline war oder aus einer Datei aufgelöst wurde. Nutze es, wenn du anzeigen musst,
woher die Konfiguration kam.
defineConfig
Ein Identitätshelfer zum Schreiben einer typisierten verbatra.config.ts: er gibt sein Argument
unverändert zurück und existiert rein für Typinferenz und Editor-Autovervollständigung,
einschließlich der Vervollständigung der bekannten Modell-IDs des gewählten Providers. Die
Modell-Einschränkung gilt nur beim Schreiben; zur Laufzeit besteht jeder nicht-leere String die
Validierung.
verbatraConfigSchema
Das zod-Schema, mit dem loadConfig validiert, exportiert, damit dein eigenes Tooling ein
Konfigurationsobjekt genauso validieren kann wie das SDK. Unbekannte Top-Level-Keys werden
abgelehnt, ein verirrtes Secret kann sich also nicht in der Konfiguration verstecken.
scaffoldingMetadata
Schreibgeschützte Metadaten, aus denen der CLI-Befehl init seine Abfragen ableitet:
providerEnv (Provider-ID zur Umgebungsvariable, aus der sein Key gelesen wird),
scaffoldModels (ein Standard-Scaffold-Modell pro LLM-Provider) und supportedFormats (die
geschlossene Menge der Format-IDs). Der Typ ScaffoldableProviderId deckt die vier gehosteten
Provider ab; openai-compatible ist ausgenommen, weil es keine einzelne verpflichtende
Umgebungsvariable hat.
Die Anatomie der RunSummary
translate, importWorkbook und jeder erfolgreiche watch-Lauf lösen zu einer RunSummary auf:
interface RunSummary {
dryRun: boolean; // true when nothing was written and no provider was called
locales: LocaleSummary[]; // one entry per target locale, in config order
succeeded: string[]; // locales whose run succeeded
failed: string[]; // locales whose run failed
usage?: UsageSummary; // summed input/output tokens; absent when no call reported usage
budget?: RunBudget; // present only when maxTokens is configured
}
interface LocaleSummary {
locale: string;
status: "succeeded" | "failed";
translated: string[]; // keys translated this run (in dry-run, keys that would be)
cacheHits: string[]; // keys served from the translation-memory cache this run
unchanged: string[]; // keys already up to date
orphaned: string[]; // target keys with no matching source key (always reported)
pruned: string[]; // orphaned keys removed this run; empty unless pruning is on
invalidIcuSource: string[]; // source keys skipped for invalid ICU
integrityMismatches: string[]; // translations withheld for a placeholder mismatch
providerFailures: string[]; // keys withheld because nothing was translated for them
budgetWithheld: string[]; // keys never sent because a "stop" budget already tripped
generated: string[]; // CLDR plural forms synthesized this run
unfilled: string[]; // import only: changed rows the translator left blank
malformedRows: { row: number; column: string }[]; // import only: rows the reader could not parse
duplicateKeys: { key: string; row: number }[]; // import only: later rows for a duplicated key
notices: LocaleNotice[]; // provider notices and SDK notices for this locale
needsReview: { key: string; reasons: string[] }[]; // accepted keys flagged for a second look
usage?: UsageSummary; // this locale's summed tokens; absent if nothing reported usage
error?: { code: string; message: string }; // present only when status is "failed"
}Die Teile, die du kennen solltest:
- needsReview listet akzeptierte, geschriebene Keys, die die Review-Heuristiken markiert
haben, jeder mit seinen Grund-Codes:
LENGTH_RATIO_OUTLIER,EQUALS_SOURCE,GLOSSARY_TERM_MISSED,INTEGRITY_REORDEREDundPROVIDER_DEGRADED. Ein Review-Flag ist nur ein Hinweis und hält nie einen Key zurück; ein Key erscheint also nie inneedsReviewundintegrityMismatcheszugleich. Was jeder Code bedeutet, steht in Übersetzungssicherheit, das Abarbeiten der Warteschlange in Review in Studio. - notices leben pro Locale, nie auf oberster Ebene. Dazu zählen Provider-Notices (etwa eine
DeepL-Degradation) und SDK-Notices mit den Codes
PLURAL_CATEGORIES_INCOMPLETE,SUB_BATCH_FAILED,BLANK_ROW_BASELINE_RETAINEDundBUDGET_TOKENS_EXCEEDEDab. - usage ist
undefined, nie eine erfundene Null, wann immer nichts in diesem Bereich einen Verbrauch gemeldet hat: ein Dry-Run ruft nie einen Provider auf, und DeepL meldet nie Tokens.RunSummary.usageist die Summe über die Locales. - budget erscheint nur, wenn
maxTokenskonfiguriert ist:{ maxTokens, behavior, supported, tokensUsed, exceeded }. Gegen einen Provider ohne Token-Meldung oder in einem Dry-Run ist es trotzdem vorhanden, mitsupported: false; die Leitplanke ist also sichtbar wirkungslos statt fälschlich ausgelöst. - error.code auf einem fehlgeschlagenen Locale ist ein durchgereichter String (der Code des
zugrunde liegenden Providers oder Adapters, mit
LOCALE_FAILEDnur als Rückfall); behandle ihn also nicht als geschlossene Menge. - cacheHits listet Keys, die aus dem Translation-Memory-Cache statt vom
Provider bedient wurden. unfilled, malformedRows und duplicateKeys werden nur von
importWorkbookbefüllt (eintranslate-Lauf lässt sie leer): eine leerechanged-Zeile, eine Arbeitsmappen-Zeile, die der Reader nicht parsen konnte, und ein doppelter Key, dessen erstes Vorkommen gewonnen hat.
Das Fehlermodell
Fehlschläge des gesamten Laufs werfen einen SdkError: eine Klasse, ein stabiler code und eine
message ohne Secrets. Verzweige auf den Code, nicht auf die Message. Fehlschläge pro Locale,
Provider-Notices und Integritätsbefunde kommen als Daten auf der RunSummary an, werden nie
geworfen.
| Code | Wann |
|---|---|
CONFIG_NOT_FOUND | die Suche fand keine Konfiguration, oder ein explizites configPath existiert nicht (geworfen von loadConfig) |
CONFIG_INVALID | eine Konfiguration wurde gefunden, ist aber nicht parsebar oder fällt durch die Validierung, oder ihre Glossardatei konnte nicht aufgelöst werden |
UNKNOWN_FORMAT | für das konfigurierte Format ist kein Adapter registriert; geworfen, bevor irgendeine Datei gelesen wird |
UNKNOWN_LOCALE | ein angefragtes Locale gehört nicht zu den konfigurierten Ziel-Locales |
UNKNOWN_KEY | ein angefragter Key ist nicht in der Quell-Ressource (keyValue, editEntry, retranslateEntry) |
PROVIDER_CONSTRUCTION_FAILED | der Provider konnte nicht gebaut werden; umhüllt den eigenen Fehler des Providers, einschließlich eines fehlenden API-Keys |
SOURCE_UNREADABLE | die Quell-Locale-Datei existiert nicht |
SOURCE_INVALID | die Quell-Locale-Datei konnte nicht gelesen oder geparst werden; umhüllt den Lesefehler des Adapters |
LOCK_FILE_INVALID | die Lock-Datei ist vorhanden, aber korrupt, übergroß oder in einer nicht unterstützten Version |
LOCK_CONTENDED | das Schreib-Lock eines Locales konnte nicht vor seinem Timeout erworben werden; die Message nennt den Pfad der Lock-Datei |
CONCURRENCY_INVALID | concurrency wurde gesetzt, ist aber keine Ganzzahl von mindestens 1; wird geworfen, bevor ein Locale läuft |
CONCURRENCY_BUDGET_CONFLICT | ein Live-Lauf setzte concurrency über 1, während maxTokens konfiguriert ist; wird vor jedem Provider-Aufruf geworfen (ein Dry-Run ist ausgenommen) |
LOCALE_FAILED | wird nie geworfen: der Rückfall-code auf dem error eines fehlgeschlagenen Locales |
Zwei Ausnahmen von der Ein-Fehlerklasse-Regel: retranslateEntry wirft den eigenen
ProviderError des Providers weiter, wenn der einzelne Aufruf fehlschlägt, und runStatus wirft
überhaupt nie. Wie diese Codes auf CLI-Exit-Codes abbilden, steht in
CI und Exit-Codes; Hilfe vom Symptom aus gibt es unter
Troubleshooting.