Recettes SDK

Des patrons complets et exécutables pour piloter verbatra depuis tes propres scripts, jobs CI et outillage.

Page traduite automatiquement

Cette page a été traduite automatiquement, elle peut donc contenir des erreurs ou sonner un peu bizarrement. La version anglaise est la référence. Lire l'original en anglais.

La référence SDK catalogue chaque point d'entrée. Cette page est le compagnon pratique : des recettes de bout en bout à copier dans un script et à lancer. Une chose à préparer d'abord : le SDK ne charge pas les fichiers .env (c'est la CLI qui fait ça), donc assure-toi que la variable d'environnement du fournisseur est définie avant que ton script tourne, par exemple :

node --env-file=.env translate.mjs

Traduire en une passe dans un script

Charge la config, lance le flux, puis lis le résumé : l'essentiel dans succeeded et failed, la dépense de tokens dans usage, et les clés qui méritent un regard humain dans le needsReview de chaque locale. Les problèmes globaux lèvent une SdkError ; les résultats par locale sont des données sur le résumé.

import { loadConfig, translate } from "@verbatra/sdk";

const config = await loadConfig();
const summary = await translate({ config });

console.log(`${summary.succeeded.length} locales ok, ${summary.failed.length} failed`);

if (summary.usage !== undefined) {
  console.log(`tokens: ${summary.usage.inputTokens} in, ${summary.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 (summary.failed.length > 0) {
  process.exitCode = 1;
}

Passe dryRun: true pour prévisualiser sans appeler de fournisseur ni rien écrire, et prune: true ou generatePlurals: true pour surcharger ces options de config le temps d'une exécution. Mets concurrency au-dessus de 1 pour traduire les locales en parallèle (non autorisé avec un budget maxTokens sur une exécution réelle) et cache: false pour contourner le cache de mémoire de traduction.

Vérifier en CI sans écrire

check lit et compare sans appeler de fournisseur ni toucher aucun fichier, et son champ inSync est vrai exactement quand rien n'est manquant ni obsolète. Ça en fait le contrôle CI naturel.

import { check, loadConfig } from "@verbatra/sdk";

const summary = await check({ config: await loadConfig() });

if (!summary.inSync) {
  for (const locale of summary.locales) {
    if (!locale.inSync) {
      console.error(`${locale.locale}: ${locale.missing} missing, ${locale.stale} stale`);
    }
  }
  process.exitCode = 1;
}

Besoin des noms de clés plutôt que des comptes ? Remplace par diff, qui renvoie les listes de clés missing, changed et orphaned par locale, avec le même verdict hasPendingChanges. Tu lances plutôt la CLI en CI ? Voir CI et codes de sortie.

Surveiller dans un processus de longue durée

watch déclenche une exécution immédiatement au démarrage, puis une par changement temporisé de la source, en rapportant chacune via onRun. Pour un arrêt propre, attends controller.stop() : il ferme la surveillance et attend la fin de l'exécution en cours avant que ton processus se termine.

import { loadConfig, watch } from "@verbatra/sdk";

const config = await loadConfig();
const controller = await watch({
  config,
  onRun: (result) => {
    if (result.status === "succeeded") {
      console.log(`ran: ${result.summary.succeeded.length} ok, ${result.summary.failed.length} failed`);
    } else {
      console.error(`run failed: ${result.error.code} ${result.error.message}`);
    }
  },
});

process.on("SIGINT", () => {
  void controller.stop().then(() => {
    process.exit(0);
  });
});

Un échec d'exécution après le démarrage ne lève jamais ; il arrive comme { status: "failed" } et la surveillance continue.

Modifier et retraduire une seule clé

Ce sont les interfaces que Verbatra Studio pilote ; utilise-les pour construire ton propre flux de révision. Lis les valeurs actuelles avec keyValue, enregistre une correction humaine avec editEntry, ou relance le fournisseur pour une clé avec retranslateEntry. Les deux fonctions d'écriture passent la valeur candidate par les mêmes vérifications de placeholders et d'ICU qu'une exécution complète et renvoient un résultat à deux branches au lieu de lever sur une valeur rejetée.

import { editEntry, keyValue, loadConfig, retranslateEntry } from "@verbatra/sdk";

const config = await loadConfig();

// Read the live values feeding your edit UI.
const current = await keyValue({ config, locale: "de", key: "checkout.title" });
console.log(`source: ${current.source}, target: ${current.target ?? "(not yet translated)"}`);

// Save a human-typed correction. No provider call.
const edit = await editEntry({
  config,
  locale: "de",
  key: "checkout.title",
  value: "Zur Kasse",
});
if (!edit.accepted) {
  console.error(`rejected (${edit.reason} check failed), nothing written`);
}

// Or ask the provider for a fresh translation of just this key.
const retry = await retranslateEntry({ config, locale: "de", key: "checkout.title" });
if (retry.accepted) {
  console.log(`wrote: ${retry.value}`);
  if (retry.reviewReasons.length > 0) {
    console.warn(`flagged for review: ${retry.reviewReasons.join(", ")}`);
  }
}

Une locale ou une clé inconnue lève UNKNOWN_LOCALE ou UNKNOWN_KEY, et retranslateEntry lève la ProviderError du fournisseur lui-même (par exemple RATE_LIMITED) quand l'appel échoue. Voir Réviser les traductions dans Studio pour les mêmes interfaces derrière une UI.

L'aller-retour du classeur

Exporte les chaînes à traduire dans un classeur Excel, confie-le à un traducteur, puis réimporte le fichier rempli. importWorkbook exécute les mêmes vérifications de dérive, de placeholders et d'ICU que translate et renvoie la même forme RunSummary, donc une passation manuelle s'insère exactement dans le reporting que tu utilises pour une exécution automatisée.

import { exportWorkbook, importWorkbook, loadConfig } from "@verbatra/sdk";

const config = await loadConfig();

// Write a workbook of the missing and changed strings.
const exported = await exportWorkbook({ config });
for (const sheet of exported.locales) {
  console.log(`${sheet.locale}: ${sheet.rows} rows`);
}
console.log(`wrote ${exported.path}`);

// ...later, after the translator returns the file, import it back.
const summary = await importWorkbook({ config, workbook: exported.path });
console.log(`${summary.succeeded.length} locales ok, ${summary.failed.length} failed`);

Passe dryRun: true à importWorkbook pour valider un fichier renvoyé sans rien écrire. Voir Traduction humaine pour ce que les traducteurs peuvent modifier et comment les lignes sont validées.

Une config sans fichier

loadConfig accepte un configOverride en mémoire, validé exactement comme un fichier chargé, donc tu peux piloter verbatra entièrement depuis le code, sans fichier de config sur disque.

import { loadConfig, translate } from "@verbatra/sdk";

const config = await loadConfig({
  configOverride: {
    sourceLocale: "en",
    targetLocales: ["de", "fr"],
    format: "i18next-json",
    files: { pattern: "locales/{locale}.json" },
    provider: { id: "gemini", options: { model: "gemini-2.5-flash", maxOutputTokens: 4096 } },
  },
});

await translate({ config });

Pour chaque forme d'entrée, l'anatomie complète du RunSummary et la table des codes SdkError, voir la référence SDK.

Edit on GitHub