Guías
CLI
El binario verbaly viene con @verbaly/compiler (dependencia del plugin de Vite), así que npx verbaly funciona directo.
Comandos
| Comando | Qué hace |
|---|---|
| verbaly init | Genera config + catálogos de locales y sugiere el plugin correcto para tu bundler |
| verbaly doctor | Diagnostica el setup (config, catálogos, cableado del plugin, tipos desactualizados, keys huérfanas) y te dice el fix exacto de cada hallazgo |
| verbaly extract | Escanea las fuentes (.js/.ts/.jsx/.tsx, y .svelte/.vue desde 0.20.0), escribe los mensajes nuevos al catálogo fuente, agrega placeholders "" al resto y regenera verbaly.d.ts |
| verbaly status | Muestra la cobertura de traducción por idioma de un vistazo (es: 45/48 translated), solo informativo, nunca falla |
| verbaly check | Verifica que cada clave tenga traducción en cada idioma. Sale con 1 ante claves faltantes o desconocidas, hecho para CI |
| verbaly translate | Llena los huecos "" que check reporta vía un provider de traducción, Claude por defecto |
| verbaly export | Escribe archivos XLIFF 2.0 o CSV por idioma listos para el traductor, o recursos nativos de Android e iOS para una app móvil hermana |
| verbaly import | Rellena los catálogos desde archivos XLIFF/CSV traducidos, con cada entrada validada estructuralmente y las rotas rechazadas y reportadas |
| verbaly pseudo | Genera un catálogo pseudo-locale de QA (en-XA) desde el fuente, exponiendo strings hardcodeados y layouts que se cortan |
| verbaly render | Pre-llena el HTML data-verbaly por locale en tu sitio compilado, así que las páginas estáticas salen ya traducidas |
Scaffolding
verbaly init deja un 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 pasos siguientes para tu bundler: Vite → @verbaly/vite, el resto → @verbaly/unplugin.
npx verbaly init --locales es,pt
# created: verbaly.config.ts, locales/en.json, locales/es.json, locales/pt.json
# detected bundler: vite → pnpm add -D @verbaly/viteRe-ejecutarlo es seguro: una config o catálogo existente se reporta como “kept” y queda intacto.
Chequeo de salud
verbaly doctor (0.13.0) 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
# ✓ config: verbaly.config.ts found
# ✓ catalogs: 3 locales (en, es, pt) in locales/
# ⚠ types: verbaly.d.ts is stale
# fix: run `npx verbaly extract`
# ⚠ orphans: 2 catalog keys are no longer referenced (old.title, hero.cta)
# fix: run `npx verbaly extract --prune` to drop them
# ✗ keys: 1 unknown key used in code (ghost.key)Un comando para responder “¿por qué no traduce esto?” Revisa tu config, tus catálogos y el cableado del plugin, si verbaly.d.ts está al día, y cualquier key huérfana o faltante.
Claves legibles
Las claves hasheadas son el default sin config. Cuando quieras ids legibles, agrupados con namespaces de puntos, opta por mensaje con t.id:
t.id('inbox.title')`Hello ${name}`;
// extracted under "inbox.title" and rewritten to:
t('inbox.title', { name });Los catálogos siguen siendo JSON plano. Los puntos son solo una convención de nombres. Los ids dinámicos (t.id(someVar)) no se tocan, y los ids duplicados con textos distintos disparan el warning de colisión de claves.
Flags
| Flag | Default | Descripción |
|---|---|---|
| --root | cwd | Raíz del proyecto |
| --dir | locales | Directorio de catálogos |
| --source | en | Idioma fuente |
| --locales | de los archivos | Idiomas extra, separados por coma |
| --prune | off | Elimina claves sin referencias (solo extract) |
| --watch | off | Re-extrae cuando cambian los archivos fuente: extracción viva para setups con webpack, Rspack y Rollup (solo extract, 0.23.0) |
| --locale | en-XA | Id del pseudo-locale (solo pseudo) |
| --site | dist | Directorio del sitio compilado (solo render) |
Desde 0.17.0 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.
Traducción máquina
verbaly translate (0.9.0) 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.
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:
export default {
translate: {
provider: async ({ sourceLocale, targetLocale, messages }) => ({ /* key → translation */ }),
},
};Traductores y TMS
¿Humanos en el ciclo? verbaly export (0.15.0) escribe archivos XLIFF 2.0 o CSV 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.
Desde 0.22.0, export también escribe recursos nativos mobile: --format android-xml para el layout res/ de Android y --format ios-strings para Xcode. Las claves sin traducir se omiten para que la app haga fallback a tu idioma fuente (--missing aplica solo a los formatos de traductor).
Render estático (SSG)
verbaly render (0.10.0) mata el flash de contenido sin traducir en sitios estáticos: recorre tu HTML compilado y pre-llena cada elemento data-verbaly por locale con el runtime real: plurales, formato Intl, data-verbaly-args, traducción de atributos y rich text con whitelist.
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- Cada copia recibe su
<html lang>; el locale fuente se llena in-place y el resto se espeja adist/<locale>/…. - Los atributos
data-verbalyquedan en el output, así que el cambio de idioma client-side sigue funcionando sobre la página pre-renderizada. - Los mensajes se escapan como HTML (nunca se inyectan), las keys faltantes se reportan y no se tocan, y re-ejecutar es idempotente.
- Links nombrados (
0.11.0): definerender.linksenverbaly.config.*(odata-verbaly-linkspor elemento) y los mensajes rich pre-renderizan elementos<a href>reales, atributos escapados, conjavascript:bloqueado. - SEO multi-idioma (
0.14.0): definerender.baseUrly cada página recibe alternateshreflangrecíprocos;--sitemapescribe un sitemap i18n y--cleanelimina páginas de locale obsoletas. - Espejos self-canonical (
0.14.5):rel="canonical"yog:urlse reescriben a la URL propia de cada idioma, porque un canonical cruzado haría que los buscadores ignoren el hreflang.
Pseudo-localización
verbaly pseudo (0.10.0) 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.
Archivo de config
Los flags ganan sobre verbaly.config.{js,mjs,ts,mts,json} en la raíz del proyecto (los configs TS necesitan esbuild instalado). Mismas opciones que el plugin de Vite, una sola fuente de verdad:
export default {
sourceLocale: 'es',
locales: ['es', 'en', 'pt'],
dir: 'locales',
};Ejemplo de CI
- run: pnpm install
- run: npx verbaly check # fails the job on missing translations
- run: pnpm build