Saltar al contenido
Saltar al contenido

Docs / Guías

Página traducida automáticamente

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

Escribe un adaptador de formato propio

Aporta un formato que verbatra no trae: nómbralo con un identificador custom:, constrúyelo sobre una fábrica de adaptadores y entiende en qué confías.

Úsalo cuando tus archivos de locale estén en un formato que verbatra no lee de serie (consulta Formatos). Construyes el adaptador en tu propio paquete, nombras el formato con un identificador custom: y le entregas a verbatra un registro que lo contenga. No se publica nada en verbatra ni hace falta ninguna versión nueva.

Necesitas @verbatra/sdk en el proyecto. La línea de comandos verbatra no carga ningún plugin, a propósito (consulta En qué confías), así que un proyecto con un formato propio usa verbatra a través del SDK.

Nombrar el formato

Un formato de fuera de verbatra es custom: seguido de un nombre en minúsculas separado por guiones, como custom:toml o custom:my-format. Ningún nombre integrado lleva dos puntos, así que nunca puede ocultar uno. Ponlo en la configuración como cualquier nombre integrado:

.verbatrarc.json
{
  "sourceLocale": "en",
  "targetLocales": ["de"],
  "format": "custom:toml",
  "files": { "pattern": "locales/{locale}.toml" },
  "provider": { "id": "gemini", "options": { "model": "gemini-2.5-flash", "maxOutputTokens": 4096 } }
}

La configuración solo comprueba la forma del identificador, porque el adaptador vive en tu paquete. Si nada aporta un adaptador para él, la ejecución falla con UNKNOWN_FORMAT. Studio y project.snapshot del servidor MCP informan del identificador tal cual, así que un agente distingue un formato propio de uno integrado.

Construir el adaptador

No implementes el contrato del adaptador a mano. Dos fábricas aportan la lectura acotada, la escritura atómica, la detección por extensión y los errores estructurados, y solo te dejan el análisis de tu formato.

Si cada entrada se identifica con una sola clave sin anidamiento, usa createFlatFileAdapter:

toml-adapter.ts
import { createFlatFileAdapter, type FormatAdapter } from "@verbatra/sdk";

const TOKEN = /\{[a-z]+\}/g;

const tokensIn = (value: string): readonly string[] =>
  [...value.matchAll(TOKEN)].map((match) => match[0]);

export const tomlAdapter: FormatAdapter = createFlatFileAdapter({
  format: "custom:toml",
  extensions: [".toml"],
  parseEntries: (content, namespace) => parseToml(content, namespace),
  serializeEntries: (entries) => serializeToml(entries),
  extractPlaceholders: tokensIn,
});

Si las entradas viven en rutas dentro de objetos anidados, usa createTreeFileAdapter, que recibe parse y serialize sobre un árbol y un deriveEntry para cada hoja.

Después, según lo que necesite tu formato:

  • Si tu extensión es genérica, dale a la fábrica un sniff que compruebe una muestra del contenido. Sin él, tu adaptador reclama todos los archivos con esa extensión y la detección informa de una ambigüedad.
  • Si un archivo contiene a la vez el texto de origen y el de destino, o registra su locale, lee el argumento extra locale que reciben parseEntries y serializeEntries.
  • Si una lista plana de tokens perdería la estructura de tus placeholders, añade comparePlaceholders; si tu formato tiene ramas de plural o select, añade compareBranchArms.
  • Si tu formato marca contenido como no traducible, devuelve { entries, excludedLeafPaths } desde parseEntries en lugar de descartarlo.
  • Lee y escribe a través del puerto fs que te entrega la fábrica, nodeAdapterFs por defecto, nunca directamente con node:fs. Así conservas la lectura acotada y la escritura atómica, y puedes probar el adaptador sin disco.

Registrarlo y ejecutar

Parte del registro integrado para que tu formato se sume a los demás y pásalo como la dependencia adapterRegistry que acepta cada flujo del SDK:

translate.ts
import { createDefaultRegistry, translate, loadConfig } from "@verbatra/sdk";
import { tomlAdapter } from "./toml-adapter.js";

const config = await loadConfig({ cwd: process.cwd() });
const adapterRegistry = createDefaultRegistry().register(tomlAdapter);

const summary = await translate({ config }, { adapterRegistry });

register devuelve el registro, así que los registros se encadenan. Rechaza un formato que el registro ya tiene con DUPLICATE_FORMAT y un identificador mal formado como custom:TOML con INVALID_FORMAT_ID, así que dos plugins con el mismo nombre fallan al arrancar.

Lanzar los errores adecuados

Un adaptador custom: se envuelve al registrarlo, así que un fallo inesperado suyo aparece como ADAPTER_FAILED, con tu formato y el método, en lugar de culpar a verbatra. El mensaje nunca repite el tuyo, que podría citar el archivo; lee tu error original desde cause.

Dos tipos de error pasan sin cambios:

  • Un AdapterError que lances tú conserva su código. Lanza INVALID_STRUCTURE para contenido que tu formato no puede representar.
  • Un error con un código errno como ENOENT lo conserva, así que un archivo que falta se sigue informando como tal. La comprobación solo mira la forma del error, así que no pongas un código errno en tus propios errores de validación.

En qué confías

Un adaptador de formato es código de plena confianza, al mismo nivel que cualquier paquete que instales. verbatra no lo aísla en ningún sandbox.

Un adaptador puede leer process.env, donde vive cada clave de proveedor, leer y escribir cualquier archivo al que acceda el proceso y abrir conexiones de red. El puerto fs es una convención, no una frontera.

El adaptador también decide qué cuenta como placeholder. Si no informa de ninguno, la comprobación de integridad de placeholders pasa siempre para su formato, y una traducción que destrozó una interpolación se publica sin aviso, tanto si el adaptador tiene un fallo como si es malicioso.

Lo que verbatra sí garantiza es que la carga nunca es implícita: no descubre plugins, no recorre directorios, no instala nada ni sigue convenciones de nombres. Un adaptador solo se ejecuta porque tu código lo importó y le entregó el registro a verbatra. Trátalo como cualquier dependencia que lee tus secretos: léelo, fija su versión y revisa cada actualización.

Relacionado

Editar en GitHub

En esta página