Docs / Erste Schritte
Maschinell übersetzte Seite
SDK-Schnellstart
Installiere @verbatra/sdk, sieh dir einen Lauf ohne API-Schlüssel in der Vorschau an, übersetze aus deinem Skript, behandle Fehler und sichere die CI ab.
Am Ende dieser Seite übersetzt ein TypeScript-Skript von dir eine englische Locale-Datei ins Deutsche, meldet, was passiert ist, und lässt einen CI-Job scheitern, sobald eine Locale nicht mehr synchron ist. Du brauchst Node.js ^22.18.0 || >=24 und etwa zehn Minuten. Die ersten drei Schritte brauchen keinen API-Schlüssel.
Jeder Schritt ist ein vollständiges Skript, das du mit node ausführst. Node.js führt TypeScript-Dateien direkt aus, ein zusätzliches Flag brauchst du nicht. Die Skripte nutzen import und Top-Level-await, deshalb markiert der erste Schritt das Projekt auch als ES-Modul.
Schritte
Das SDK installieren
npm init -y
npm pkg set type=module
npm install --save-dev @verbatra/sdkFühr das in einem leeren Verzeichnis aus: npm init -y legt die package.json an, die npm pkg set type=module als ES-Modul markiert. In einem bestehenden Projekt lässt du npm init -y weg. Wenn pnpm mit ERR_ endet, sieh unter Installation nach.
Eine Quelldatei und eine Konfiguration anlegen
{
"greeting": "Hello, {{name}}!",
"cart": {
"empty": "Your cart is empty."
}
}import { defineConfig } from "@verbatra/sdk";
export default defineConfig({
sourceLocale: "en",
targetLocales: ["de"],
format: "i18next-json",
files: { pattern: "locales/{locale}.json" },
provider: { id: "gemini", options: { model: "gemini-2.5-flash", maxOutputTokens: 4096 } },
});loadConfig findet diese Datei ausgehend vom Arbeitsverzeichnis und validiert sie. Unter Wähle deinen Stack steht das format für dein Framework, und Provider listet jeden Provider mit seinen Optionen. Willst du ganz ohne Datei auskommen, übergib dasselbe Objekt als configOverride; siehe SDK-Rezepte.
Den Lauf ohne Schlüssel in der Vorschau ansehen
import { loadConfig, translate } from "@verbatra/sdk";
const config = await loadConfig();
const preview = await translate({ config, dryRun: true });
for (const locale of preview.locales) {
console.log(`${locale.locale}: would translate ${locale.translated.join(", ")}`);
}node preview.tsde: would translate cart.empty, greetingEin Probelauf baut keinen Provider, braucht also keinen Schlüssel, kostet nichts und schreibt nichts. Übergib stattdessen estimate: true, um eine Token- oder Kostenzahl zu bekommen; siehe Kosten schätzen.
Übersetzen und die Zusammenfassung lesen
import { loadConfig, translate } from "@verbatra/sdk";
const config = await loadConfig();
const summary = await translate({
config,
onProgress: (event) => {
if (event.type === "locale-finished") console.log(`${event.locale}: ${event.translated} keys`);
},
});
const { succeeded, partial, failed, usage } = summary;
console.log(`${succeeded.length} ok, ${partial.length} partial, ${failed.length} failed`);
if (usage !== undefined) {
console.log(`tokens: ${usage.inputTokens} in, ${usage.outputTokens} out`);
}
for (const locale of summary.locales) {
if (locale.status === "failed") {
console.error(`${locale.locale}: ${locale.error?.code} ${locale.error?.message}`);
continue;
}
for (const entry of locale.needsReview) {
console.warn(`review ${locale.locale}/${entry.key}: ${entry.reasons.join(", ")}`);
}
}
if (failed.length > 0 || partial.length > 0) {
process.exitCode = 1;
}Der Provider liest seinen Schlüssel aus der Umgebung, und anders als die CLI lädt das SDK keine .env-Dateien, also reichst du ihn selbst weiter. Provider nennt die Variable für jeden Provider.
node --env-file=.env translate.tslocales/de.json enthält jetzt beide Keys, und {{name}} ist unversehrt. Eine Locale mit partial wurde geschrieben, obwohl noch Keys fehlen, deshalb scheitert das Skript daran genauso wie an failed. Probleme einzelner Locales kommen als Daten in der Zusammenfassung an; nur ein Problem des ganzen Laufs wirft. translate listet jede weitere Option.
Fehler behandeln Verfügbar ab 0.12.0
Ein Problem des ganzen Laufs wirft einen SdkError. Verzweige über seinen stabilen code und gib errorHint aus, um den nächsten Schritt zu zeigen.
import { errorHint, loadConfig, SdkError, translate } from "@verbatra/sdk";
try {
const summary = await translate({ config: await loadConfig() });
console.log(`${summary.succeeded.length} locales translated`);
} catch (error) {
if (!(error instanceof SdkError)) {
throw error;
}
switch (error.code) {
case "CONFIG_NOT_FOUND":
console.error(`${error.code}: ${error.message} (searched from ${process.cwd()} upward)`);
break;
case "PROVIDER_CONSTRUCTION_FAILED":
console.error(`${error.code}: the provider could not be built, most often for a missing key`);
break;
default:
console.error(`${error.code}: ${error.message}`);
}
const hint = errorHint(error);
if (hint !== undefined) {
console.error(`next: ${hint}`);
}
process.exitCode = 2;
}Führst du es ohne Schlüssel aus, meldet es PROVIDER_ und nennt die fehlende Variable, nie einen Schlüsselwert. Fehlercodes listet jeden Code.
Die CI mit check absichern
import { check, loadConfig } from "@verbatra/sdk";
const summary = await check({ config: await loadConfig() });
for (const locale of summary.locales) {
console.log(`${locale.locale}: ${locale.missing} missing, ${locale.stale} stale`);
}
if (!summary.inSync) {
process.exitCode = 1;
}node check.tscheck ruft keinen Provider auf und schreibt nichts, braucht in der CI also keinen Schlüssel. Das Skript endet mit 1, wenn ein Quelltext keine Übersetzung hat oder sich seit der Übersetzung geändert hat.
CommonJS
In einem CommonJS-Projekt liefert require("@verbatra/sdk") dieselben Exporte. Top-Level-await gibt es dort nicht, also packst du die Aufrufe in eine async-Funktion.
Nächste Schritte
- SDK-Rezepte: Schätzungen, Watch-Modus, ein Test-Double für den Provider, die Review-Warteschlange und die Roundtrips über Arbeitsmappe und TMX.
- SDK-Referenz: jeder Einstiegspunkt, seine Eingabe und was er wirft.
- Eigene Provider und eigene Format-Adapter: binde ein, was verbatra nicht mitliefert.
- Übersetzungssicherheit: was verbatra prüft, bevor es eine Übersetzung schreibt.