Saltar al contenido

Referencia

CLI

El comando verbaly vive en @verbaly/compiler. Añádelo a tus dependencias de desarrollo para que npx verbaly funcione: los gestores de paquetes solo enlazan un comando de un paquete que instalaste tú, y los plugins dependen del compilador sin instalártelo.

Comandos

14 comandos, en el orden en que los usa el ciclo. Cada uno lleva a su sección.

Scaffolding

verbaly init deja un proyecto montado en un comando. Te da una config tipada (.ts si tienes tsconfig, .mjs si no) y tus catálogos: el fuente, más uno por cada idioma que pases en --locales. Después te dice qué queda por conectar. Astro, Nuxt, Next.js, SvelteKit y Vite tienen su propia integración; cualquier otro bundler usa @verbaly/unplugin.

npx verbaly init --locales es,pt
  1. created: verbaly.config.ts, locales/en.json, locales/es.json, locales/pt.json
  2. detected: vite
  3. next steps: 1. pnpm add verbaly @verbaly/vite
  4. 2. add verbaly() to the plugins in vite.config

Re-ejecutarlo es seguro: una config o catálogo existente se reporta como “kept” y queda intacto.

Chequeo de salud

verbaly doctor es el hermano de init para proyectos ya andando: inspecciona todo el setup y reporta cada hallazgo con el comando exacto que lo arregla. Verde significa sano; los problemas salen con 1.

npx verbaly doctor
  1. Correcto config: verbaly.config.ts found
  2. Correcto catalogs: 3 locales (en, es, pt) in locales/
  3. Correcto plugin: @verbaly/vite installed for vite
  4. Aviso types: src/verbaly.d.ts is stale fix: run npx verbaly typegen
  5. Aviso orphans: 2 catalog keys are no longer referenced (old.title, hero.cta) fix: run npx verbaly extract --prune to drop them
  6. Aviso outdated: 1 translation written for an older source text (es: hero.title) fix: update them, or keep them with npx verbaly review --approve
  7. Error imports: 1 file imports t from a verbaly package, which never exports it (src/app.ts) fix: t comes from your instance (React: const t = useT()) or from virtual:verbaly
  8. Error translations: 1 broken translation (es): present but not rendering what the source renders fix: run npx verbaly check to read what each one lost

Un comando para responder a «¿por qué no se traduce esto?». Mira cuatro cosas.

Un informe limpio quiere decir que check también pasa. doctor falla en todo lo que falla check, más los fallos de montaje como ese import, y nunca en algo que construye y renderiza bien.

Envolver texto hardcodeado

verbaly wrap encuentra texto hardcodeado en tu JSX y lo envuelve en t`…` por ti. Primero informa, y --write aplica. Lo ambiguo se lista para un humano en vez de adivinarlo, y un fichero donde t no está disponible se deja intacto y se informa, así el proyecto siempre sigue compilando.

npx verbaly wrap           # report what it would wrap
npx verbaly wrap --write   # apply it

Pasar desde otra librería

verbaly migrate pasa los catálogos que ya tienes. Tu fichero conserva su forma, anidada o plana, y lo único que tiene que reescribir es la interpolación: {{name}} pasa a {name}, porque una llave doblada es como Verbaly escribe una llave literal. Primero reporta, y --write aplica.

npx verbaly migrate             # report what it would port
npx verbaly migrate --write     # apply it
npx verbaly migrate --plurals --write   # and merge _one/_other

--plurals es la mitad opcional: fusiona _one y _other en un solo mensaje con variantes, que es lo que da la selección de plural automática, y dentro el número se imprime ya localizado. También entiende la forma antigua key + key_plural. Sin el flag, esas keys siguen funcionando tal cual.

Lo que no va a adivinar te lo lista: un formato de i18next dentro de las llaves, un valor {{- sin escapar}}, un anidado con $t(), y una fusión que pisaría una key que ya usas. Esos mensajes se quedan exactamente como estaban.

Extracción

verbaly extract escanea tu código (.js/.ts/.jsx/.tsx, más .svelte, .vue y .astro), escribe los mensajes nuevos en el catálogo fuente, añade huecos "" al resto y regenera los tipos. Nombra cualquier archivo que no pudo parsear en vez de detenerse en él. Cada texto fuente que siguió a tu código recibe una línea con el texto que tenía antes, así una edición que hiciste en el código se lee como un cambio, y una hecha en el catálogo muestra lo que deshizo. Después avisa, con archivo y línea, de lo que si no pasaría desapercibido: una clave escrita con dos textos, un t con otro nombre, un mensaje que se quedó con un bloque plural o de formato como texto literal, y un valor que un traductor vería como {_0}. Con --watch, cada aviso se dice una vez, y otra solo si vuelve.

npx verbaly extract             # sync catalogs + types
npx verbaly extract --prune     # and drop keys nothing references
npx verbaly extract --dry-run   # say what it would change, write nothing

Generación de tipos

verbaly typegen escribe los tipos de TypeScript de tus mensajes y nada más, desde el texto que publica tu build, donde tu framework los lee: src/verbaly.d.ts en una app de Vite o SvelteKit, .verbaly/types.d.ts en Next.js, y la carpeta de tipos propia de Astro y de Nuxt. extract, los servidores de desarrollo y el build escriben el mismo fichero, así que solo lo necesitas donde ninguno corrió: un clon fresco, o un job de CI a punto de correr tsc.

npx verbaly typegen && tsc --noEmit   # a fresh clone, or CI

Cobertura

verbaly status muestra de un vistazo cuánto está traducido por idioma (es: 45/48 translated), cuántas traducciones automáticas siguen esperando revisión, cuántas están rotas y cuántas se escribieron para un texto fuente anterior. Es solo informativo y nunca falla; --json da los mismos números a badges y herramientas.

npx verbaly status          # es: 45/48 translated
npx verbaly status --json   # the same numbers, for badges and tooling

Pseudo-localización

verbaly pseudo llena un catálogo de QA (en-XA por defecto) desde el texto que publica tu build en el locale fuente: letras acentuadas, marcadores ⟦…⟧ y ~33% de padding. El texto que sale limpio en el build pseudo está hardcodeado; los layouts que se cortan se delatan antes de que llegue una traducción real.

npx verbaly pseudo                 # locales/en-XA.json
# "Hello {name}" → "⟦Ĥéĺĺó {name} ~⟧"

Params, bloques de variantes y tags sobreviven verbatim, garantizados por la misma validación estructural de translate. Re-ejecutar regenera el catálogo completo.

Traducción máquina

verbaly translate cierra el ciclo: escribir → extract → translate → check en verde. El provider por defecto usa Claude (@anthropic-ai/sdk como peer opcional + ANTHROPIC_API_KEY); batches de 20 por request, cada uno diciéndole al modelo en qué archivos fuente vive el texto, así traduce con contexto. Cualquier modelo actual de Claude funciona con translate.model o --model, y un batch que el modelo rechaza pasa a un modelo de respaldo en vez de volver sin traducir.

npx verbaly translate --dry-run        # list what's missing, write nothing
npx verbaly translate --locales es,pt  # fill only these locales
npx verbaly translate --model claude-opus-4-8  # override the default (claude-sonnet-5-5)

Cada traducción se verifica: los placeholders y las etiquetas deben sobrevivir intactos. Si uno no lo hace, la traducción se rechaza y la entrada queda en "", así que check la sigue marcando hasta arreglarla.

Sin lock-in: conecta tu propio provider en verbaly.config.ts. En TypeScript, TranslateProvider lo tipa por ti, y origins te dice en qué archivos del código aparece cada texto, así lo traduces para el sitio donde se usa:

verbaly.config.ts
import type { TranslateProvider } from '@verbaly/compiler';

const provider: TranslateProvider = async ({ sourceLocale, targetLocale, messages, origins }) => ({
  /* key → translation */
});

export default { translate: { provider } };

Revisa lo pendiente

La salida de la máquina es un borrador, no trabajo revisado. translate registra todo lo que escribe en verbaly.lock, junto a tu config (committeado con tus catálogos, jamás editado a mano), y verbaly review cierra el ciclo: lee los borradores y apruébalos. El mismo archivo recuerda para qué texto fuente se escribió cada traducción, desde el momento en que se escribe, así que cuando cambias un texto, sus traducciones también esperan en review, como desactualizadas: actualízalas, o apruébalas si siguen valiendo. Cada una aparece con el texto que se publica al lado de su traducción, para que la juzgues ahí mismo, y --approve seguido de claves acepta solo esas.

npx verbaly review               # each one with its source text and its translation
npx verbaly review hero.title --approve   # accept only the keys you name
npx verbaly review --approve     # accept everything after reading
npx verbaly check --drafts       # CI gate: fail while drafts remain
npx verbaly check --outdated     # and while a translation is older than its text

¿Quieres bloquear el merge hasta que un humano firme? Añade --drafts al check de tu CI: sigue fallando mientras queden traducciones a máquina sin revisar, y --outdated hace lo mismo con las traducciones escritas para un texto fuente anterior. Un archivo de traductor traído con import cuenta como revisión por sí solo.

Traductores y TMS

¿Humanos en el ciclo? verbaly export escribe archivos XLIFF 2.0, CSV o gettext PO por idioma listos para el traductor y verbaly import los trae de vuelta, validados estructuralmente con el mismo gate que translate. El flujo completo, opciones de TMS incluidas, vive en Trabajar con traductores.

verbaly import valida cada entrada, y rechaza e informa las rotas. Las entradas PO marcadas como fuzzy cuentan como sin traducir, y las claves importadas dejan de contar como borradores sin revisar, salvo que pases --draft para un archivo que nadie ha leído aún. El idioma de cada archivo se lee como uno de los tuyos, así que el pt_BR de gettext llena tu pt-BR. Un archivo de un idioma nuevo empieza su catálogo con el código bien escrito, salvo que tu config liste sus locales: entonces un idioma fuera de la lista se salta con un aviso y código de salida 1, porque tu app nunca lo cargaría.

Export también escribe recursos nativos de móvil: --format android-xml para la estructura res/ de Android y --format ios-strings para Xcode. Las keys sin traducir se omiten para que la app caiga a tu idioma fuente (--missing aplica solo a los formatos de traductor). Todos los formatos escriben en verbaly-export/ salvo que apuntes --out a otro sitio.

Qué revisa el gate

check hace cuatro preguntas. ¿Está traducido cada mensaje? ¿Existe cada clave que escribe el código? ¿Tiene cada clave un solo texto, para que ningún sitio muestre palabras escritas para otro? ¿Y puede cada traducción renderizar lo que renderiza su fuente? Una traducción rellena no es automáticamente una que funciona, así que estas también hacen fallar check, vengan de donde vengan: un traductor, una máquina o una edición a mano. Cada build lista los mismos problemas y termina, así que corre check en el CI.

La traducciónPor qué falla
perdió un {param}, o le cambió el nombreel valor nunca llega al texto
perdió un <em>, o ganó unoel énfasis o la marca del enlace desaparece
convirtió un bloque de plural en texto planouna sola redacción para cualquier cantidad
tiene un bloque de plural sin caso othercada cantidad que no lista se muestra vacía

Algunos hallazgos son advertencias: se imprimen y el código de salida sigue en 0, porque el texto igual se muestra.

Un build corre el mismo gate, y cuando encuentra advertencias imprime una sola línea que dice cuántas hay, y pasa.

Falle lo que falle, el informe termina diciéndote cómo arreglarlo: crear y rellenar un mensaje que todavía no tiene traducción, corregir la clave de uno que no vive en ningún catálogo, dar a cada texto su propia clave donde una clave tiene dos, o reparar el mensaje mismo cuando está roto.

Ejemplo de CI

.github/workflows/ci.yml
- run: pnpm install
- run: npx verbaly check --reporter github   # each finding becomes a PR annotation
- run: pnpm build

Con --reporter github, cada hallazgo aparece como anotación en la pull request, en el archivo y la línea donde vive el texto. Los errores llegan como errores y los avisos como avisos, así que un aviso nunca pone el job en rojo. Sin él tienes la lista de siempre, con el mismo código de salida.

Render estático (SSG)

verbaly render es lo que mata el parpadeo de texto sin traducir en un sitio estático. Recorre tu HTML construido y rellena cada elemento data-verbaly, una vez por idioma, usando el runtime de verdad: plurales, formato de Intl, data-verbaly-args, atributos y texto rico de la whitelist. Dentro de un idioma, los enlaces a páginas que ese idioma también tiene conservan su prefijo, así que quien llega se queda. Llevarlo hasta ahí es --redirect, aquí abajo.

npx vite build              # or astro build, eleventy, …
npx verbaly render          # dist/index.html filled in the source locale
                            # dist/es/index.html, dist/pt/… for the rest
npx verbaly render --site out --locales es  # custom dir / locale filter

Flags

FlagPor defectoDescripción
--rootcwdRaíz del proyecto
--dirlocalesDirectorio de catálogos
--sourceenIdioma fuente
--localesde los archivosSolo estos idiomas, siempre con el fuente incluido (en init: los que crea)
--pruneoffElimina claves sin referencias (solo extract)
--watchoffRe-extrae cuando cambian los archivos fuente: extracción viva para setups con webpack, Rspack y Rollup (solo extract)
--localeen-XAId del pseudo-locale (solo pseudo)
--sitedistDirectorio del sitio compilado (solo render)
--baseraíz del sitioSubruta bajo la que se sirve el sitio (solo render)
--redirectoffManda a su idioma a quien llega a la página de inicio (solo render)

Las flags se validan por comando: una flag que pertenece a otro comando termina con un error accionable en vez de ignorarse en silencio: translate --locale es te dice que querías --locales.

Archivo de config

Los flags ganan sobre verbaly.config.{js,mjs,ts,mts,json} en la raíz del proyecto, y el plugin toma las mismas opciones. Todas ellas, con su valor por defecto, viven en Configuración.

Agentes de código

Tu agente de código puede correr este mismo ciclo sin tocar la terminal, a través del servidor @verbaly/mcp. Ese canal tiene página propia. Agentes de código cubre el servidor, sus herramientas y recursos, la Agent Skill instalable y el índice llms.txt que sirve este sitio.

↑↓para moverteEnterpara abrir
Copiado en el portapapeles