Saltar al contenido

Novedades

0.72.0

Última versión

Instalar con pnpm funciona a la primera

Verbaly deja de traer esbuild a tu proyecto, lo que hacía fallar pnpm add por un script de build que nadie pidió. verbaly.lock se une solo después de que dos ramas traduzcan en paralelo, <br> funciona lo escribas como lo escribas, y un visitante recibe el idioma que lee aunque tu lista solo tenga una variante cercana. Breaking: Verbaly ahora necesita Node 22.12 o más reciente.

Destacados
  • Instalar con pnpm funciona a la primera. Verbaly ya no trae esbuild, así que pnpm add @verbaly/vite deja de fallar por un script de build que nunca pediste, y la instalación pesa unos 12 MB menos. Un verbaly.config.ts sigue funcionando, y también sus imports escritos sin extensión.
  • Un merge ya no rompe verbaly.lock. Cuando dos ramas tradujeron en paralelo, Verbaly lee los dos lados del conflicto, conserva todos los borradores de cada lado, y el siguiente extract escribe el archivo entero. Añádelo al commit que resuelve el merge.
  • <br> funciona lo escribas como lo escribas. <br>, <br/> y <br /> son todos saltos de línea en los mensajes rich, en los archivos que mandas a traducir y en verbaly check. Antes, <br> desaparecía y <br /> salía como texto.
  • Cada visitante recibe el idioma que lee. Un navegador o una request en zh-HK ahora recibe tu chino tradicional, y pt o pt-PT recibe tu pt-BR, en vez de caer al inglés.
  • Builds más rápidos. El plugin de Vite y @verbaly/unplugin leen cada archivo una vez en lugar de dos.
  • Breaking: Node 22.12 o más reciente. Node 20 llegó al fin de su vida en abril de 2026, y los frameworks que Verbaly soporta ya piden Node 22.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.71.0

Versión

El estado de tus traducciones tiene su lockfile

Lo que Verbaly recuerda de tus traducciones (para qué texto fuente se hizo cada una y cuáles son borradores) sale de tu carpeta de catálogos hacia verbaly.lock, junto a tu config, y se muda solo. Una clave escrita con dos textos distintos ahora hace fallar verbaly check, porque uno de sus sitios muestra el texto del otro. Breaking: un proyecto con una clave así ve fallar check y doctor, y failOnMissing: true para el build por ella.

Destacados
  • Tu carpeta de catálogos tiene solo tus catálogos. Lo que Verbaly recuerda de tus traducciones ahora vive en verbaly.lock, junto a verbaly.config.ts. Trátalo como el lockfile de un gestor de paquetes: Verbaly lo escribe, tú lo committeas y nadie lo edita.
  • El archivo viejo se muda solo. El siguiente extract o arranque del servidor de dev mueve .verbaly-state.json a verbaly.lock y lo dice una vez. No hay nada que configurar.
  • Breaking: una clave con dos textos hace fallar verbaly check. Cuando t.id('title') se escribe dos veces con palabras distintas, un sitio muestra el texto del otro. Cada build ahora la lista junto a las traducciones rotas, y check se para en ella, nombrando los dos sitios.
  • Cosas pequeñas: el primer ejemplo del README muestra la clave que el compilador escribe de verdad, y el repositorio tiene un AGENTS.md para quien contribuye y sus agentes de código.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.70.0

Versión

Un texto nunca para tu build

Una traducción que falta o está rota, o una clave que ningún catálogo tiene, ahora aparece al final de cada build, y el build termina: lo que para una versión es verbaly check en tu CI. Para probar la entrada, pasamos Memos, una app de código abierto con 46 idiomas, de react-i18next a Verbaly y arreglamos todo lo que encontró. Breaking: el build ya no se para solo, y una clave escrita entre comillas invertidas que ningún catálogo tiene ahora hace fallar check.

Destacados
  • Un texto nunca para tu build. Cada build lista lo que falta o está roto, primero las traducciones rotas, y termina. El control es npx verbaly check, en tu CI. Breaking: para que el build siga fallando, pon failOnMissing: true en las opciones del plugin.
  • Probado en una migración real. Pasamos Memos (46 idiomas, 879 claves) de react-i18next a Verbaly: 20 archivos cambiados a mano, el mismo build y los mismos tests en verde, y unos 11 KB menos para cada visitante. init ahora conserva los catálogos que ya tienes, y migrate deja texto como {timestamp} como texto y nunca convierte un idioma dos veces.
  • Builds más rápidos con Vite. El plugin de Vite frenaba los builds grandes: Memos tardaba 37 segundos en compilar, y ahora tarda 17 (13 sin Verbaly).
  • Sin provider en el navegador. En una app de una sola página y en los tests de componentes, useT() funciona sin <VerbalyProvider>, el plugin de Vue ni provideVerbaly, como en react-i18next.
  • Menos errores de tipos al migrar. Una clave guardada en una variable tipada como un conjunto de claves pasa con sus parámetros, y los tipos generados ya no molestan a Biome ni a Prettier.
  • Cosas pequeñas: doctor dice "setup works, with 1 warning to read" en vez de "healthy" después de un aviso, y el servidor MCP vuelve a leer un config CommonJS. Breaking: una clave escrita entre comillas invertidas, o como {'…'} en JSX, se comprueba como una entre comillas.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.69.1

Versión

Las claves que vienen de datos vuelven a compilar

La 0.69.0 tipó cada t, y con ello rechazó cualquier clave guardada en un string cualquiera, así que el código que lee sus claves de datos, y cada migración desde otra librería, empezaba lleno de errores. Ahora una clave que escribes a mano se sigue comprobando contra tu catálogo, con sus params, y una clave que viene de datos compila tal cual. No hay nada que cambiar en tu código.

Destacados
  • Las claves que vienen de datos vuelven a compilar. t(item.key) y t(`status.${s}`) funcionan en cada t sin cast, mientras que una clave que escribes a mano se sigue comprobando contra tu catálogo, params incluidos, y tu editor la sigue completando.
  • La misma regla para una instancia que construyes tú. En createVerbaly({ messages }), una errata nombra ahora la clave que falló, y una clave que viene de datos también pasa ahí.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.69.0

Versión

Cada t conoce tus claves

Cada t de tu proyecto comprueba ahora sus claves contra tu catálogo, y los tipos generados quedan donde tu framework ya los lee. Esta versión arregla lo que una auditoría de la 0.68.0 encontró en lo primero que tocas: los tipos, el servidor de Next.js, las líneas de instalación y el cambio de idioma. Next.js gana además traducciones sin petición y texto enriquecido en Server Components. Breaking, solo en tipos: una clave guardada en un string cualquiera ya no compila.

Destacados
  • Claves tipadas en cada t. useT() en React, Vue y Svelte, getT() en Next.js y el t de cualquier instancia comprueban cada clave y sus params contra tu catálogo. Una errata hace fallar tsc, y el error nombra la clave. Breaking: una clave guardada en un string cualquiera ya no compila: declárala con defineKeys, o márcala as VerbalyKey.
  • Los tipos se escriben donde mira tu framework. src/verbaly.d.ts en apps de Vite y SvelteKit, .verbaly/types.d.ts en Next.js (Verbaly lo añade a tu tsconfig.json), y las carpetas que Astro y Nuxt reservan para esto. La CLI y el servidor de desarrollo escriben el mismo fichero, el viejo de la raíz se va solo, y npx verbaly typegen los escribe en CI.
  • Next.js: traducciones sin petición, y texto enriquecido en el servidor. getT({ locale: 'es' }) funciona en una imagen OG, un sitemap o un email y deja la ruta estática, y <Trans> se pinta en Server Components desde @verbaly/next/server.
  • El texto que Verbaly no ve ya no calla. Cuando arranca un build o un servidor de desarrollo, Verbaly nombra cada fichero fuera de tu include que escribe t`…`, como components/ en una app de Next.js sin src/, con el patrón que hay que añadir. doctor también los lista.
  • Cambiar de idioma conserva el resto de la dirección. switchLocale conserva el ?q= y el #anchor.
  • Detalles que antes molestaban: init y doctor imprimen la línea de instalación del README con tu propio gestor de paquetes, un catálogo con saltos de línea de Windows ya no se reescribe cuando nada cambió, y el servidor MCP ve un verbaly.config.mjs editado sin reiniciarse.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.68.0

Versión

Las promesas se cumplen en todas partes

La 0.67.0 prometió que nada cambia a tus espaldas. Una auditoría encontró los sitios donde eso todavía fallaba, y esta versión los cierra de raíz. Una traducción desactualizada se detecta la escriba quien la escriba, cada comando lee el texto que de verdad se publica, una clave muestra siempre las mismas palabras, nada del estado de revisión se pierde en silencio, y los servidores de desarrollo dicen lo importante una vez. Nada nuevo rompe tu build.

Destacados
  • Una traducción desactualizada se detecta la escriba quien la escriba. translate, import, Studio y el verbaly_write_drafts de un agente registran para qué texto fuente se escribió una traducción en el momento en que la escriben, e import lo toma del archivo del traductor. Un texto fuente que cambia antes del siguiente extract, o un archivo hecho para un texto anterior, queda marcado en vez de aceptarse en silencio.
  • Cada comando lee el texto que se publica. check --outdated, status, review, translate, export, import, Studio y el servidor MCP leen el texto de tu código allí donde el código es su dueño, así que el CI ya no deja pasar una traducción que el build publica junto a un texto más nuevo.
  • Una clave, las mismas palabras en todas partes. Cuando una clave tiene dos textos, gana el que se escribió primero por ruta de archivo, en extract, en cada build y en los dos servidores de desarrollo. Antes dependía del orden en que se leían los archivos, que cambiaba de una ejecución a otra.
  • Nada del estado de revisión se pierde en silencio. extract --locales es deja en paz los demás idiomas, el archivo de borradores viejo de un compañero se fusiona en vez de descartarse, y un archivo de estado ilegible detiene los comandos que escriben borradores antes de que escriban nada.
  • --prune conserva las traducciones que lee un t con otro nombre, también en archivos .vue, .svelte y .astro, y ahora el aviso aparece ahí.
  • Los servidores de desarrollo dicen lo importante, una vez. Vite dev nunca devuelve un texto viejo encima de un checkout, un catálogo guardado a medio escribir es una pausa de una línea en los dos servidores, y un aviso vuelve si su problema vuelve.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.67.0

Versión

Nada cambia a tus espaldas

Verbaly deja de esconderte cosas. Una traducción escrita para un texto que ya cambió queda marcada, dos textos con la misma clave se reportan con los dos sitios, y dev y build muestran siempre las mismas palabras. En Next.js, next typegen ya no se detiene por traducciones que faltan, y los agentes pueden guardar sus propias traducciones como borradores. Nada nuevo rompe tu build.

Destacados
  • Las traducciones desactualizadas quedan marcadas. Cambia un texto fuente y las traducciones escritas para el anterior aparecen en status, check y doctor hasta que alguien las actualice o las mantenga con verbaly review --approve. check --outdated puede hacer que eso falle en tu CI.
  • Dev y build muestran siempre el mismo texto. Un texto escrito en tu código gana a una edición a mano del catálogo, en dev y en el build por igual, y Verbaly te dice dónde vive ese texto en lugar de reemplazar tu edición sin avisar.
  • Dos textos con la misma clave se reportan, con los dos sitios. Antes el segundo desaparecía sin aviso.
  • next typegen funciona aunque falten traducciones. El gate de Next.js ahora corre cuando el build ya compiló, no al cargar la config, y next experimental-analyze ya no necesita un next dev antes.
  • extract --prune también limpia los borradores, y los agentes guardan sus propias traducciones como borradores con la nueva herramienta MCP verbaly_write_drafts, así nadie edita a mano el archivo de borradores. Ese archivo ahora es .verbaly-state.json, y el antiguo se migra solo.
  • En React, useT() te da un t nuevo cuando cambia el idioma, así useMemo(…, [t]) lo sigue.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.66.0

Versión

Ninguna traducción se pierde en silencio

Un archivo con un error ya no deja que extract --prune borre traducciones, las claves con nombres como toString o constructor ya no tumban el gate, y la traducción automática funciona con cualquier modelo actual de Claude, con Sonnet 5.5 por defecto. Next.js deja de descargar un catálogo dos veces, y tu build ahora dice en una línea cuándo check tiene advertencias. Nada nuevo hace fallar tu build.

Destacados
  • extract --prune ya no borra una traducción porque un archivo tenga un error. Mientras algún archivo fuente no se pueda leer, prune espera y nombra el archivo. Antes, cada clave que solo usaba ese archivo perdía su traducción en todos los idiomas.
  • Las claves con nombres como toString o constructor ya no pueden tumbar check, doctor ni tu build. Una traducción que llevaba una paraba el gate con un error sobre matchAll. Ahora es una clave como cualquier otra.
  • La traducción automática usa Claude Sonnet 5.5 por defecto, y funciona con cualquier modelo actual de Claude. Elegir Sonnet 5.5 u Opus 5.5 con --model hacía fallar cada batch. Un batch que el modelo rechaza ahora pasa a un modelo de respaldo en vez de volver sin traducir.
  • Next.js descarga cada catálogo una sola vez. La página ya no vuelve a pedir el catálogo que el servidor ya mandó, y el build solo reescribe los archivos que lee verbaly extract.
  • Tu build ahora avisa cuando check tiene advertencias, en una sola línea, y sigue pasando.
  • El árabe o el hebreo escritos como ar_EG o he_IL se leen de derecha a izquierda, y un almacenamiento del navegador lleno ya no bloquea un cambio de idioma.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.65.0

Versión

Tu trabajo más seguro, páginas más firmes

La traducción automática ya no pisa un mensaje que arreglaste mientras corría, los nombres que los objetos de JavaScript ya traen no pueden romper una página, y un idioma escrito como pt_BR deja de romper números y fechas. Tres problemas que pasaban desapercibidos ahora traen un aviso, y ninguno hace fallar tu build. Si usas mensajes ICU con TypeScript, sus parámetros ahora tienen tipo, así que una llamada que los omitía aparece como error de tipos.

Destacados
  • La traducción automática nunca pisa tu trabajo. Si arreglas un mensaje mientras verbaly translate, Studio o un agente están traduciendo, tu texto se queda, y la ejecución te dice cuántos respetó.
  • Los nombres que los objetos de JavaScript ya tienen ya no pueden romper una página. Un idioma, un formato, una etiqueta rich o un grupo del catálogo llamado constructor, toString o __proto__ podía tumbar un render o convertirse en un enlace vacío. Ahora es un nombre como cualquier otro.
  • Un idioma escrito como pt_BR ya no rompe números, fechas y plurales. Lo leen como pt-BR y lo dicen una vez. doctor lo señala, init lo escribe bien, e import llena tu pt-BR desde un archivo pt_BR de gettext.
  • Tres problemas silenciosos ahora traen un aviso, y ninguno hace fallar tu build: una clave que solo tiene una traducción (Studio también la muestra en su resumen), un nombre de idioma que el navegador no sabe leer, y una app de Next.js cuyas URLs llevan el idioma mientras su config dice que no.
  • En Next.js, cambiar de idioma sigue a tus URLs. Con routing: 'prefix-all' en tu config, useSwitchLocale() va a la misma página en el idioma nuevo, sin opciones que pasar.
  • Vigilar cambios en Linux pesa mucho menos. next dev y verbaly extract --watch dejan de recorrer node_modules, que podía agotar el límite de archivos vigilados del sistema antes de llegar a tu código.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.64.0

Versión

Un parámetro malo deja de tumbar el render

Un parámetro que JavaScript se niega a convertir en texto hacía que Verbaly lanzara, y el camino que debía absorberlo lanzaba también. Ahora el mensaje se pinta sin él y Verbaly lo dice una vez.

Destacados
  • Un parámetro malo ya no puede tumbar un render. Si un valor no se puede convertir en texto, el mensaje se pinta sin él y Verbaly lo avisa una vez, igual que hace con cualquier otro valor malo.
  • Esa forma te la da JSON gratis. Un payload con un campo llamado toString que contiene un objeto es JSON válido, así que un CMS o un catálogo cargado en caliente podía traerlo hasta tu página.
  • Nada cambia en un proyecto que estaba bien. La comprobación solo corre donde un parámetro ya era inservible.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.63.0

Versión

Un menú en cada fila

Cada fila de mensaje en Studio tiene ahora su menú. Copia la clave, copia el texto original, edita ahí mismo, mira qué ficheros usan un mensaje, y mira el commit que lo cambió por última vez, que es lo único que el panel nunca había sabido contestar.

Destacados
  • Cada fila de mensaje tiene su menú. Copia su clave, copia el texto original o empieza a editar, sin salir de la tabla.
  • Mira el commit que cambió un mensaje por última vez. Studio lee el historial de tus catálogos y te dice el commit, quién lo escribió y qué decía. Al pulsarlo se copia el sha corto, así que un git show en tu terminal queda a un pegado.
  • Mira qué ficheros usan un mensaje, desde la propia fila. Cuando es más de uno te dice cuántos, y se despliega en la lista entera.
  • Cuando no hay respuesta, el menú dice de qué tipo es ese no. Un mensaje que aún no has commiteado, uno más viejo que el historial que Studio leyó, y un proyecto sin git son tres cosas distintas, y se leen como tres cosas distintas.
  • En el menú no hay ningún botón que no haga nada. La entrada de IA que pide el diseño no está, porque el asistente al que llamaría todavía no existe.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.62.0

Versión

El idioma que acabas de traducir

Marca un solo idioma y Studio deja de comparar. Te dice que el trabajo ya salió y que nada está roto, y pone arriba los pocos que merecen una lectura, con el motivo escrito al lado de cada uno.

Destacados
  • Marcas un idioma y tienes ese idioma. Una barra sobre la tabla dice cuántos mensajes tiene, que ya salen en tu web, y que la comprobación que corre tu build pasa. La tranquilidad va primero porque es la parte cierta.
  • Cada fila que merece un vistazo dice por qué, con palabras, justo al lado. No que cambió un enlace, sino cuál. No que se movieron los números, sino que el fuente dice 20 y este dice 22.
  • Das por bueno un idioma entero con un clic, y se deshace. No hay diálogo de confirmación, porque sigues editando en la fila y el deshacer te espera en el raíl.
  • Un idioma en el raíl enseña todo lo que queda, no solo lo peor. Antes leías una rompe tu web para un idioma al que además le faltaba una, así que la segunda no se veía.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.61.0

Versión

Tres comprobaciones que no eran tan estrictas como parecían

Una revisión de la propia red de seguridad de Verbaly encontró tres cosas que prometía y no cumplía del todo: una comprobación de URL que el navegador se salta sin enterarse, una búsqueda de mensaje que podía responder con algo que no es un mensaje, y formatos de número que imprimen NaN sin decir nada. Las tres están cerradas.

Destacados
  • Un enlace que viene de tu catálogo ya no puede colar una URL javascript: en tu página. La comprobación leía el texto tal cual, y el navegador borra tabulaciones y saltos de línea de una URL antes de leerla, así que un enlace podía pasar. Ahora se comprueba como la lee el navegador.
  • Un mensaje que se llama toString o constructor falta, no está vacío. Esos nombres son de cualquier objeto de JavaScript, así que la búsqueda encontraba el del objeto en vez del tuyo, y te devolvía una cadena vacía sin decir nada.
  • Un formato de número al que le llega algo que no es un número lo dice. Un precio con un valor de texto pintaba NaN, y un precio sin valor pintaba un 0,00 con toda confianza. Los dos enseñan ahora el valor tal cual y nombran el mensaje del que salieron.
  • Nada cambia en cómo escribes tus mensajes. Todo esto solo corre cuando algo ya va mal, así que un proyecto que estaba bien se queda exactamente igual.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.60.0

Versión

Un catálogo por el que puedes moverte

El buscador solo miraba los idiomas que tenías marcados, así que una palabra española con español sin marcar no encontraba nada y nunca decía por qué. Y los grupos que tus claves ya declaran no estaban en ninguna pantalla. Los dos están arreglados, y funcionan juntos.

Destacados
  • El buscador encuentra una palabra en cualquier idioma, no solo en los que marcaste. Antes el campo filtraba la tabla, así que solo veía lo que la tabla enseñaba. Ahora lee tu catálogo entero.
  • Cada resultado dice en qué idioma lo encontró. Eso es justo lo que una tabla filtrada no puede decirte: la misma palabra suele existir en uno solo de tus idiomas.
  • Command K lo abre, las flechas mueven, enter te lleva al mensaje. Baja hasta la fila esté donde esté, aunque quede muy por debajo de lo que la pantalla había cargado.
  • Tus claves ya tenían grupos, y ahora el panel los enseña. Eliges uno en el raíl y la tabla, sus cuentas y los comandos se estrechan a él. Un resultado de búsqueda dice en qué grupo vive.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.59.0

Versión

Studio abre por lo que te necesita

Antes abría en la tabla, sin decirte cuáles de tus mensajes estaban esperando ni si tu proyecto estaba sano. Ahora la primera pantalla te lo dice, y lo último que enseña es real: los commits que tocaron tus catálogos.

Destacados
  • Studio abre en un resumen, no en una tabla. Lo que te está esperando, una línea cada cosa con su propio botón, y si el proyecto está sano. Pulsar una te lleva exactamente a esos mensajes.
  • Los últimos cambios de tus catálogos, desde git. Commits de verdad sobre tu directorio de catálogos, con quién y cuándo. Un proyecto sin git simplemente no enseña la tarjeta, en vez de enseñarla vacía.
  • Una clave que tu código llama y que ningún catálogo define por fin se ve. Ya hacía fallar tu build, y hasta ahora el único sitio donde podías verla era la línea de comandos.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.58.0

Versión

Tu catálogo conserva el orden en el que lo escribiste

Dos sitios donde Verbaly hacía en silencio algo distinto de lo que decía. Reescribía tu catálogo en orden alfabético sin mencionarlo, y te decía que una traducción estaba comprobada sin haber mirado nunca dentro de un mensaje ICU. Los dos están arreglados en su origen.

Destacados
  • Tu catálogo conserva el orden en el que lo escribiste. Todo lo que escribía un catálogo reordenaba el fichero entero alfabéticamente, así que el primer guardado convertía un fichero ordenado a mano en un diff de todas sus líneas. En el catálogo de este mismo sitio eran 1817 de 1823 líneas, y ahora son cero.
  • Las comprobaciones por fin miran dentro de un mensaje ICU. Una traducción que aplanaba un plural ICU a texto plano, o que le quitaba un parámetro, salía limpia. Ahora se caza, en verbaly check, en lo que puede devolver una traducción de máquina y en lo que puede traer un fichero importado.
  • El preview en vivo de Studio dice lo mismo que dice el build, ICU incluido. Antes se ponía verde sobre un mensaje que el servidor luego rechazaba.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.57.0

Versión

Studio vuelve a ser un comando

Hace tres versiones Studio era una sola cosa que ejecutas. Luego ganó tres puntos de entrada, un peer opcional y un capítulo de su README sobre pintar el panel a mano, y todo eso existía para que una página de este sitio pudiera importarlo. Ya no está, y lo que instalas vuelve a ser un comando.

Destacados
  • Instalas @verbaly/studio y no hay nada que importar. Un comando, ningún peer que añadir, y ningún .svelte que tenga que compilar tu bundler. El paquete vuelve a tener una sola entrada.
  • Ruptura: se quitan tres puntos de entrada, y svelte deja de ser una dependencia peer. Salieron en la 0.56.0 y tenían un solo consumidor en el mundo, la página de demo de este sitio.
  • Nada cambió en cómo se ejecuta Studio. npx verbaly-studio abre la misma pantalla, sobre los mismos ficheros, con los mismos comandos.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.56.1

Versión

La pantalla cuando no hay nada en ella

Studio abría sobre un proyecto todavía sin configurar y te decía que marcaras un idioma que no existía. Ahora cada pantalla vacía y cada botón apagado dice lo que de verdad pasa, que es la parte de levantarlo que una persona realmente lee.

Destacados
  • La tabla vacía dejó de pedir lo imposible. Con un solo idioma en tu config no hay nada que marcar, así que te dice que tienes un idioma y dónde añadir el siguiente.
  • Cuatro pantallas vacías, una frase cada una: sin catálogos, un solo idioma, ninguno marcado, y un filtro que no encontró nada. Cada una nombra un hecho, no un botón.
  • Un comando que no puede correr está apagado, y dice por qué. Con el escaneo de código desactivado en tu config, Buscar texto nuevo ya no espera a que lo pulses para devolverte un error.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.56.0

Versión

El panel dejó de pedir sus propios datos

A Studio se le entrega aquello con lo que habla en vez de ir a buscarlo, y eso es lo que convierte el panel de una página que sirve el comando en algo que puedes poner en la tuya. Y por fin abre en oscuro en una máquina oscura.

Destacados
  • El panel abre en el tema de tu máquina. Tenía paleta oscura y ninguna forma de llegar a ella, así que npx verbaly-studio abría en claro en un escritorio oscuro.
  • Ya nada dentro del panel sabe de la red. Se le entrega a quién llamar, así que los mismos componentes corren sobre un servidor de verdad o sobre cualquier otra cosa que conteste igual.
  • El panel se puede pintar en tu propia página, si tu página compila Svelte 5: los componentes de verdad, sobre cualquier cosa que responda como responde el servidor.
  • Todo lo que pinta vive en una sola clase. Sus colores y su modelo de caja ya no pueden llegar a tu página, que es lo que hizo posible meterlo dentro de otro sitio.
  • Instalarlo no cambió en nada. npx verbaly-studio no se trae Svelte ni pide nada nuevo: el panel que sirve ya viene construido.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.55.0

Versión

El panel

Studio publicó su servidor hace dos versiones y decía, en su propio README, que faltaba la pantalla. Esta es la pantalla. Abre con tus mensajes, te deja corregir uno donde lo estás leyendo, y corre los dos comandos que cambian tus catálogos, con el presupuesto delante del que cuesta dinero.

Destacados
  • La pantalla que prometió la versión anterior de Studio. npx verbaly-studio abre ahora una página con todos los mensajes de tu proyecto, en los idiomas que marques, y el estado de cada uno.
  • Corriges una traducción en la propia fila donde vive. No se abre nada: la línea que estás leyendo se convierte en el campo donde escribes, y te dice qué está mal mientras escribes.
  • Los estados se llaman por lo que significan para ti: listo, falta, lo escribió una máquina y nadie lo ha leído, o rompe tu web. Cada uno lleva su propia forma además de su color.
  • Desde la página corren dos comandos. Uno lee tu código y añade el texto que tus catálogos no tienen. El otro traduce lo que falta, y como ese gasta dinero te enseña el presupuesto antes de llamar a nada.
  • Una tirada de traducción es algo de lo que puedes irte. Recarga la página y la barra de progreso vuelve, porque le pregunta a la tirada cómo va en vez de quedarse escuchándola.
  • Lo que escribe una máquina sigue siendo un borrador. Una tirada terminada te deja una lista que leer, no un trabajo dado por bueno.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.54.0

Versión

Trae tus catálogos tal como están

Alguien preguntó cuánto hay que aprender antes de que Verbaly sirva, y la respuesta resultó ser un problema de documentación y no de producto. Tres de las cuatro cosas que nuestra página de migración pedía nunca hicieron falta: un catálogo tal cual sale de i18next ya pasa, con sus grupos y todo. Esta versión borra ese trabajo de la página y le pasa el único cambio real a un comando.

Destacados
  • Un comando nuevo: npx verbaly migrate. Apúntalo a un proyecto que use otra librería de i18n y te pasa los catálogos que ya tienes. Primero te enseña qué haría, y --write lo aplica.
  • Tus ficheros conservan su forma. Los grupos siguen siendo grupos, y el comando devuelve exactamente la disposición que tu fichero ya tenía. No se reformatea nada.
  • Una sola cosa tiene que cambiar de verdad, y ya no la haces a mano: {{name}} pasa a {name}. Una llave doblada es como Verbaly escribe una llave literal, así que las dos formas no pueden significar lo mismo.
  • Lo que no va a adivinar, te lo dice. Un formato dentro de las llaves, un valor sin escapar, o una fusión que pisaría una key que usas se listan con el motivo, y esos mensajes se quedan exactamente como estaban.
  • Fusionar tus keys de plural es opcional. --plurals junta _one y _other en un solo mensaje, que es lo que enciende la selección de plural automática, y entonces el número se imprime ya localizado. Déjalo apagado y esas keys siguen funcionando.
  • Nuestra página de migración dejó de pedir trabajo que nunca hizo falta. Antes te decía que aplanaras tus grupos, fusionaras tus keys de plural y renombraras tus namespaces. Ninguna de las tres fue nunca obligatoria.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.53.0

Versión

Tus catálogos, en tu propia máquina

Ya puedes ver tu proyecto entero en una dirección de tu propia máquina. npx verbaly-studio lee todos tus catálogos de una vez y te deja escribir una traducción de vuelta, revisada igual que la revisa tu build. Tus ficheros JSON son la base de datos y git es el historial, así que no puede desincronizarse de tu código: no es dueño de nada. Esta primera versión trae la parte de abajo, no la pantalla de arriba, y lo dice ella misma.

Destacados
  • Un paquete nuevo: @verbaly/studio. Ejecuta npx verbaly-studio dentro de tu proyecto y te sirve todo lo que Verbaly sabe de él en tu propia máquina: cada catálogo, lo que falta, lo que está roto, lo que escribió una máquina y en qué parte de tu código se usa cada mensaje.
  • Esta versión es el servidor, no la pantalla. Todavía no hay panel. Lo que funciona hoy es la dirección que sirve y --json, que imprime lo mismo que leerá la pantalla, así que ya puedes pasarlo por un script. La pantalla viene después.
  • Nunca toca tu texto fuente. Ese texto vive en tu código y la key sale de él, así que escribir encima aquí se desharía la próxima vez que extraigas. Guardar en tu idioma fuente se rechaza, y también una key que tu fuente no tiene.
  • Una traducción que guardas se revisa antes de entrar. Pasa las dos mismas comprobaciones que pasa tu CI, así que un {name} perdido, una etiqueta perdida o un plural sin su caso general se rechaza con el motivo, en vez de colar aquí y romperte el build después.
  • Nada de lo que lee puede tumbarlo. Un catálogo que no puede leer, un fichero de borradores que no puede leer, un fichero de código que no compila, o apuntarlo a la carpeta equivocada se avisan por su nombre, y el resto carga igual. Es lo que abres para arreglar esos ficheros, así que tiene que abrir.
  • Te dice qué traducciones automáticas merecen leerse primero. Añadir un idioma escribe cientos de golpe, y leerlas una a una es un muro. Seis señales apuntan a las pocas que piden tus ojos: en nuestro propio sitio son 18 mensajes de 1425 por idioma.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.52.0

Versión

Un enlace dentro de una frase te deja en tu idioma

En un sitio publicado en varios idiomas, todos los enlaces escritos a mano ya llevaban el idioma del lector, y los escritos dentro de una frase traducida no. Pulsar uno dejaba a un lector en español en las páginas en inglés, y por eso resultaba tan raro: el resto de la página estaba bien. Llevaba así desde que existen los enlaces dentro de mensajes, escondido detrás de dos tests que lo daban por bueno.

Destacados
  • Pulsa un enlace dentro de una frase traducida y te quedas en tu idioma. Hasta ahora esos enlaces apuntaban a tu idioma de origen, así que quien pulsaba "mira la guía" a mitad de un párrafo en español aterrizaba en la página en inglés.
  • Estaba escondido detrás de dos tests que lo afirmaban. Uno de ellos recorre el sitio traducido entero con un visitante, así que la suite seguía verde mientras el problema se publicaba. Los dos esperan ahora la dirección correcta.
  • Una página traducida lleva sus propios enlaces. Ya no necesita la lista de enlaces de tu configuración cuando llega al navegador, así que nada puede reconstruir un enlace sin su idioma.
  • Los formularios van con ellos. Enviar es navegar, así que un formulario que apunta a una página que publicas en todos los idiomas se queda dentro de ese idioma.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.51.0

Versión

Una página traducida sigue traducida al navegar

La versión anterior hizo que cada página llevara sus propios mensajes, y se equivocó en la segunda: en un sitio con routing de cliente, al pulsar un enlace el texto salía en tu idioma de origen hasta que el visitante recargaba. No era un fallo sino tres, que es por lo que se rompía tan del todo. Los tres están arreglados, y en Astro no tienes que escribir nada.

Destacados
  • La regresión de la 0.50.0 se acabó. Leer un sitio en español y navegarlo se queda en español: de página a página, de una sección al inicio, y al cambiar de idioma.
  • Eran tres fallos, no uno. Los mensajes que llevaba una página se leían una vez y nunca más, el runtime no distinguía "esta página no traía la palabra" de "este idioma no tiene palabra para eso", y el intérprete de texto trataba la página que metía el router como texto escrito por él.
  • En Astro se arregla solo. Encender inlineCatalog ahora cablea también el router de cliente, así que no escribes nada. Cualquier otro montaje tiene una llamada, adoptPage, desde su hook de navegación.
  • Cambiar de idioma salió más barato de paso. Pasar de español a portugués se descargaba el catálogo portugués entero; ahora la página a la que llegas ya trae lo que muestra, así que el cambio no cuesta nada extra.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.50.0

Versión

Una página traducida deja de bajarse el diccionario entero

Hasta ahora, abrir una página en español descargaba todos los mensajes en español que tiene tu sitio, y la mayoría esa página no los muestra nunca. Ahora el mirror escribe en cada página exactamente los mensajes que renderiza, así que la página no necesita nada más. En este sitio, una primera visita a la home deja de bajarse unos 50 KB, que son unas nueve veces lo que cuesta el runtime entero de Verbaly.

Destacados
  • Una primera visita pesa mucho menos. Un visitante se bajaba 53 KB de mensajes en español para leer una página que usa 2.8 KB de ellos. Ahora recibe los 2.8 KB, y le llegan con la página en vez de como una segunda petición.
  • El ahorro es por página, y siempre es casi todo el fichero. Medido en este sitio: 50 KB menos en la home, 49 en una página de docs, 32 en novedades, que es la página más pesada de aquí.
  • No falta nada cuando alguien interactúa. Si tu página pide después un mensaje que no mostró, Verbaly se trae el resto una vez y actualiza, en vez de enseñar tu idioma de origen sin decir nada.
  • Es una línea y viene apagado. Añade inlineCatalog a tus ajustes de render. Un proyecto que no lo enciende se construye exactamente igual que antes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.49.0

Versión

Tu agente puede leer tus mensajes

El servidor MCP podía contar tus mensajes, decirte cuáles faltaban y traducirlos, y no podía enseñarte ni una frase. Eso hacía imposible una cosa: revisar una traducción máquina a través de un agente, porque te daban una clave y te pedían aprobarla. Ahora un agente puede leer tus ficheros de idioma y tus ajustes directamente, y cada traducción que te espera viene con la frase de la que salió.

Destacados
  • Un agente ya puede leer lo que dice de verdad un mensaje. Antes te podía decir que faltaban catorce traducciones y no enseñarte ninguna. Tus ficheros de idioma y tus ajustes se leen directamente, y mirarlos no le gasta una de sus acciones.
  • Revisar una traducción máquina por fin funciona a través de un agente. Recibes cada una que te espera junto a la frase original, así que puedes leer las dos y decidir. Aceptar sigue siendo solo tuyo, a propósito: ninguna herramienta de aquí puede aprobar una traducción, y ninguna lo hará nunca.
  • Un agente puede montar Verbaly en un proyecto desde cero. Crea tu fichero de ajustes y tus ficheros de idioma, averigua qué bundler o framework usas, y te dice la única línea que aún tienes que añadir tú.
  • No cambia nada de lo que ya usas. Todas las herramientas responden exactamente igual que antes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.48.0

Versión

La dirección decide el idioma

Cuando tus páginas viven en direcciones como /es/dashboard, esa dirección es la que dice en qué idioma está la página. Hasta ahora las integraciones de servidor de Verbaly nunca la miraban: preguntaban por la elección guardada del visitante y por su navegador, así que el mismo enlace podía llegar en inglés para una persona y en español para otra. Ahora manda la dirección, porque una dirección se comparte, se enlaza y se cachea mientras que una elección guardada es de una sola persona.

Destacados
  • Una página en /es/dashboard ahora llega en español, siempre. Antes Verbaly preguntaba por la elección guardada y por el navegador en vez de leer la dirección, así que el mismo enlace podía mostrar dos idiomas distintos a dos personas.
  • Tus páginas en inglés dejan de traducirse por accidente. Quien eligió portugués una vez recibía portugués también en tus páginas sin prefijo. Una dirección a secas ahora significa tu idioma de origen, para todo el mundo.
  • Las páginas de Next.js vuelven a poder construirse por adelantado. Verbaly leía los headers de la petición en cada página, lo que convertía en silencio cada página traducida en una que se reconstruye en cada visita. Pásale el idioma desde el nombre de tu carpeta y la página vuelve a construirse una sola vez.
  • Tus páginas traducidas también pueden contarse entre ellas a los buscadores desde un servidor. Los enlaces de idioma y la dirección canónica existían solo para sitios construidos estáticamente, y el mismo conjunto está ahora disponible donde sea que rendericen.
  • Las rutas de SvelteKit se quedan simples. Una línea y /es/docs lo sirve tu ruta /docs, así que no duplicas tus carpetas de rutas por idioma.
  • No cambia nada si tus direcciones no llevan idioma. Todo esto se activa con el ajuste de URL que ya tienes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.47.0

Versión

Keys que escribes tú, y un sitemap que no miente

Lo normal en Verbaly es que escribas texto y nunca veas una key, y eso no cambia. Esta versión cubre el otro caso real: keys que son un contrato con algo de fuera de tu app, un cliente móvil o una memoria de traducción, escritas una vez en un módulo y leídas desde todas partes. Hasta ahora Verbaly no veía esas keys, así que limpiar los mensajes sin usar te las borraba y nada comprobaba que existieran. La segunda mitad es el sitemap, que publicaba redirecciones y páginas de error como si fueran resultados.

Destacados
  • Puedes tener tus keys en un módulo y Verbaly las sigue comprobando. Un fichero que asocia nombres a keys es una forma que muchos proyectos ya escriben. Antes Verbaly no veía esas keys: limpiar los mensajes sin usar te las borraba, y nada verificaba que existieran.
  • Una key que ningún catálogo tiene es un error donde la declaras, no un hueco que descubres en la interfaz más tarde. Tu editor autocompleta desde tu propio catálogo mientras escribes el módulo.
  • Tu sitemap deja de listar páginas que piden no ser indexadas. Las redirecciones y las páginas de error se publicaban como si fueran resultados. En este sitio eran 21 direcciones de 81, y la lista son ahora solo las 60 páginas reales.
  • Esas páginas se siguen traduciendo y publicando igual que antes. Lo único que cambió es la lista de direcciones, así que quien aterrice en una la sigue recibiendo en su idioma.
  • Nada cambia si no usas ninguna de las dos. Son añadidos, y un proyecto que no escriba ninguna se comporta exactamente como antes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.46.0

Versión

Los diez primeros minutos

Todo lo que se arregla aquí está en el camino que recorres una sola vez, cuando añades Verbaly a un proyecto que ya existe: instalarlo, crear su estructura, pasar la revisión, envolver tus textos y extraerlos. Nada de ello está en el camino que recorres a diario, y por eso más de mil pruebas nunca lo vieron. El comando que crea la estructura ignoraba la configuración que ya habías escrito y creaba un segundo juego de catálogos. Un fichero suelto en tu carpeta de catálogos se convertía en un idioma que no podías quitar. El comando que envuelve tus textos podía dejar un proyecto sin compilar. Todo eso queda arreglado, y una comprobación nueva hace una instalación real con dos gestores de paquetes para que siga arreglado.

Destacados
  • verbaly init ahora lee la configuración que ya escribiste. Antes la ignoraba y creaba un segundo juego de catálogos en la carpeta por defecto y en el idioma por defecto. Si tu configuración decía español en locale/, te salía inglés en locales/.
  • Cambio importante: los idiomas que listas en tu configuración son ahora la lista entera. Un fichero JSON olvidado en tu carpeta de catálogos se convertía en un idioma que no podías quitar nunca, y bloqueaba compilaciones pidiendo traducciones que nunca quisiste. Si no los listas, los ficheros de la carpeta siguen decidiendo, igual que antes.
  • verbaly wrap --write ya no deja tu proyecto sin compilar. Antes envolvía texto en ficheros donde t no estaba disponible. Ahora se salta esos ficheros, te dice cuáles son y cuántos textos esperan en cada uno, y si son componentes de cliente para que sepas qué línea añadir.
  • El envoltorio deja de recoger cosas que no son texto de interfaz: el contenido de los bloques de código, palabras sueltas en minúscula como usuarios de demo y nombres de fichero, y frases que empiezan por un valor en vez de por palabras.
  • Cuando el comando verbaly no está instalado, Verbaly lo dice en vez de pedirte que lo ejecutes. La compilación nombra el paquete que hay que añadir, y la revisión tiene una línea para ello.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.45.0

Versión

Un catálogo solo crece, y todas las páginas pagaban el catálogo entero

El texto que vive en una sola página, una lista de versiones, un archivo de blog, una lista larga de preguntas, lo descargaba cada visitante en todas las páginas. Esta versión te deja nombrar esos grupos de mensajes y dejarlos en el build. Las páginas que los usan siguen saliendo traducidas, porque ese texto ya está escrito en el HTML, y el navegador deja de bajarlo. Buscar la prueba destapó además un defecto real por debajo. Tras su primera pasada, Verbaly podía sustituir texto traducido correcto de la página por el nombre interno del mensaje cuando ese mensaje faltaba. Queda arreglado aquí, y le importa a cualquiera que pre-renderice su sitio.

Destacados
  • El texto que solo necesita una página deja de viajar a todas. Nombra ese grupo de mensajes en tu configuración y el navegador ya no lo descarga. Las páginas que lo usan siguen saliendo traducidas, porque ese texto ya está en el HTML.
  • El texto pre-renderizado ya no se destruye. Si falta un mensaje, Verbaly conserva el texto que ya está en la página en vez de sustituirlo por el nombre interno del mensaje. Antes eso podía pasar un instante después de cargar la página.
  • Medido en este sitio: el fichero que carga cada página pasó de 46,3 KB a 33,5 KB comprimido, y los árboles en español y portugués bajaron unos 14 KB cada uno. No se perdió nada en pantalla.
  • Nada cambia si no lo activas. Es una opción nueva, y un proyecto que no la escriba se comporta exactamente igual que antes.
  • El build te avisa cuando algo pinta mal, nombrando un grupo que no coincide con nada de tu catálogo, o uno que tu código lee directamente.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.44.0

Versión

Nuestros propios chequeos medían la máquina, no el código

El job que comprueba nuestra cobertura de tests fallaba al azar, y la causa no era un test lento. Un test que tarda 22 milisegundos lo tumbaba un límite de 5 segundos, porque ese límite cuenta tiempo real y nuestro comando de tests levanta doce procesos sobre los mismos núcleos. Dos veces eso bloqueó una publicación. Esta versión lo arregla de raíz, y dedica el resto a la misma idea aplicada a nuestra cadena de suministro: qué puede hacer nuestro build, qué herramientas corre exactamente, y código que no podía ejecutarse nunca. Nada del paquete cambia.

Destacados
  • Nada de lo que instalas cambia. El runtime es idéntico al de la 0.43.0 y toda la API publicada se comporta igual. Esta versión va de la maquinaria que nos revisa.
  • Nuestro build dejó de fallar al azar. La suite podía tumbar un test perfectamente sano solo porque la máquina estaba ocupada, y dos veces eso bloqueó una publicación.
  • Cada herramienta que corre nuestro build está fijada a un commit exacto. Una etiqueta la puede mover quien la controla, pero un commit no, así que nada puede cambiar en silencio lo que construye tu paquete.
  • El job que publica las versiones pide permiso de escritura solo donde lo necesita, en vez de dárselo a todo el flujo.
  • El análisis estático corre en cada cambio, y su configuración vive ahora en nuestro repositorio, fijada y legible, en vez de ser un ajuste que solo veíamos nosotros.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.43.0

Versión

Todo lo que decimos de nosotros vuelve a ser cierto

El badge de nuestro README dice ~3KB desde el principio, mientras el runtime pesaba en realidad 3,68 KB. En vez de debilitar el claim, esta versión saca la última pieza que valía la pena sacar: el formato de tiempo relativo son 318 bytes que casi ninguna aplicación escribe, y ahora solo viaja cuando alguno de tus mensajes lo pide. El resto de la versión es la misma idea apuntada a todo lo demás que el proyecto dice de sí mismo.

Destacados
  • El runtime pesa 3,00 KB. El formato de tiempo relativo se suma a ICU como algo que solo viaja cuando alguno de tus mensajes lo usa de verdad, y no hay nada que tengas que configurar.
  • Un formateador que escribas tú ahora sabe para qué mensaje lo llamaron. Recibe el nombre del parámetro y la clave del mensaje, así que sus propios errores pueden decir dónde ocurrieron, cosa que antes no se podía.
  • La política de seguridad cubre los doce paquetes, no los siete que existían cuando se escribió, y ahora explica cómo verificar que una versión salió de verdad de nuestro CI.
  • Nuestra postura de seguridad es algo que puedes comprobar en vez de algo que afirmamos: una puntuación de la OpenSSF corre en cada cambio y el badge del README la lee.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.42.0

Versión

Un runtime más pequeño para quien nunca necesitó ICU

La sintaxis propia de Verbaly cubre plurales, selects y formatos, y la sintaxis ICU es la salida para lo que no cubre. Esa salida siempre se describió como algo opcional, y nunca lo fue: el parser entraba en toda aplicación usara ICU o no. Nuestro propio sitio de documentación no tiene ni un mensaje ICU y lo publicaba en cada página. Verbaly ya lee tus catálogos, así que ahora solo manda el parser donde algún mensaje lo necesita de verdad.

Destacados
  • El runtime es un 11% más pequeño para quien no usa sintaxis ICU, que son casi todos los proyectos. El parser solo viaja cuando alguno de tus mensajes lo necesita de verdad, y no hay nada que tengas que encender.
  • No cambia nada si sí usas ICU. Verbaly lo ve en tus catálogos y se lleva el parser, igual que antes.
  • Un mensaje que llega a tu aplicación después del build y usa ICU ahora muestra su propio texto y dice por qué, en vez de quedarse a medio renderizar en algo que parece casi correcto. Si tu texto viene de un CMS, un ajuste manda el parser igual.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.41.0

Versión

Una línea para cambiar, y tu elección por fin se queda

Verbaly traía un cambiador de idioma completo para una forma de hacer las direcciones y una pieza suelta para la otra, así que todo proyecto escribía la segunda a mano, el nuestro incluido. Reescribir nuestro propio sitio sobre el helper de la librería encontró un fallo que llevaba ahí desde que el cambiador entró en el runtime: quien elegía un idioma volvía al de su navegador en la siguiente carga. La otra mitad es que Verbaly había empezado a suponer que querías el idioma en tus direcciones; ahora lee tu montaje en vez de adivinar.

Destacados
  • Cambiar de idioma es una línea, y es la misma línea funcionen como funcionen tus direcciones. Va a la otra dirección cuando el idioma vive ahí, y cambia el texto donde está cuando no.
  • Tu elección de idioma sobrevive a la siguiente carga. Elegir inglés en una página en español podía devolverte al español, porque el cambio guardaba tu elección en un sitio y la página que te recibe leía otro.
  • Verbaly deja de suponer que quieres el idioma en tus direcciones. Lee tu montaje: si construyes una versión de tu sitio por idioma tienes direcciones por idioma, y si no, una sola sirve para todas. Solo lo escribes para llevar la contraria.
  • verbaly doctor te dice si leyó tu elección o la dedujo, para que un ajuste que nadie escribió no parezca una decisión que alguien tomó.
  • La comprobación de tamaño ahora mide lo que una aplicación real embarca de verdad, y no solo la importación más pequeña posible y la más grande imposible.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.40.0

Versión

Di dónde vive el idioma, y traduce también la cabecera

Verbaly lleva mucho con dos formas de cargar el idioma y nunca nombró ninguna, así que cuál te tocaba lo decidía si te acordabas de pasar un campo opcional. Nombrarlas destapó lo que hacía que nombrarlas importara: una página podía estar traducida en todo lo que un visitante mira y aun así decirle a un buscador que está en inglés, porque el título y la descripción viven en la cabecera, donde nadie los lee. Nuestra propia documentación publicaba 27 de 27 páginas así.

Destacados
  • Ahora puedes decir dónde vive el idioma en tus direcciones, una vez, en la configuración: /docs y /es/docs, un prefijo en todos los idiomas, o una sola dirección para todos. Antes la respuesta dependía de qué helper llamabas y qué le pasabas.
  • El selector de idioma es una línea y no se puede escribir mal. Verbaly te da un helper que ya conoce tus idiomas, tu fuente y tu modo, y la misma línea sigue funcionando si cambias de idea sobre el modo.
  • El título y la descripción de tus páginas también se traducen. Viven en la cabecera, nadie los lee en la página y son lo que enseña un resultado de búsqueda, así que una página podía parecer traducida entera y aparecer listada en inglés.
  • verbaly render cuenta las páginas cuyo título todavía no cambia nunca y te lo dice una vez, con el arreglo. Nunca tumba un build: el nombre de un producto puede no traducirse.
  • verbaly doctor te dice en qué modo están tus direcciones, y te avisa cuando tu configuración pide dos cosas que no pueden ser ciertas a la vez.
  • Breaking: pedir una ruta sin nombrar tu idioma fuente ya no compila. Antes ponía prefijo a todos los idiomas incluido el tuyo, en silencio, que casi nunca era lo que alguien quería.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.39.0

Versión

Traducir sobrevive a una mala conexión, y los agentes reciben el ciclo entero

Verbaly deja que un agente de código lo ejecute desde hace tiempo, pero de sus doce comandos solo cuatro llegaron a estar disponibles, y los dos que faltaban son los dos primeros que un agente necesita: averiguar qué falla en un proyecto y envolver el texto que ya está escrito en él. Mirando eso apareció algo peor al lado. verbaly translate es el único comando que cuesta dinero y minutos, y una sola respuesta mala tiraba la corrida entera: lotes ya pagados y traducidos nunca llegaban al disco.

Destacados
  • verbaly translate ya no pierde el trabajo que ya pagaste. Una petición que no vuelve se reintenta, y si aun así falla la corrida sigue y guarda todo lo demás. Volver a correrlo pide solo lo que falta, en vez de pagarlo todo otra vez.
  • Traducir es unas cuatro veces más rápido. Ahora las peticiones salen juntas en vez de una detrás de otra, y una corrida larga te va contando qué llegó mientras trabaja, en lugar de quedarse callada durante minutos.
  • Puedes decir qué no se traduce nunca. Pon los nombres de tu producto y cualquier forma que ya hayas decidido en translate.glossary, y cómo tratas al lector en translate.instructions, en vez de corregir la misma palabra a mano después de cada corrida.
  • Tu agente de código recibe las dos herramientas que le faltaban: una para averiguar por qué un proyecto no funciona, y otra para encontrar el texto escrito directamente en tus componentes y envolverlo. Llevar una aplicación existente a Verbaly ya no necesita una terminal.
  • Ahora los agentes leen números, no frases. Cada herramienta responde con datos simples además del texto, así que un agente deja de adivinar una redacción que puede cambiar entre versiones.
  • Aceptar una traducción automática sigue siendo algo que solo puede hacer una persona, y eso no ha cambiado.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.38.0

Versión

Las traducciones escritas por grupos ya son seguras en todas partes

Puedes guardar tus traducciones como grupos anidados en vez de una sola lista plana, y Verbaly lleva tiempo leyendo esa forma. Solo la leía la mitad: los comandos que escriben tus catálogos tomaban los nombres de grupo como si fueran mensajes. Así que extract añadía una segunda copia de cada mensaje, --prune borraba grupos enteros con todas las traducciones dentro, los exports llegaban rotos a tu traductor y translate decía que no había nada que hacer sobre una app a medio traducir. Para un catálogo plano no cambia nada.

Destacados
  • Las traducciones guardadas por grupos están a salvo de punta a punta. Ahora todos los comandos las leen y las escriben igual, y tu fichero conserva la forma que le diste en vez de quedar aplanado a tus espaldas.
  • verbaly extract --prune ya no borra traducciones. En un catálogo escrito por grupos leía el nombre de cada grupo como un mensaje, no lo reconocía y se llevaba el grupo entero con todas las traducciones dentro.
  • Tus ficheros para el traductor dejan de llegar rotos. El export escribía [object Object] donde tenía que ir el texto, y verbaly translate decía que no había nada que hacer mientras verbaly status decía que media app estaba sin traducir.
  • Un idioma que añadas después encaja con el resto. Un catálogo nuevo toma la forma de los que ya tienes, así que un proyecto nunca acaba medio por grupos y medio plano.
  • La herramienta cuenta en inglés de verdad. Antes decía 1 messages, 1 locales y 1 pages en nueve sitios.
  • Un aviso repetido se dice una sola vez. Una colisión de keys se anunciaba tres veces en un solo verbaly extract, una de ellas después de que el resumen ya se hubiera impreso.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.37.0

Versión

El idioma que guardaste sobrevive al F5

La versión anterior le puso nombre a las dos formas que tiene un sitio de llevar su idioma. Escribir la página que las explica destapó por qué una de ellas nunca había funcionado del todo: si tu app mantiene una sola dirección por página y carga los idiomas a demanda, Verbaly sabía qué idioma quería el visitante y sencillamente no lo pedía nunca. Una línea, y el ejemplo de nuestras propias docs lo venía enseñando desde siempre.

Destacados
  • El idioma guardado ya sobrevive a un F5 en un sitio de una sola dirección. Quien volvía recibía el idioma fuente otra vez, sin nada en la consola que lo explicara.
  • No cambia nada si tu idioma va en la dirección, que es de lo que iban las dos versiones anteriores. Esto solo estaba roto donde el idioma sale del almacenamiento o del navegador.
  • Un aviso que daba un consejo imposible ahora da el bueno. Cuando tu página dice un idioma y Verbaly está en otro, te decía que leyeras el idioma de la dirección. En un sitio de una sola dirección no hay nada que leer.
  • React, Vue y Svelte se probaron uno a uno contra un idioma que llega cuando la página ya está en pantalla. Antes era un camino raro y ahora es el normal.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.36.0

Versión

Tus visitantes llegan solos a su idioma

Verbaly publica tu sitio en cada idioma, cada uno en su propia dirección. La versión anterior dejó esas páginas bien, y esta va sobre cómo llega la gente hasta ellas, y sobre poder preguntar desde tu propio código a qué idioma pertenece una página. Las dos cosas las tenía que escribir a mano cada proyecto, este sitio dos veces en un día. También arregla una forma en la que el nombre de una página se podía confundir con un idioma.

Destacados
  • Preguntar en qué idioma está una página ya no necesita un ayudante tuyo. Verbaly responde con el idioma que dice la dirección, o con nada cuando la dirección no dice ninguno. Esa es una pregunta distinta a qué prefiere el visitante, y mezclar las dos es lo que dejaba que una preferencia guardada pintara el idioma equivocado sobre una página.
  • Verbaly ya puede mandar al visitante a su idioma. Lo activas y quien aterriza en tu página de inicio va a tu sitio en su idioma antes de que se dibuje nada. Solo la página de inicio, así que un buscador sigue llegando directo a cualquier página de tu sitio.
  • Un sitio servido desde una subcarpeta funciona. Le dices a Verbaly cuál es la carpeta y los enlaces dentro de cada idioma apuntan a donde deben, en vez de apuntar a la nada en silencio.
  • Una página llamada /es-la-guia es una página, no español. Verbaly leía el principio de una dirección con demasiadas ganas, así que una página cuyo nombre empezaba como un código de idioma se podía traducir a ese idioma. Ahora solo cuenta un código de idioma de verdad.
  • Lo que esta versión no cambia: una app con una sola dirección por página funciona exactamente igual que antes. Todo esto es para sitios donde cada idioma tiene su propia dirección.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.35.0

Versión

Tus páginas pre-traducidas dejan de parpadear

Verbaly publica tu sitio estático en cada idioma, bajo /es/ y /pt/. Esta versión va sobre lo que le pasaba a quien llegaba a una de esas páginas: llegaba en español y parpadeaba a inglés antes de volver, nada le decía al runtime que ya estaba en una página en español, y todos los enlaces apuntaban hacia fuera. La página estaba bien y todo lo que había entre ella y el visitante, no.

Destacados
  • Una página pre-traducida deja de parpadear a inglés. Verbaly servía la página en español y luego pintaba el texto en inglés encima hasta que terminaba de cargar el catálogo español, justo en las páginas que esta función existe para mantener quietas.
  • Aterrizar en /es/ ya es suficiente. Verbaly lee el prefijo que él mismo escribió antes de mirar el almacenamiento o el navegador, porque la página que estás viendo ya está en ese idioma.
  • Cada idioma deja de ser una isla. Sus enlaces apuntaban a la raíz del sitio, así que llegar en español y hacer un clic te devolvía al inglés. Los enlaces a páginas que ese idioma también tiene ahora se quedan dentro.
  • Tu selector de idioma lleva a tu sitio en ese idioma. Esa es la dirección que se puede compartir y la que indexan los buscadores, y la página llega ya traducida, así que no parpadea nada. En una app con una sola dirección por página, cambiar de idioma sigue cambiando solo el texto, igual que antes.
  • Lo que esta versión no hace: no enruta a nadie. Quien aterriza en tu raíz está recibiendo el idioma fuente, y mandarlo a su idioma es una regla en la configuración de tu hosting.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.34.0

Versión

Lo que el gate del build no puede ver

El gate del build se niega a compilar cuando una traducción no puede renderizar lo que renderiza tu fuente, pero solo ve lo que hay en tu proyecto al compilar. Esta versión va por todo lo que llega después: un catálogo que viene de un gestor de contenidos, un archivo de código que Verbaly no pudo leer y un salto de línea dentro de un mensaje con formato sobre el que la página pre-renderizada y el navegador no se ponían de acuerdo. Cuatro errores reales, cada uno una forma de publicar algo mal con todos los comandos en verde.

Destacados
  • Un salto de línea dentro de un mensaje con formato ya no se duplica en una página pre-renderizada. Verbaly lo escribía de una forma que los navegadores leen como dos saltos, y la página los reemplazaba por uno al cargar. Un salto visible, justo en las páginas que esa función existe para mantener quietas.
  • Una traducción que llega como null ya no tumba tu aplicación al arrancar. Un campo que nadie rellenó en un gestor de contenidos paraba todo antes del primer render. Ahora se salta esa clave, la aplicación funciona y la consola te dice cuál era.
  • Los comandos sobreviven a un archivo que no pueden leer. Un archivo con un error de sintaxis terminaba la ejecución entera con una posición y ningún nombre de archivo. Ahora se nombra el archivo, se saltan sus textos y el resto se sigue leyendo.
  • El texto dentro de JSX escrito en un archivo .js se encuentra igual que en cualquier otro sitio. Una aplicación React con componentes en .js no podía ni ejecutar el comando extract, porque la primera etiqueta lo terminaba.
  • Un aviso ya no se repite porque cambió un número. Tres de ellos imprimían el valor que los causaba, así que un contador subiendo podía llenar la memoria de copias del mismo mensaje.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.33.0

Versión

La API pública pasa a ser una decisión

El paquete del compilador te dejaba importar 132 cosas distintas, y ninguna estaba escrita en ningún sitio. Se habían ido acumulando como lo que los paquetes de framework fueran necesitando, y en la versión 1.0 cada una se habría convertido en una promesa que nadie había revisado nunca. Esta versión lee la lista entera contra una regla escrita, publica las 60 que la pasan, las documenta y añade un test que falla si la lista vuelve a crecer sin querer.

Destacados
  • Si usas la línea de comandos o cualquiera de los paquetes de framework, esta versión no te cambia nada. Ni configuración, ni imports, nada que editar. Todo lo de aquí pasa dentro de un paquete al que solo llegan las integraciones hechas a mano.
  • El paquete del compilador ya documenta qué puedes importar, en dos grupos: los tipos que necesitan tu archivo de configuración y tu propio proveedor de traducción, y las piezas para construir una integración que nosotros no publicamos. Todo lo demás es interno y ahora lo dice.
  • La lista pasó de 132 nombres a 60. Cada uno se quedó porque lo usa una integración real, porque es una forma documentada de extender Verbaly, o porque otro lo necesita. Los 72 que no cumplían ninguna de las tres ya no están.
  • Un plugin de build ya no recibe el árbol interno con el que Verbaly lee tu código. Antes le llegaba entero solo para leerle dos campos, y ahora recibe los mensajes que encontró. Una cosa menos que se puede romper cuando cambie ese lector.
  • Los dos paquetes fallan su propio test si la lista crece, así que añadir algo público es ahora una decisión que alguien revisa, en vez de algo que pasa de camino a arreglar otra cosa.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.32.0

Versión

Nada se rompe en silencio

Verbaly ya se negaba a compilar cuando una traducción no podía renderizar lo que renderiza tu fuente. Esta versión cierra la misma historia por el otro lado: cada sitio donde Verbaly hacía lo seguro sin decir nada ahora te avisa, en el momento en que puedes actuar. Un plural que renderiza una línea vacía, un precio sin moneda, un bloque escrito donde no puede funcionar y un nombre importado de donde no existe: cuatro formas de publicar el texto equivocado con todo en verde.

Destacados
  • Un plural sin caso comodín ahora avisa en el navegador, no solo en el build. La comprobación del build ya lo rechazaba, pero un catálogo que llega por carga diferida o desde un gestor de contenidos nunca pasa por el build, así que la línea vacía podía llegar a una página real. Ahora nombra el mensaje y te dice qué añadir.
  • Un hueco al que le falta su argumento deja de renderizar un número pelado. Un precio sin código de moneda, una medida sin unidad, una fecha sin unidad de tiempo: cada uno imprimía el valor plano y se callaba. Ahora cada uno dice qué necesita y te muestra la forma del arreglo.
  • Escribir un plural dentro de una plantilla t ya no se publica con las llaves a la vista. En esa plantilla los valores vienen de tu código, así que un plural o un formato escrito ahí se vuelve texto que ven tus usuarios. verbaly extract y verbaly doctor ahora señalan el archivo y el texto exacto.
  • Importar t del paquete por fin recibe una respuesta que menciona a Verbaly. t viene de tu instancia o del módulo generado, nunca del paquete, y hasta ahora solo se quejaba el bundler, con un mensaje que no daba ninguna pista de dónde debía salir t.
  • Cada error de la línea de comandos imprime su nombre una vez. Antes todo fallo se leía [verbaly] [verbaly].
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.31.0

Versión

La herramienta deja de contradecirse

Un comando decía que el proyecto estaba sano mientras otro bloqueaba su build por los mismos archivos. El doctor rechazaba los catálogos escritos como grupos anidados, aunque el runtime siempre los ha leído, y le decía a un proyecto Astro o Nuxt que instalara el paquete que el comando de setup le acababa de desaconsejar. El gate del build leía cualquier palabra entre signos de menor y mayor como markup, y tumbaba traducciones correctas por eso. Todo eso pasa a contar la misma historia: lo que un comando te dice es lo que tu proyecto es.

Destacados
  • verbaly doctor deja de contradecir a verbaly check. Una traducción que está pero está rota ahora también es un error en el doctor, así que el comando que corres cuando algo va mal ya no puede responder "el setup se ve sano" en un proyecto cuyo build falla.
  • Los catálogos escritos como grupos anidados funcionan en todas partes. El doctor los rechazaba como inválidos, y el gate solo comparaba los nombres de los grupos, así que un grupo con una línea sin traducir dentro contaba como traducido entero. Ahora cada línea se revisa por su cuenta, como el runtime ya la leía.
  • El doctor te señala el paquete que tu proyecto realmente necesita: Astro, Nuxt, Next.js, SvelteKit, Vite o el plugin de tu bundler. Es la misma respuesta que da verbaly init, porque los dos leen ahora una sola tabla.
  • El build deja de fallar por texto que solo parece markup. "Press <Enter> to continue" traducido como "Pulsa <Intro> para continuar" se reportaba como dos tags rotos. Un tag cuenta como estructura solo cuando el mensaje lo cierra, así que tu prosa sigue siendo prosa y un tag de énfasis o un enlace de verdad siguen protegidos.
  • Cada fallo nombra el paso que lo repara, en vez de un único "corre extract" que solo arreglaba las traducciones que faltaban. Y apagar la revisión de faltantes ahora significa lo que dice: puedes buildear con texto sin traducir, y Verbaly sigue negándose a publicar una traducción que renderiza mal.
  • Un valor que falta dice de qué mensaje viene. El aviso imprimía solo el nombre del placeholder, una vez por nombre, así que el segundo mensaje con el mismo hueco se quedaba callado.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.30.0

Versión

El gate del build deja de confiar en una traducción llena

Hasta ahora el check hacía una sola pregunta: ¿hay un valor para cada key? Una traducción podía dejar afuera tu placeholder de nombre, perder un tag de énfasis o aplanar un bloque de plural, y el build seguía en verde mientras producción mostraba en silencio el texto equivocado, o nada. Ahora el gate lee cada traducción contra su original y falla ante todo lo que no la puede mostrar, con el motivo en palabras simples y la línea del fuente para hacer clic. El runtime deja de callarse el mismo tipo de bug, y el paquete de React queda verificado contra Preact.

Destacados
  • El build ahora caza traducciones que están pero están rotas. Un placeholder que falta, un tag perdido, un bloque de plural convertido en texto plano, o un plural sin caso comodín: cada uno detiene el build con una frase que dice qué pasó y por qué importa. Antes de esto, un catálogo editado a mano no tenía ninguna revisión.
  • El bug del texto vacío se fue. Un bloque de plural que perdía su caso comodín no mostraba nada para cada cantidad que no listaba. En polaco, un mensaje con solo "one" y "few" mostraba una cadena vacía para 5 elementos. Eso ahora falla el build en vez de publicarse.
  • Verbaly le dice a quien traduce qué formas plurales necesita de verdad su idioma. Un catálogo polaco o ruso con solo dos formas recibe una advertencia que nombra las que faltan. Es un consejo, no un fallo: el texto igual se muestra. Las formas que ningún contador real alcanza nunca se piden, así que el español, el francés, el portugués y el italiano quedan en silencio.
  • verbaly status muestra un conteo de roto por idioma, así ves el estado de un catálogo sin correr el gate.
  • Un valor que falta ahora avisa en la consola. Mostrar un placeholder crudo porque nadie pasó el valor era el único caso de dato malo que Verbaly no reportaba. Todos los demás ya lo hacían.
  • Preact funciona, y ahora está probado. El paquete de React corre su suite completa una segunda vez con React resuelto a preact/compat: hooks, cambio de idioma, texto rico y render en servidor pasan todos. Sin paquete aparte y sin cambios en tu código.
  • VS Code puede mostrar tus traducciones al pasar el mouse. El README del repositorio trae la configuración de i18n-ally que convierte las keys con hash en texto legible mientras programas.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.29.0

Versión

Tu agente de código ya puede correr todo el ciclo de traducción

Un nuevo servidor MCP le da a Claude Code, Cursor y cualquier cliente MCP cuatro herramientas: ver la cobertura, listar lo que falta, extraer texto nuevo y traducir los huecos a máquina. Todo lo que el agente traduce sigue esperando tu revisión. Una Agent Skill pública y un llms.txt en la documentación completan el canal, los proyectos Nuxt mantienen su raíz limpia y los fragmentos de código que solo se muestran ya no pueden volverse claves fantasma.

Destacados
  • El ciclo de traducción como herramientas de agente. Un comando (claude mcp add verbaly -- npx -y @verbaly/mcp) y tu agente de código puede revisar la cobertura, listar traducciones faltantes, extraer texto nuevo y llenar los huecos con traducción máquina. Lo que traduzca se guarda como borrador, así que nada se publica sin que una persona diga que sí.
  • Una Agent Skill pública le enseña Verbaly a tu agente. Instala skills/verbaly del repositorio en tu proyecto y el agente conoce el ciclo de escribir, extraer, verificar y traducir, y las reglas que lo mantienen seguro.
  • La documentación ahora habla LLM. Este sitio publica un índice llms.txt, así los agentes que leen documentación se ubican en Verbaly sin raspar HTML.
  • Los proyectos Nuxt mantienen su raíz limpia. Los tipos generados ahora viven dentro de .nuxt/ y se registran solos, igual que ya lo hacía la integración de Astro. Ningún archivo en la raíz del proyecto y ningún cambio en tsconfig.
  • El código que solo se muestra ya no puede volverse una clave de traducción. Las páginas que enseñan ejemplos de t como texto visible en archivos Vue, Astro o Svelte corrían el riesgo de que esos fragmentos se extrajeran como claves reales. Ahora solo cuenta el código dentro de expresiones de verdad.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.28.0

Versión

Gettext PO, placeholders protegidos y un runtime más sólido

El kit para traductores está completo: exporta e importa archivos gettext PO, y XLIFF ahora protege tus placeholders y tags para que un traductor no pueda romperlos por accidente. El nombre custom del sitemap en render por fin funciona, un crash raro con fechas inválidas desapareció, y el runtime ya no puede crecer en silencio por encima de su presupuesto de tamaño.

Destacados
  • Exporta e importa archivos gettext PO. verbaly export --format po escribe un archivo .po por idioma, listo para Poedit, Weblate o cualquier editor PO. verbaly import los lee de vuelta con la misma red de seguridad que todos los formatos: una traducción que rompe un placeholder se rechaza, no se publica. Las entradas que una herramienta marca como fuzzy cuentan como sin traducir.
  • Los traductores ya no pueden romper tus placeholders en XLIFF. Placeholders y tags viajan como códigos protegidos con nombres con sentido, así que las herramientas de traducción los muestran como fichas intocables en vez de texto editable. Las palabras de plural y select siguen editables a propósito: esas sí se traducen.
  • Los nombres custom de sitemap ya funcionan. Configurar un nombre propio para el sitemap en render se ignoraba: siempre escribía sitemap-i18n.xml. El nombre que configuras es el nombre que obtienes.
  • Un crash raro desapareció. Pasar una fecha inválida a un mensaje podía lanzar un error en vez de degradar con gracia. Lo encontró una suite nueva de tests aleatorios que castiga al parser con basura en cada corrida, así que esta clase de bug se queda arreglada.
  • El runtime ya no puede crecer en silencio. Cada push mide el bundle del core y falla si supera su presupuesto de tamaño. La promesa de ~3 KB la hace cumplir una máquina, no una costumbre.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.27.0

Versión

Traducciones a máquina que revisas antes de confiar

Las traducciones a máquina ahora llegan como borradores que revisas, no como trabajo terminado en el que confías a ciegas. Un comando nuevo las aprueba, el gate de CI puede esperar a un humano, y el modelo traduce con contexto de tu código.

Destacados
  • La salida de la máquina es un borrador hasta que digas lo contrario. verbaly translate sigue llenando los huecos, pero todo lo que escribe queda marcado como borrador sin revisar. Tus catálogos quedan tan limpios como antes: el estado de revisión vive en un archivo .verbaly-drafts.json aparte, junto a ellos.
  • Aprueba las traducciones cuando las hayas leído. verbaly review lista todo lo que espera a un humano; verbaly review --approve lo acepta, todo o un idioma a la vez. Importar el archivo de un traductor también cuenta como revisión, así que la marca de borrador se limpia sola.
  • Bloquea merges con texto de máquina sin revisar. verbaly check --drafts hace fallar el CI mientras quede alguna traducción a máquina sin revisar. El verbaly check normal no cambia, así que nada se rompe hasta que decidas activarlo.
  • Mejores traducciones, porque el modelo recibe contexto. verbaly translate ahora le dice al provider en qué archivos fuente aparece cada texto, así el tono y el largo encajan donde el texto se usa.
  • Mira qué falta revisar de un vistazo. verbaly status (y --json) ahora reportan cuántos borradores sin revisar hay por idioma.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.26.0

Versión

Soporte para Astro, un codemod wrap y anotaciones en CI

Astro se une a la familia: una línea conecta todo y el rendering por idioma corre solo. Un nuevo comando wrap envuelve tu texto JSX hardcodeado por ti, y los fallos de CI se vuelven anotaciones directamente en tus pull requests.

Destacados
  • Soporte para Astro, una línea. Agrega verbaly() a las integrations de astro.config y todo queda conectado: extracción en vivo mientras programas, claves type-safe y el gate del build. Las claves tipadas viven dentro de la carpeta .astro propia de Astro, así que ningún archivo extra aterriza en tu proyecto. En el flujo de espejo, verbaly render corre solo después de cada build.
  • Escribe tu texto directamente en archivos .astro. El mismo t`…` que ya usas en .js, .tsx, .svelte y .vue ahora funciona en el frontmatter y el markup de los componentes Astro.
  • ¿Migrando una app existente? Deja que verbaly wrap haga la parte aburrida. Escanea tu JSX, encuentra el texto visible hardcodeado y lo envuelve en t`…` por ti. Primero reporta; nada se toca hasta que pases --write.
  • Los fallos de CI ahora apuntan a tu código. verbaly check --reporter github convierte cada traducción faltante en una anotación sobre el archivo y la línea exactos, directamente en el pull request.
  • verbaly status --json te da los números de cobertura en formato machine-readable, listos para badges y dashboards.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.25.0

Versión

RTL automático, nombres de idioma reales y contexto para traductores

Agregar árabe o hebreo ahora simplemente funciona: la dirección de la página sigue al idioma en todas partes. Los selectores de idioma reciben nombres reales de la plataforma, y los archivos de traducción dicen dónde vive cada texto.

Destacados
  • Los idiomas de derecha a izquierda simplemente funcionan. Agrega árabe, hebreo o persa y la dirección de la página sigue al idioma por su cuenta: cuando el usuario cambia, cuando el servidor renderiza y en las páginas estáticas pre-renderizadas. Sin atributo dir que administrar, nunca.
  • Selectores de idioma sin nombres hardcodeados. localeName('es') devuelve 'español' y localeName('de', 'en') devuelve 'German'. Los nombres vienen de la plataforma, así que cualquier locale funciona sin mantener una tabla.
  • ¿Necesitas la dirección tú mismo? localeDirection('ar') devuelve rtl. Es el mismo helper que usa el resto del toolkit, exportado para tus propios layouts.
  • Los traductores ahora ven dónde vive cada texto. verbaly export marca cada mensaje con los archivos fuente de donde viene: XLIFF recibe notas de ubicación estándar y CSV una columna de ubicación, así que el contexto deja de ser adivinanza.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.24.0

Versión

Llaves literales y páginas pre-renderizadas más seguras

Los mensajes rich por fin pueden mostrar una llave literal, y las páginas pre-renderizadas con verbaly render aplican las mismas reglas de seguridad que el navegador.

Destacados
  • Los mensajes ya pueden mostrar llaves literales. Escribe &#123; y &#125; en un mensaje rich y se renderizan como { y }. Las formas hex como &#x7B; también funcionan, en el navegador, en cada <Trans> y en páginas pre-renderizadas.
  • Las páginas pre-renderizadas son ahora tan seguras como el navegador. Los atributos traducidos pasan por los mismos guards, así que los links inseguros y los atributos peligrosos de un catálogo nunca llegan al HTML estático.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.23.0

Versión

Un <Trans> para todo, extracción en vivo y una vista de cobertura

Los componentes <Trans> de React, Vue y Svelte ahora comparten las mismas props y las mismas reglas de render, el CLI aprende dos comandos de uso diario y los últimos breaking changes planeados llegan antes de 1.0.

Destacados
  • <Trans> ya es el mismo componente en React, Vue y Svelte: mismas props, mismas reglas de render. Tu componente propio gana, luego los links nombrados, luego la whitelist segura de tags; lo desconocido degrada a texto plano.
  • Breaking: los <Trans> de React y Vue ahora renderizan tags whitelisteados como em y code como elementos reales, igual que Svelte y el intérprete de DOM. Pasa una lista richTags vacía para mantener el comportamiento anterior de aplanar a texto.
  • Breaking: @verbaly/svelte ahora requiere Svelte 5. A cambio <Trans> gana la prop components: mapea un tag del mensaje a tu propio componente. En Svelte 4, quédate en 0.22.0.
  • verbaly status muestra cuánto falta por traducir, una línea por idioma, sin hacer fallar nada. verbaly check sigue siendo el gate del build.
  • verbaly extract --watch mantiene catálogos y tipos al día mientras escribes código, pensado para setups de webpack, Rspack y Rollup donde el plugin de Vite no está disponible.
  • Dar feedback es más fácil: el README lleva los reportes de bugs y de fricción al lugar correcto, y los formularios de issues cubren los diez paquetes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.22.0

Versión

Tus catálogos se vuelven recursos nativos de mobile

El comando export aprende dos formatos mobile: carpetas de recursos de Android y archivos de strings de iOS. Una app web y su companion mobile ya pueden compartir un solo set de traducciones.

Destacados
  • Exporta tus traducciones para apps mobile: verbaly export --format android-xml escribe carpetas que puedes soltar en res/, y --format ios-strings escribe carpetas .lproj para Xcode.
  • Defaults sensatos por plataforma: tu idioma fuente se vuelve el default de la plataforma, y las keys sin traducir se omiten para que la app caiga en él en vez de mostrar texto vacío.
  • Catálogos más seguros: un catálogo con JSON roto ahora detiene el comando y nombra el archivo, en vez de leerse en silencio como vacío. Un BOM de Windows al inicio del archivo simplemente se tolera.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.21.0

Versión

Un pase de calidad, y config de Nuxt tipada

Una limpieza a fondo de los diez paquetes, más opciones totalmente tipadas en tu config de Nuxt. Los internos quedaron más ordenados y un poco más pequeños, sin cambiar cómo escribes Verbaly.

Destacados
  • La key verbaly de nuxt.config.ts ahora está totalmente tipada: tienes autocompletado y detección de typos, y el módulo sigue sin sumar dependencias.
  • Un editor más tranquilo en dev. verbaly.d.ts solo se reescribe cuando su contenido realmente cambia, así tu servidor de TypeScript deja de recargar tipos en cada guardado.
  • Un runtime un poco más pequeño: el core tree-shaken ahora pesa 3.28 KB gzip, antes 3.30.
  • Tipos generados más limpios: un valor usado como fecha y como texto plano ya no aparece dos veces en verbaly.d.ts.
  • Mensajes del CLI más claros. Cada error y sugerencia se lee en palabras llanas, y check ahora imprime el texto fuente justo al lado de la key faltante.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.20.0

Versión

Escribe tu texto también en archivos .svelte y .vue

El texto natural ya funciona dentro de componentes Svelte y Vue: escríbelo en el archivo, script o markup, y el compilador lo extrae con key estable y params tipados.

Destacados
  • Escribe t`Hello ${name}` directamente en un template .vue o {$t`Hello ${name}`} en markup .svelte. El compilador lo detecta como siempre lo hizo en archivos .ts: key estable, params tipados, catálogos por idioma.
  • La forma store de Svelte se entiende: $t`…`, $t('key') y $t.id('key')`…` funcionan en cualquier parte de un archivo .svelte.
  • En vivo en dev, con gate en build: guarda un componente con texto nuevo y los catálogos más verbaly.d.ts se actualizan al instante. Las traducciones faltantes siguen deteniendo el build.
  • Las keys legibles y las keys de runtime también funcionan en markup: t.id('home.title')`…` extrae bajo tu key, y las llamadas t('key') cuentan como keys usadas para check y prune.
  • verbaly extract escanea más por defecto: archivos .svelte y .vue, más la carpeta app/ junto a src/ (donde viven Nuxt 4 y el App Router de Next.js). Tu propio include sigue ganando.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.19.0

Versión

Next.js se une a la familia: el ciclo está completo

La última gran integración de meta-framework. Las páginas del App Router de Next.js se renderizan ya traducidas, hidratan sin flash y funcionan en Turbopack y webpack.

Destacados
  • Nuevo paquete @verbaly/next. Dos pasos: envuelve tu config con withVerbaly() en next.config.ts y suelta <VerbalyProvider> en el layout raíz. Los Server Components traducen con await getT(); los Client Components siguen usando useT y <Trans> como en cualquier app React.
  • Funciona en Turbopack (el default de Next 16) y en webpack. next dev extrae tus mensajes mientras escribes, y next build se detiene si falta una traducción.
  • Cada visitante recibe su propio idioma, resuelto una vez por request desde su cookie o las preferencias del navegador. Las páginas llegan ya traducidas, nada parpadea, y los visitantes concurrentes nunca ven el idioma de otro.
  • useSwitchLocale() cambia el idioma al instante, recuerda la elección para la próxima visita y actualiza también los Server Components.
  • Los mensajes rich ya pueden mostrar markup literal, así un mensaje puede enseñar "<html lang>" como texto visible en vez de un escape roto.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.18.0

Versión

Nuxt se une a la familia

La segunda integración de meta-framework: un módulo de Nuxt sin config renderiza cada página en el idioma del visitante e hidrata sin flash.

Destacados
  • Nuevo paquete @verbaly/nuxt. Una línea en tu config (modules: ['@verbaly/nuxt']) conecta todo: extracción en vivo, idioma por visitante e hidratación con el mismo locale y catálogo que usó el servidor. Sin flash, sin mismatch.
  • Sin lock del framework: el módulo no depende ni de nuxt ni de @nuxt/kit, y está verificado contra una app Nuxt 4 real.
  • switchLocale() ahora es un export del core compartido por SvelteKit, Nuxt y setups a mano. Carga el catálogo primero y cambia después, así nada parpadea. Los imports existentes siguen funcionando.
  • Las apps client-only también están cubiertas: con ssr: false el módulo igual elige el idioma correcto en el navegador.
  • Apoya a Verbaly: GitHub Sponsors ya está activo en github.com/sponsors/AronSoto.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.17.0

Versión

Robusto por dentro, de verdad

La release de hardening: una auditoría completa de los ocho paquetes corrigió cada borde afilado que encontró, y SSR gana su pieza faltante.

Destacados
  • La traducción de atributos ahora es XSS-safe de punta a punta: data-verbaly-attr sanitiza atributos de URL y bloquea style y srcdoc por completo, así un catálogo comprometido no puede inyectar scripts.
  • t() nunca crashea por argumentos de formato malos: un código de moneda, fecha o estilo de hora inválido avisa una vez y renderiza el valor plano.
  • createRequestInstance(locale) en virtual:verbaly: el patrón SSR per-request en una llamada, con el catálogo ya cargado y sin flash.
  • El CLI ahora rechaza flags mal puestas. verbaly translate --locale es antes traducía todos los idiomas en silencio; ahora da error y sugiere --locales. Además --dry-run para extract --prune.
  • normalizeLink() y resolveRequestLocale() ahora viven una sola vez en el core, compartidos por cada adapter e integración SSR.
  • Breaking: instance.inspect(key) ahora devuelve { from, source } en lugar de { locale, source }: un solo nombre para un solo concepto en toda la API de observabilidad.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.16.0

Versión

Server-side rendering, de verdad

La primera integración de meta-framework: las páginas de SvelteKit se renderizan en el idioma del visitante en el servidor e hidratan sin flash.

Destacados
  • Nuevo paquete @verbaly/sveltekit. SSR en tres cables: verbalyHandle() en tus hooks de servidor, un load de +layout y %verbaly.lang% en app.html. Las páginas llegan traducidas.
  • El idioma se decide por request: cookie primero, luego el header Accept-Language (es-PE matchea es), luego tu fallback. Los requests concurrentes nunca filtran el idioma de otro.
  • switchLocale(): un switch client-side que carga el catálogo primero y luego guarda la elección en la cookie que el servidor lee.
  • negotiateLocale() en el core: el matcher de Accept-Language es un export público que cualquier servidor Node puede usar.
  • createInstance() en virtual:verbaly: instancias frescas por request sobre tus catálogos compilados, más los exports locales y sourceLocale.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.15.0

Versión

Tus traductores ya pueden trabajar

El ciclo write→ship se abre a humanos: exporta archivos listos para traductores, impórtalos de vuelta validados.

Destacados
  • verbaly export escribe un archivo listo para traductores por idioma: XLIFF 2.0 para plataformas de traducción, CSV para hojas de cálculo. --missing exporta solo lo que falta por traducir.
  • verbaly import valida cada entrada: una traducción que pierde un placeholder, una variante o un tag se rechaza y se reporta.
  • Las traducciones existentes se conservan salvo que pases --overwrite, y --dry-run previsualiza el import completo.
  • No necesitas plataforma de traducción: los catálogos son JSON plano, y Crowdin, Lokalise y Phrase lo leen nativo.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.14.5

Versión

Revisión de 0.14.0: la release de repaso

Una auditoría dura de lo que envió 0.14.0 encontró tres defectos reales. Todos corregidos aquí.

Destacados
  • El overlay de verbaly/devtools ya no congela la página: su observer ahora ignora sus propias escrituras.
  • "" ahora significa sin traducir en todas partes: el runtime cae al fallback en vez de renderizar un hueco en blanco.
  • Los mirrors por idioma reciben rel="canonical" y og:url auto-canónicos, así el set de hreflang por fin cuenta.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.14.0

Versión

Sale traducido, y puedes ver por qué

SEO multi-idioma para el renderer estático, observabilidad del runtime, uso server-side endurecido.

Destacados
  • verbaly render emite alternates hreflang recíprocos y un sitemap i18n: define render.baseUrl y listo.
  • verbaly/devtools opt-in: pasa el cursor por cualquier elemento para ver su key, estado e idioma de origen.
  • Nuevo hook onResolve + inspect(key), con costo cero cuando no se usan.
  • El uso server-side en Node quedó endurecido y fijado con tests.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.13.1

Versión

README renovado: legible en el modo oscuro de npm

Patch solo de docs; primera release publicada desde CI con npm provenance.

Destacados
  • Los siete READMEs de paquete se leen bien en el tema oscuro de npm y son más fáciles de escanear.
  • MIT re-afirmado; las releases ahora salen con npm provenance desde el workflow automático.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.13.0

Versión

verbaly doctor + adopción y confianza

Un comando responde "¿por qué esto no traduce?", y una ruta real para salir de i18next.

Destacados
  • verbaly doctor inspecciona config, catálogos, cableado del plugin, tipos viejos y keys huérfanas, y le da a cada hallazgo su fix exacto.
  • Nueva guía Migrar desde i18next: conserva tus keys y tu JSON, cambia el runtime página por página.
  • La publicación pasa a GitHub Actions con npm provenance: cada paquete queda vinculado públicamente a su commit.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.12.0

Versión

verbaly init + el toolchain de TypeScript 7

De cero a traducir en un comando; el build pasa a tsdown y TS 7 nativo.

Destacados
  • verbaly init genera config + catálogos y detecta tu bundler. Nunca sobrescribe.
  • Toolchain: tsup → tsdown; typecheck en TypeScript 7 nativo (~10× más rápido). Sin cambio visible para el consumidor.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.11.0

Versión

Links rich + toda la superficie moderna de Intl

Links nombrados con hrefs que nunca salen de los catálogos, y los últimos formatters de Intl que faltaban.

Destacados
  • Los links nombrados en mensajes rich renderizan elementos <a> reales. El href sale de tu código, nunca del catálogo, y los schemes inseguros se bloquean.
  • Tiempo relativo ({when:relative}), listas ({xs:list}) y unidades CLDR ({n:unit/kilometer}): todo Intl nativo, cero dependencias.
  • Licencia: Apache-2.0 → MIT en los siete paquetes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.10.0

Versión

Los sitios estáticos salen traducidos + Verbaly más allá de Vite

El FOUC muere en SSG, y webpack/Rollup/esbuild/Rspack se suman vía unplugin.

Destacados
  • verbaly render pre-llena tu HTML compilado por idioma con el runtime real, así las páginas estáticas salen ya traducidas.
  • Nuevo @verbaly/unplugin: los mismos módulos virtuales + gate de build en webpack 5, Rollup, esbuild y Rspack.
  • verbaly pseudo: un idioma de QA (⟦Ĥéĺĺó ~⟧) que expone strings hardcodeados y layouts recortados.
  • <Trans> llega a Svelte.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.9.0

Versión

La traducción automática cierra el ciclo

write → extract → translate → check en verde: el ciclo completo en una sola herramienta.

Destacados
  • verbaly translate llena los huecos "" que reporta check: por lotes, con --dry-run y filtros por idioma.
  • Validación estructural: placeholders, variantes y tags deben sobrevivir intactos o la traducción se rechaza.
  • Providers conectables: Claude como referencia, y cualquier función (messages) => translations funciona. Cero impacto en runtime.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.8.0

Versión

Keys legibles + catálogos lazy

Ids legibles cuando los quieres, carga lazy por idioma cuando la necesitas.

Destacados
  • t.id('inbox.title')`Hello ${name}`: keys legibles con namespace; el hash sigue siendo el default sin config.
  • loaders en createVerbaly: empaqueta solo el idioma fuente y carga el resto bajo demanda, sin flash con await loadLocale.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.7.0

Versión

Svelte se une al ecosistema

Stores idiomáticos sobre el mismo core reactivo, para Svelte 4 y 5.

Destacados
  • @verbaly/svelte: $t('key') se re-renderiza al cambiar de idioma, y bind:value={$locale} simplemente funciona.
  • Contexto vía provideVerbaly/useVerbaly o factories de stores sin árbol de componentes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.6.0

Versión

El compilador entiende todo tu codebase

Escribe JSX en su lugar y el compilador lo extrae.

Destacados
  • Extracción write-in-place de <Trans>: el texto fuente con elementos reales se vuelve key + components automáticamente.
  • Soporte de verbaly.config.ts / .mts (esbuild como peer opcional).
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.5.0

Versión

Hardening + performance, con recibos

Los benchmarks vs i18next corren en cada release de aquí en adelante.

Destacados
  • Hot path memoizado de punta a punta: lookup 31×, interpolación 10×, plurales 5× vs i18next.
  • Auditoría de defensa: cadenas de fallback cacheadas, args de DOM por elemento, caché de AST con tope.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.4.0

Versión

El intérprete de DOM se pone al día

Texto rich en HTML plano, con seguridad, más helpers de bootstrap del idioma.

Destacados
  • data-verbaly-rich: los mensajes con tags renderizan elementos reales desde una whitelist de phrasing, nunca innerHTML.
  • resolveLocale / persistLocale: storage → navigator → fallback, SSR-safe.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.3.0

Versión

Escape-hatch de ICU + robustez

Trae tus strings ICU: se detectan solos, cero dependencias.

Destacados
  • ICU MessageFormat (plural, select, selectordinal) parsea al mismo motor, opt-in por mensaje.
  • Tokenizer de <Trans> endurecido + avisos de colisión de keys en build.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.2.0

Versión

Ecosistema público + texto rich

Primera publicación en npm de los paquetes del ecosistema.

Destacados
  • @verbaly/compiler, @verbaly/vite, @verbaly/react y @verbaly/vue llegan a npm, con versión alineada.
  • <Trans> en React y Vue: interpola elementos dentro de frases traducidas con tags nombrados.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.

0.1.0

Versión

La primera release

La idea central, funcionando: escribe texto, envía traducciones.

Destacados
  • Runtime: formato de mensajes sobre Intl nativo, store de idioma reactivo, intérprete de DOM, keys y params a nivel de tipos.
  • Compilador: extracción por AST de t`…` a keys hasheadas estables, extract/check, verbaly.d.ts tipado.
  • Plugin de Vite: extracción en vivo, HMR, code-splitting por idioma, el build falla con traducciones faltantes.
Notas completas de la versiónCada detalle, por paquete, en el changelog del repo.
Copiado en el portapapeles