SDK-Referenz

Jeder Einstiegspunkt von @verbatra/sdk, gruppiert nach Aufgabe, mit dem Fehlermodell und der Anatomie der RunSummary.

Maschinell übersetzte Seite

Diese Seite wurde automatisch übersetzt und kann daher Fehler oder seltsame Formulierungen enthalten. Die englische Version ist die maßgebliche Quelle. Das englische Original lesen.

@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/sdk

Benö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? }.

  • dryRun liest, vergleicht und meldet, ohne den Provider zu konstruieren oder aufzurufen und ohne irgendetwas zu schreiben.
  • prune entfernt verwaiste Keys (Ziel-Keys ohne Gegenstück in der Quelle) aus der geschriebenen Datei und dem Lock. generatePlurals synthetisiert 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 wirft CONCURRENCY_INVALID; bei einem Live-Lauf wirft ein Wert über 1 mit gesetztem maxTokens einen CONCURRENCY_BUDGET_CONFLICT (ein Dry-Run ist ausgenommen).
  • cache ist 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-cache der CLI).
  • onProgress wird aufgerufen, während der Lauf fortschreitet (pro Locale-Start und -Ende sowie pro Provider-Sub-Batch), und onLockWait feuert, 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 mit LOCK_CONTENDED fehlschlägt.
  • maxBatchSize, maxTokens und budgetBehavior sind 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_REORDERED und PROVIDER_DEGRADED. Ein Review-Flag ist nur ein Hinweis und hält nie einen Key zurück; ein Key erscheint also nie in needsReview und integrityMismatches zugleich. 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_RETAINED und BUDGET_TOKENS_EXCEEDED ab.
  • 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.usage ist die Summe über die Locales.
  • budget erscheint nur, wenn maxTokens konfiguriert ist: { maxTokens, behavior, supported, tokensUsed, exceeded }. Gegen einen Provider ohne Token-Meldung oder in einem Dry-Run ist es trotzdem vorhanden, mit supported: 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_FAILED nur 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 importWorkbook befüllt (ein translate-Lauf lässt sie leer): eine leere changed-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.

CodeWann
CONFIG_NOT_FOUNDdie Suche fand keine Konfiguration, oder ein explizites configPath existiert nicht (geworfen von loadConfig)
CONFIG_INVALIDeine Konfiguration wurde gefunden, ist aber nicht parsebar oder fällt durch die Validierung, oder ihre Glossardatei konnte nicht aufgelöst werden
UNKNOWN_FORMATfür das konfigurierte Format ist kein Adapter registriert; geworfen, bevor irgendeine Datei gelesen wird
UNKNOWN_LOCALEein angefragtes Locale gehört nicht zu den konfigurierten Ziel-Locales
UNKNOWN_KEYein angefragter Key ist nicht in der Quell-Ressource (keyValue, editEntry, retranslateEntry)
PROVIDER_CONSTRUCTION_FAILEDder Provider konnte nicht gebaut werden; umhüllt den eigenen Fehler des Providers, einschließlich eines fehlenden API-Keys
SOURCE_UNREADABLEdie Quell-Locale-Datei existiert nicht
SOURCE_INVALIDdie Quell-Locale-Datei konnte nicht gelesen oder geparst werden; umhüllt den Lesefehler des Adapters
LOCK_FILE_INVALIDdie Lock-Datei ist vorhanden, aber korrupt, übergroß oder in einer nicht unterstützten Version
LOCK_CONTENDEDdas Schreib-Lock eines Locales konnte nicht vor seinem Timeout erworben werden; die Message nennt den Pfad der Lock-Datei
CONCURRENCY_INVALIDconcurrency wurde gesetzt, ist aber keine Ganzzahl von mindestens 1; wird geworfen, bevor ein Locale läuft
CONCURRENCY_BUDGET_CONFLICTein Live-Lauf setzte concurrency über 1, während maxTokens konfiguriert ist; wird vor jedem Provider-Aufruf geworfen (ein Dry-Run ist ausgenommen)
LOCALE_FAILEDwird 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.

Edit on GitHub