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

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

Scaffolding

verbaly init deja el proyecto listo en un comando: una config tipada (.ts si tienes tsconfig, .mjs si no), tu catálogo fuente más uno por cada --locales, y los siguientes pasos según lo que encuentre: Astro, Nuxt, Next.js, SvelteKit y Vite tienen cada uno su integración, y 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: pnpm add -D @verbaly/vite

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: verbaly.d.ts is stale fix: run npx verbaly extract
  5. Aviso orphans: 2 catalog keys are no longer referenced (old.title, hero.cta) fix: run npx verbaly extract --prune to drop them
  6. 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
  7. 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 “¿por qué esto no se traduce?” Revisa tu config y tus catálogos, si está instalada la integración que tu framework necesita, si verbaly.d.ts está al día, las keys huérfanas y la salud de tus traducciones: las que faltan, las rotas y los avisos. También caza dos cosas que el gate del build no puede ver: t importado de un paquete de verbaly, que ningún bundler resuelve, y un mensaje que se quedó con un bloque plural o de formato como texto literal. También nombra cualquier archivo que no pudo parsear, como aviso: sus textos no se extraen, pero el archivo puede compilar igual en tu proyecto. Un reporte sano significa un build que pasa: doctor falla en todo lo que falla check, más fallos de setup como esos dos, y jamás en algo que compila y renderiza.

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 verbaly.d.ts. Avisa cuando un mensaje se quedó con un bloque plural o de formato como texto literal, y nombra cualquier archivo que no pudo parsear en vez de detenerse en él.

npx verbaly extract           # sync catalogs + types
npx verbaly extract --prune   # and drop keys nothing references

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 y cuántas están rotas. 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 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 → extracttranslatecheck 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.

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)

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 los borradores

La salida de la máquina es un borrador, no trabajo revisado. translate registra todo lo que escribe en locales/.verbaly-drafts.json (committeado con tus catálogos, jamás editado a mano), y verbaly review cierra el ciclo: lee los borradores y apruébalos.

npx verbaly review               # es: x7Ka9q2f, hero.title (2 awaiting review)
npx verbaly review --approve     # accept after reading
npx verbaly check --drafts       # CI gate: fail while drafts remain

¿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. 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.

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 dos preguntas, no una. ¿Está traducido cada mensaje? ¿Y puede cada traducción mostrar lo que muestra el original? Una traducción llena no es automáticamente una que funciona, así que esto también detiene el build, venga de donde venga: de una persona, de una máquina o de una edición a mano.

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

Dos hallazgos son advertencias: se imprimen, el código de salida sigue en 0, porque el texto igual se muestra. Uno es un plural al que le faltan formas que el idioma necesita, porque el polaco y el árabe piden más que el inglés. El otro es un caso puntual como =0 que el original tenía y la traducción dejó afuera, así que esa cantidad ahora cae en other.

Falle lo que falle, el reporte cierra con el paso que repara ese fallo: generar y rellenar cuando a un mensaje aún le falta la traducción, corregir la key cuando esa key no vive en ningún catálogo, y arreglar 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 el pull request, apuntando al archivo y la línea donde vive el texto: los errores como errores, las advertencias como advertencias, así que una advertencia nunca pone el job en rojo. Sin eso obtienes la lista en texto plano, con el mismo código de salida.

Render estático (SSG)

verbaly render mata el parpadeo de texto sin traducir en sitios estáticos: recorre tu HTML construido y rellena cada elemento data-verbaly por idioma usando el runtime de verdad: plurales, formato con Intl, data-verbaly-args, traducción de 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 ahí se queda ahí. Llevarlo hasta ahí es --redirect, más 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

FlagDefaultDescripción
--rootcwdRaíz del proyecto
--dirlocalesDirectorio de catálogos
--sourceenIdioma fuente
--localesde los archivosIdiomas extra, separados por coma
--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