Un catálogo solo crece, y todas las páginas pagaban el catálogo entero
Añadido1Corregido1
En esta versión
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.
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.
Añadido · 1
An option that keeps the groups of messages only the build needs out of the browser
Corregido · 1
Pre-rendered text is no longer replaced by a message’s internal name when that message is missing
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.
Añadido · 1
A CodeQL workflow, so the configuration of our static analysis lives in the repository instead of in a setting
Cambiado · 4
The test suite no longer fails a healthy test when the machine is busy
Every GitHub Action our build uses is pinned to an exact commit
The release job holds write access only on the job that needs it
Three branches of code that could never execute were removed
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.
Añadido · 2
A setting that ships relative time formatting anyway, for text that only reaches your app after the build
A formatter receives the parameter name and the message key it was called for
Cambiado · 3
The runtime went from 3.28 KB to 3.00 KB for a project that writes neither ICU nor relative time
The size limits were tightened again, so the saving cannot be quietly spent later
The README quotes the measured number and names the command that measures it
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.
Añadido · 1
A setting that ships the ICU parser anyway, for text that only reaches your app after the build
Cambiado · 3
The runtime went from 3.68 KB to 3.28 KB for a project whose messages do not use ICU syntax
An ICU message with no parser shows its own text and says why, instead of rendering something that looks almost right
The size limits were tightened to match, so the saving cannot be quietly spent later
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.
Añadido · 2
A language switcher that works the same in both ways of handling addresses, bound to your project so there is nothing to pass
The switch remembers your choice in both places a page can read it back from, under one name
Cambiado · 4
Where the language lives in your addresses is read from your setup instead of assumed, and you only write it to disagree
verbaly doctor says whether it read that setting or worked it out
On Next.js the switch uses the app router, so a language change keeps your app alive instead of re-rendering twice
The size check measures four things now, and separates a budget from a warning light
Corregido · 2
Someone who picked a language was sent back to their browser language on the next page load
A project with a single address was told it had one address per language, which was simply not true of it
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.
Añadido · 4
A routing setting with three values, so where the language sits in your addresses is said once instead of inferred
A path helper that already knows your languages, your source and your mode, so a language switcher cannot be written wrong
A routing line in verbaly doctor, including a warning when two settings ask for opposite things
verbaly render counts the pages whose title never changes between languages, and says it once with the fix
Cambiado · 3
Asking for a path now requires naming your source language wherever that decides the answer
Under one-address mode the path helper returns the address you are already on, so one switcher works in both modes
The English descriptions on this site were rewritten shorter: several ran past what a search result shows
Corregido · 3
A translated page shipped its title and description in the source language, which is most of what a search result shows
Switching language without a navigation left the page title alone, and nothing said so
Pages that only redirect were being reported for a title nobody will ever read in a search result
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.
Añadido · 4
Two new tools for coding agents: one that diagnoses a project end to end, and one that wraps hardcoded text so the compiler can pick it up
Every agent tool now answers with structured data alongside the sentence it always returned
translate.instructions and translate.glossary, so tone and required wordings are settings of the project rather than something you fix afterwards
translate.concurrency and translate.retries, for a provider that rate limits you or a connection that drops
Corregido · 6
One failed request threw away every request that had already succeeded, so a run that broke near the end wrote nothing at all
A request that failed for a passing reason was treated as a real failure, with no second attempt
Requests went out one at a time although nothing connected them
An answer cut short by length failed with a message about broken text instead of saying the batch was too big
A translate run said nothing at all while it worked, sometimes for minutes
verbaly doctor counted the way the rest of the tool stopped counting, and a suggested fix could end up in a different place than the problem it fixed
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.
Cambiado · 2
A catalog value that is not text is now refused, naming the file and the exact path, instead of being dropped the next time a catalog is written
Reading a message is faster on a large catalog, and stops falling off a cliff past a couple of thousand of them
Corregido · 4
Commands that write your catalogs read a group name as if it were a message, so extract duplicated, prune deleted, export broke and translate went quiet
A language added later was always written flat, even when every other catalog in the project used groups
Nine lines of output said "1 messages", "1 locales", "1 pages", "1 keys" or "1 translations"
A key collision was reported once per command instead of once per run
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.
Corregido · 2
A language chosen on a previous visit was recognised but never loaded, so the page stayed in the source language
The page-language warning suggested a fix that does not exist on a site without the language in the address
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.
Añadido · 3
A way to ask which language the address says, which answers nothing when the address says none
An option that sends someone landing on your home page to their language, before anything is drawn
Support for a site served from a subfolder, in the address helpers and in the pages Verbaly writes
Corregido · 1
A page whose name begins like a language code is no longer read as that language
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.
Añadido · 3
A helper that gives you the same page in another language, which is what a language switcher needs on a mirrored site
A warning when the page language and your instance disagree, because that combination is always a flash
An end to end test that builds a site and walks a visitor through the pages it wrote
Cambiado · 3
The DOM binder no longer repaints text it did not write while the catalog for that language is still loading
Locale detection reads the url first, then storage, then the browser
Mirrored redirect pages send you to the mirrored target, not to the root one
Corregido · 3
The runtime undid the work of the pre-render on every mirrored page
Locale detection ignored the language prefix Verbaly had written itself
A link inside a translated message could stop the pre-render with an internal error
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.
Añadido · 3
One shared list of the HTML tags that take no children, read by every surface that renders rich text
A test that renders the same messages through the static output and through the browser and compares the two, the one that caught the line break bug
Files the parser cannot read are now reported by name, by the extract command, by doctor and by the build plugins
Cambiado · 4
A catalog value that is not text is skipped with a warning naming its path, instead of crashing or disappearing
Every warning names the message it came from, and none of them prints the value that caused it
Files ending in .js are read with JSX support, the same as .jsx and .tsx
Counts in the command line read as text, so nothing says "1 messages" any more
Corregido · 5
The pre-rendered page and the live page disagreed about line breaks inside rich messages
A null value in a catalog stopped the app before its first render
One unreadable file ended the extract, check and doctor commands
Three warnings could repeat forever as the value that caused them changed
The review command accepted a locale option that its help never mentioned
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.
Añadido · 3
A test in the compiler package and another in the runtime that pin the exact list of public names, each one verified to fail on an extra export before being trusted
A "Programmatic API" section in the compiler package readme: the two groups, every name by area, and a minimal plugin example
The custom-provider example now shows the type that describes it, and mentions that providers also receive the source files each text appears in
Cambiado · 3
The per-file build step hands a plugin the messages it found instead of the internal parse tree
72 names are no longer importable from the compiler package; the command line covers the same ground
Nothing in the runtime moved, and nothing about what Verbaly renders changed
Corregido · 1
Four test files were being measured against the budget for a quick test while they load the real compiler, which could fail a release at random
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].
Añadido · 3
The runtime reports every way a message can degrade, naming the message: a plural with no catch-all case, a placeholder missing its argument, a list that is not a list
verbaly extract and verbaly doctor point at a message that kept a plural or a format as literal text
The doctor reports t imported from a verbaly package, with the line that says where it really comes from
Cambiado · 3
The doctor fails on setup faults that break a build on their own, and never on something that builds and renders
The relative-time warning names both suspects instead of blaming the time unit for what is often an invalid date
Nothing about what Verbaly renders changed: this version only adds the report
Corregido · 2
Every error from the command line printed its name twice
A test that starts an external process was being measured against the budget for a quick one, which could fail a release at random
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.
Añadido · 3
The doctor reports translation health: broken translations as an error, plural warnings as advice, in the same place it already reported the missing ones
The doctor explains a project with source scanning off, and stops guessing about orphan keys and types it cannot know about
One table maps your framework to the package that wires it, read by both verbaly init and verbaly doctor, covering Nuxt, Next.js, SvelteKit, Astro, Vite and the bundlers
Cambiado · 5
The gate and the coverage report read every catalog the way the runtime does, so nested groups are counted line by line instead of by group name
A tag is only checked when the message closes it, so ordinary text with angle brackets is free to be translated
Turning off the missing check no longer turns off the rest of the gate: unknown keys and broken translations still block the build
Every failure prints the step that repairs it, in the build gate and in verbaly check
A missing value warns once per message, naming it, instead of once per placeholder name
Corregido · 1
A stray invisible character made one compiler source file unreadable to git, which had been hiding its diffs since it was added
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.
Añadido · 4
Structural validation of catalogs: every translation is read against its source, and each finding is either an error that fails the build or a warning that only prints
A broken count per language in verbaly status, in the text output and in --json
Preact verification in the React package: the same suite, run again through preact/compat
The i18n-ally editor setup in the README, so hashed keys read as real text in VS Code
Cambiado · 3
Imports and machine translations are held to the same stricter standard: a flattened plural block or one that would render empty is now rejected too
t() warns once when a value is missing instead of quietly leaving the placeholder in your text
The verbaly_missing agent tool reports broken translations and warnings, not only missing ones
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.
Añadido · 4
@verbaly/mcp: an MCP server with verbaly_status, verbaly_missing, verbaly_extract and verbaly_translate; failures come back as actionable messages, never a crashed server
A public Agent Skill in the repository (skills/verbaly), installable into any project
An llms.txt index on the docs site, generated from the real navigation
New compiler exports collectOrigins and resolveProvider for tooling built on the cycle
Cambiado · 2
The Nuxt module writes the generated types into .nuxt/ and registers them automatically; an explicit dts option still wins
Markup extraction in .vue, .astro and .svelte files counts only expressions; plain display text is never extracted
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.
Añadido · 4
verbaly export --format po and .po import: gettext PO with the catalog key as context, source locations as comments and fuzzy entries respected
XLIFF exports protect placeholders and tags as inline codes with semantic names; imports reconstruct them exactly
A size gate in CI: the core bundle is measured (min+gzip) on every push and the build fails over budget
Property-based tests: parser and formatter are exercised with random input on every run and must never crash
Corregido · 2
A custom sitemap filename in render was ignored and always wrote sitemap-i18n.xml
An invalid date passed to a message threw an error instead of degrading with a warning
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.
Añadido · 5
A .verbaly-drafts.json sidecar next to the catalogs records which keys are unreviewed machine translations; catalogs stay plain flat JSON
verbaly review: list drafts awaiting review; --approve accepts them, optionally per --locale
verbaly check --drafts: opt-in CI gate that also fails while unreviewed drafts remain
Translation requests carry the source files of each text, so providers translate with context
verbaly status (and --json) report the unreviewed draft count per locale
Cambiado · 3
verbaly translate marks everything it writes as a draft
verbaly import clears the draft flag for imported keys: a human file is reviewed by definition
Locale discovery ignores dotfile sidecars, so the drafts file never becomes a phantom locale
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.
Añadido · 7
@verbaly/astro: a thin Astro integration wiring the Vite plugin and running verbaly render after static builds (opt-in, never on path-based i18n routing)
.astro extraction: frontmatter and markup, same strict scanner as .svelte/.vue; the default include covers the extension
verbaly wrap: JSX/TSX onboarding codemod with report-first flow, --write to apply, and a "needs a human" list for ambiguous cases
verbaly check --reporter github: failures as workflow annotations with source file and line; githubCheckAnnotations exported for tooling
verbaly status --json: machine-readable coverage
verbaly init detects Astro projects and points at the integration
A dts config option: move the generated types file anywhere, or turn it off with dts: false
Cambiado · 1
The Vite and unplugin transforms now respect the config include/exclude: only files the CLI would scan get rewritten, and include: [] turns source scanning off entirely
Corregido · 1
A raw NUL byte in a compiler source file made git treat it as binary (no reviewable diffs); replaced with the escape
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.
Añadido · 4
localeDirection(locale): ltr or rtl for any locale, script-aware, never throws
localeName(locale, displayIn?): localized language names via Intl.DisplayNames, endonym by default
Source-file locations in translator exports: XLIFF location notes and a CSV location column
%verbaly.dir% placeholder for SvelteKit's app.html, next to %verbaly.lang%
Cambiado · 3
switchLocale and persistLocale now set <html dir> alongside <html lang>
verbaly render writes dir on each mirrored page; the Nuxt module keeps it in sync live
CSV export header is now key,source,target,location; files in the old three-column shape still import fine
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 { y } en un mensaje rich y se renderizan como { y }. Las formas hex como { 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.
Añadido · 2
Numeric character references ({, {) decode in rich text: bindDom, every <Trans> and verbaly render
safeAttribute(name, value): the attribute guard as a public core helper, shared by bindDom and verbaly render
Cambiado · 1
Internal: render link handling reuses normalizeLink, the same helper every adapter uses
Corregido · 1
verbaly render now applies the runtime attribute guards: unsafe URLs are blocked and style/srcdoc are never written from translations
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.
Añadido · 3
components prop on the Svelte <Trans>; instance and richTags props on React and Vue
verbaly status: per-language translation coverage, informational only
verbaly extract --watch: re-extracts as source files change, with the building block exported as watchProject
Cambiado · 3
React and Vue <Trans> render whitelisted tags as real elements (breaking; an empty richTags list restores the old behavior)
@verbaly/svelte requires Svelte 5 (breaking); the shipped components moved to runes
An extract that changes nothing no longer rewrites catalog files, so file watchers stay quiet
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.
Añadido · 1
Two export formats in @verbaly/compiler: android-xml (Android resource layout, keys adapted to valid resource names) and ios-strings (one .lproj folder per locale)
Cambiado · 2
A corrupt catalog file fails with a clear error naming the path; before, it was read as empty and a later extract could have lost translations
--missing is rejected for the mobile formats with a message explaining why: mobile output already skips untranslated keys
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.
Cambiado · 3
A quality pass across the whole codebase: shared plugin code lives in one place, dead code is gone, and hot paths are simpler, with the full test suite green
Breaking, advanced only: the compiler helpers generateDts and writeDts take the catalog object directly instead of a Map. The command line and every bundler plugin are unaffected
Dev tooling updated to the latest stable (tsdown, typescript-eslint)
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.
Añadido · 2
SFC extraction in @verbaly/compiler: .svelte and .vue files are analyzed in full, script blocks and markup
@verbaly/vite and @verbaly/unplugin now transform .svelte/.vue sources
Cambiado · 2
Rewrites inside component markup use single quotes, so bindings like :title="t`…`" stay valid
Default include is now {src,app}/** and covers .svelte/.vue; explicit configs are untouched
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.
Añadido · 2
@verbaly/next, the 10th package: the withVerbaly config wrapper, a server API (getT, getVerbaly, getRequestLocale, getVerbalyProps), a client provider with useSwitchLocale, and the compiler as a loader for both bundlers
loadMessages(locale) in virtual:verbaly: the raw catalog that SSR integrations send to the client
Corregido · 1
HTML entities decode inside rich text (core), so a message can display <html lang> literally and pre-rendered HTML round-trips cleanly
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.
Añadido · 2
@verbaly/nuxt, the 9th package: zero-config module plus a runtime plugin (per-request language, payload hydration, reactive <html lang>)
switchLocale / SwitchLocaleOptions (core)
Cambiado · 1
@verbaly/sveltekit re-exports switchLocale from core, with identical API and behavior
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.
Añadido · 2
normalizeLink, resolveRequestLocale, LOCALE_STORAGE_KEY (core) and createRequestInstance (virtual:verbaly)
failOnMissing opt-out for the Vite build gate; --dry-run on verbaly extract
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.
Añadido · 2
@verbaly/sveltekit, the 8th package: verbalyHandle + switchLocale
negotiateLocale (core) and SSR exports in virtual:verbaly
Cambiado · 1
The Release workflow now resumes per package after a partial run
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.
Añadido · 2
verbaly export: translator-ready XLIFF 2.0 / CSV files per locale
verbaly import: a validated round-trip back into your catalogs
Cambiado · 2
GitHub Release notes are now short: theme, highlights and a link to the full changelog
Community docs pass: SECURITY and CONTRIBUTING read friendlier
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.
Añadido · 3
richLinks + data-verbaly-links + links prop on every <Trans>