Recetas del SDK

Patrones completos y ejecutables para manejar verbatra desde tus propios scripts, jobs de CI y herramientas.

Página traducida automáticamente

Esta página fue traducida automáticamente, así que puede contener errores o sonar un poco raro. La versión en inglés es la fuente de la verdad. Lee el original en inglés.

La referencia del SDK cataloga cada punto de entrada. Esta página es la compañera práctica: recetas de principio a fin que puedes copiar en un script y ejecutar. Una cosa que preparar primero: el SDK no carga archivos .env (eso lo hace la CLI), así que asegúrate de que la variable de entorno del proveedor está definida antes de que corra tu script, por ejemplo:

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

Traducción única en un script

Carga la configuración, ejecuta el flujo y luego lee el resumen: el titular en succeeded y failed, el gasto de tokens en usage y las claves que merecen una mirada humana en el needsReview de cada locale. Los problemas de toda la ejecución lanzan un SdkError; los resultados por locale son datos en el resumen.

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;
}

Pasa dryRun: true para previsualizar sin llamar a un proveedor ni escribir nada, y prune: true o generatePlurals: true para anular esas opciones de configuración durante una ejecución. Pon concurrency por encima de 1 para traducir locales en paralelo (no permitido con un presupuesto maxTokens en una ejecución real) y cache: false para omitir la caché de memoria de traducción.

Comprueba en CI sin escribir

check lee y compara sin llamar a un proveedor ni tocar ningún archivo, y su indicador inSync es true exactamente cuando no hay nada faltante ni obsoleto. Eso lo convierte en la puerta natural de CI.

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;
}

¿Necesitas los nombres de las claves en lugar de contadores? Cambia a diff, que devuelve listas de claves missing, changed y orphaned por locale con la misma puerta hasPendingChanges. ¿Ejecutas la CLI en CI en su lugar? Consulta CI y códigos de salida.

Vigila en un proceso de larga duración

watch dispara una ejecución inmediatamente al arrancar, y luego una por cada cambio del origen asentado por el anti-rebote, informando de cada una a través de onRun. Para un apagado limpio, espera controller.stop() con await: cierra el watcher y espera a que termine la ejecución en curso antes de que salga tu proceso.

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 fallo de ejecución después del arranque nunca lanza; llega como { status: "failed" } y la vigilancia continúa.

Edita y retraduce una sola clave

Estos son los puntos de integración que usa Verbatra Studio; úsalos para construir tu propio flujo de revisión. Lee los valores actuales con keyValue, guarda una corrección humana con editEntry o vuelve a ejecutar el proveedor para una clave con retranslateEntry. Ambos escritores pasan el valor candidato por las mismas comprobaciones de marcadores de posición e ICU que una ejecución completa y devuelven un resultado de dos ramas en lugar de lanzar ante un valor rechazado.

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(", ")}`);
  }
}

Un locale o una clave desconocidos lanzan UNKNOWN_LOCALE o UNKNOWN_KEY, y retranslateEntry lanza el ProviderError propio del proveedor (por ejemplo RATE_LIMITED) cuando la llamada en sí falla. Consulta Revisión en Studio para los mismos puntos de integración detrás de una interfaz.

El ciclo de ida y vuelta del libro

Exporta las cadenas que necesitan traducción a un libro de Excel, entrégaselo a un traductor y luego importa el archivo rellenado de vuelta. importWorkbook ejecuta las mismas comprobaciones de desfase, marcadores de posición e ICU que translate y devuelve la misma forma RunSummary, así que una entrega manual encaja en el mismo informe exacto que usas para una ejecución automática.

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`);

Pasa dryRun: true a importWorkbook para validar un archivo devuelto sin escribir nada. Consulta Traducción humana para saber qué pueden editar los traductores y cómo se validan las filas.

Una configuración sin archivo

loadConfig acepta un configOverride en memoria, validado exactamente igual que un archivo cargado, así que puedes manejar verbatra enteramente desde código sin ningún archivo de configuración en disco.

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 });

Para cada forma de entrada, la anatomía completa de RunSummary y la tabla de códigos de SdkError, consulta la referencia del SDK.

Edit on GitHub