O Verbaly deixa de trazer o esbuild para o seu projeto, o que fazia o pnpm add falhar por um script de build que ninguém pediu. O verbaly.lock se junta sozinho depois que duas branches traduzem em paralelo, o <br> funciona do jeito que você escrever, e um visitante recebe o idioma que lê mesmo quando a sua lista só tem uma variante próxima dele. Breaking: o Verbaly agora precisa do Node 22.12 ou mais recente.
O Verbaly deixa de trazer o esbuild para o seu projeto, o que fazia o pnpm add falhar por um script de build que ninguém pediu. O verbaly.lock se junta sozinho depois que duas branches traduzem em paralelo, o <br> funciona do jeito que você escrever, e um visitante recebe o idioma que lê mesmo quando a sua lista só tem uma variante próxima dele. Breaking: o Verbaly agora precisa do Node 22.12 ou mais recente.
Destaques
Instalar com pnpm funciona de primeira. O Verbaly não traz mais o esbuild, então pnpm add @verbaly/vite deixa de falhar por um script de build que você nunca pediu, e a instalação fica cerca de 12 MB mais leve. Um verbaly.config.ts continua funcionando, e os imports dele escritos sem extensão também.
Um merge não quebra mais o verbaly.lock. Quando duas branches traduziram em paralelo, o Verbaly lê os dois lados do conflito, mantém todos os rascunhos de cada lado, e o próximo extract escreve o arquivo inteiro. Adicione-o ao commit que resolve o merge.
<br> funciona do jeito que você escrever.<br>, <br/> e <br /> são todos quebras de linha nas mensagens rich, nos arquivos que você manda para tradução e no verbaly check. Antes, <br> sumia e <br /> aparecia como texto.
Cada visitante recebe o idioma que lê. Um navegador ou uma requisição em zh-HK agora recebe o seu chinês tradicional, e pt ou pt-PT recebe o seu pt-BR, em vez de cair no inglês.
Builds mais rápidos. O plugin do Vite e o @verbaly/unplugin leem cada arquivo uma vez em vez de duas.
Breaking: Node 22.12 ou mais recente. O Node 20 chegou ao fim da vida útil em abril de 2026, e os frameworks que o Verbaly suporta já pedem o Node 22.
Alterado · 5
A TypeScript config loads with jiti, so esbuild leaves the install
Every package needs Node 22.12 or newer
verbaly.lock reads both sides of a merge conflict, and the next command that writes it writes both
resolveLocale and negotiateLocale match by likely script and region, then by a sibling in the same script
The Vite plugin and unplugin parse each file once per build
Corrigido · 2
<br> and <br /> are line breaks in rich messages, in check and in the XLIFF export
The compiler README and the Agent Skill still named the old state file
O que o Verbaly lembra das suas traduções (para qual texto fonte cada uma foi feita e quais são rascunhos) sai da sua pasta de catálogos para o verbaly.lock, ao lado da sua config, e se muda sozinho. Uma chave escrita com dois textos diferentes agora faz o verbaly check falhar, porque um dos lugares dela mostra o texto do outro. Breaking: um projeto com uma chave assim vê o check e o doctor falharem, e failOnMissing: true para o build por ela.
Destaques
Sua pasta de catálogos tem só os seus catálogos. O que o Verbaly lembra das suas traduções agora fica no verbaly.lock, ao lado do verbaly.config.ts. Trate-o como o lockfile de um gerenciador de pacotes: o Verbaly o escreve, você o commita e ninguém o edita.
O arquivo antigo se muda sozinho. O próximo extract ou início do servidor de dev move o .verbaly-state.json para o verbaly.lock e avisa uma vez. Não há nada para configurar.
Breaking: uma chave com dois textos faz o verbaly check falhar. Quando t.id('title') é escrito duas vezes com palavras diferentes, um lugar mostra o texto do outro. Cada build agora a lista junto com as traduções quebradas, e o check para nela, nomeando os dois lugares.
Coisas pequenas: o primeiro exemplo do README mostra a chave que o compilador escreve de verdade, e o repositório tem um AGENTS.md para quem contribui e seus agentes de código.
Alterado · 3
The review state lives in verbaly.lock at the project root, and the old .verbaly-state.json moves into it on its own
The first command that writes verbaly.lock says so, in the CLI, both dev servers and the MCP server
A key written with two texts fails check, doctor and a build with failOnMissing: true
Corrigido · 1
The README example showed a key the compiler never writes
Uma tradução que falta ou está quebrada, ou uma chave que nenhum catálogo tem, agora aparece no fim de cada build, e o build termina: o que para uma versão é o verbaly check no seu CI. Para testar a entrada, passamos o Memos, um app de código aberto com 46 idiomas, de react-i18next para Verbaly e corrigimos tudo o que ele encontrou. Breaking: o build não para mais sozinho, e uma chave escrita entre crases que nenhum catálogo tem agora faz o check falhar.
Destaques
Um texto nunca para o seu build. Cada build lista o que falta ou está quebrado, primeiro as traduções quebradas, e termina. A verificação é o npx verbaly check, no seu CI. Breaking: para manter um build que falha, defina failOnMissing: true nas opções do plugin.
Testado numa migração real. Passamos o Memos (46 idiomas, 879 chaves) de react-i18next para Verbaly: 20 arquivos alterados à mão, o mesmo build e os mesmos testes passando, e cerca de 11 KB a menos para cada visitante. O init agora mantém os catálogos que você já tem, e o migrate deixa texto como {timestamp} como texto e nunca converte um idioma duas vezes.
Builds mais rápidos com Vite. O plugin do Vite deixava os builds grandes lentos: o Memos levava 37 segundos para compilar, e agora leva 17 (13 sem Verbaly).
Sem provider no navegador. Num app de página única e nos testes de componentes, useT() funciona sem <VerbalyProvider>, o plugin do Vue ou provideVerbaly, como no react-i18next.
Menos erros de tipo ao migrar. Uma chave guardada numa variável tipada como um conjunto de chaves passa com seus parâmetros, e os tipos gerados não atrapalham mais o Biome nem o Prettier.
Coisas pequenas: o doctor diz "setup works, with 1 warning to read" em vez de "healthy" depois de um aviso, e o servidor MCP volta a ler um config CommonJS. Breaking: uma chave escrita entre crases, ou como {'…'} em JSX, é verificada como uma entre aspas.
Alterado · 8
A missing, broken or unknown key is listed by every build, which finishes; failOnMissing: true stops it instead
A key written in backticks, as {'key'} in JSX or through a renamed t is checked like a quoted one
A variable typed as a union of keys passes, with its params left open
init keeps the catalogs a project already has and points the config at them
migrate doubles the braces i18next showed as text and remembers which languages it converted
useT() and useLocale() read the app instance when no provider is above them, in the browser
The generated verbaly.d.ts is left alone by Biome and Prettier
doctor counts the warnings instead of calling the setup healthy
Corrigido · 2
The Vite plugin slowed large builds: its hooks now filter the modules they receive
A CommonJS verbaly.config.js stayed cached in long-lived processes like the MCP server
A 0.69.0 tipou cada t, e com isso recusou qualquer chave guardada numa string qualquer, então o código que lê suas chaves de dados, e cada migração vinda de outra biblioteca, começava cheio de erros. Agora uma chave que você escreve à mão continua conferida contra o seu catálogo, com seus params, e uma chave que vem de dados compila como está. Não há nada a mudar no seu código.
Destaques
Chaves que vêm de dados voltam a compilar.t(item.key) e t(`status.${s}`) funcionam em cada t sem cast, enquanto uma chave que você escreve à mão continua conferida contra o seu catálogo, params incluídos, e o seu editor continua a completá-la.
A mesma regra para uma instância que você cria. Em createVerbaly({ messages }), um erro de digitação agora nomeia a chave que errou, e uma chave que vem de dados também passa ali.
Alterado · 1
A key held in a string, or a template with a part from data, passes in every t; a key written by hand is still checked, params included
Corrigido · 1
A typo on an instance built from a dictionary names the key instead of the tagged template
Cada t do seu projeto agora confere as chaves contra o seu catálogo, e os tipos gerados ficam onde o seu framework já os lê. Esta versão corrige o que uma auditoria da 0.68.0 encontrou no que você toca primeiro: os tipos, o servidor do Next.js, as linhas de instalação e a troca de idioma. O Next.js ganha também traduções sem requisição e texto rico em Server Components. Breaking, só nos tipos: uma chave guardada numa string qualquer não compila mais.
Destaques
Chaves tipadas em cada t.useT() em React, Vue e Svelte, getT() no Next.js e o t de qualquer instância conferem cada chave e seus params contra o seu catálogo. Um erro de digitação faz o tsc falhar, e o erro nomeia a chave. Breaking: uma chave guardada numa string qualquer não compila mais: declare-a com defineKeys, ou marque-a as VerbalyKey.
Os tipos são escritos onde o seu framework procura.src/verbaly.d.ts em apps Vite e SvelteKit, .verbaly/types.d.ts no Next.js (o Verbaly o adiciona ao seu tsconfig.json), e as pastas que o Astro e o Nuxt reservam para isso. A CLI e o servidor de desenvolvimento escrevem o mesmo arquivo, o antigo da raiz some sozinho, e npx verbaly typegen os escreve no CI.
Next.js: traduções sem requisição, e texto rico no servidor.getT({ locale: 'es' }) funciona numa imagem OG, num sitemap ou num email e mantém a rota estática, e <Trans> renderiza em Server Components a partir de @verbaly/next/server.
O texto que o Verbaly não vê não fica mais calado. Quando um build ou um servidor de desenvolvimento começa, o Verbaly aponta cada arquivo fora do seu include que escreve t`…`, como components/ num app Next.js sem src/, com o padrão a adicionar. O doctor também os lista.
Trocar de idioma mantém o resto do endereço.switchLocale mantém o ?q= e o #anchor.
Detalhes que incomodavam:init e doctor imprimem a linha de instalação do README no seu próprio gerenciador de pacotes, um catálogo com quebras de linha do Windows não é mais reescrito quando nada mudou, e o servidor MCP vê um verbaly.config.mjs editado sem reiniciar.
Adicionado · 6
Register, Translate and Locale in verbaly: the types every t of your project reads
npx verbaly typegen writes the types alone, for CI before tsc
getT({ locale }) in Next.js, for an OG image, a sitemap or an email
A <Trans> for Server Components in @verbaly/next/server, and @verbaly/react/server for any React Server Component
Builds and dev servers name each file outside include that writes a t`…`, and doctor lists them
doctor checks the types where your framework reads them, and the tsconfig line in Next.js
Alterado · 4
Breaking, in types: useT, getT and an instance t take only your keys, so a key held in a plain string needs defineKeys or as VerbalyKey
The types move to src/verbaly.d.ts, to .verbaly/types.d.ts in Next.js, or to Astro's and Nuxt's own folder, and the old root file is removed
Breaking for code that builds one: ResolvedConfig.dts is never undefined
init and doctor print the install line from the README, in your package manager
Corrigido · 11
An instance from the generated module no longer takes any key
The types reach a Vite or SvelteKit app, whose tsconfig never read the project root
extract no longer declares the types twice in Astro and Nuxt
A typo in a key names the key instead of the tagged template
The <Trans> written with children compiles in TSX
The order of the generated types no longer depends on the machine
The MCP server sees an edited verbaly.config.mjs without a restart
A catalog with Windows line endings is no longer rewritten when nothing changed
The MCP catalog resource, pseudo and render read the text that ships
switchLocale keeps the query and the hash
A broken config no longer ends an unplugin build with a raw stack
A 0.67.0 prometeu que nada muda pelas suas costas. Uma auditoria encontrou os lugares onde isso ainda falhava, e esta versão os fecha pela raiz. Uma tradução desatualizada é detectada seja quem for que a escreva, cada comando lê o texto que de fato é publicado, uma chave mostra sempre as mesmas palavras, nada do estado de revisão se perde em silêncio, e os servidores de desenvolvimento dizem o que importa uma vez. Nada novo quebra o seu build.
Destaques
Uma tradução desatualizada é detectada seja quem for que a escreva.translate, import, o Studio e o verbaly_write_drafts de um agente registram para qual texto fonte uma tradução foi escrita no momento em que a escrevem, e o import o pega do arquivo do tradutor. Um texto fonte que muda antes do próximo extract, ou um arquivo feito para um texto anterior, fica marcado em vez de ser aceito em silêncio.
Cada comando lê o texto que é publicado.check --outdated, status, review, translate, export, import, o Studio e o servidor MCP leem o texto do seu código onde o código é o dono dele, então o CI não deixa mais passar uma tradução que o build publica ao lado de um texto mais novo.
Uma chave, as mesmas palavras em todo lugar. Quando uma chave tem dois textos, vence o que foi escrito primeiro pelo caminho do arquivo, no extract, em cada build e nos dois servidores de desenvolvimento. Antes dependia da ordem em que os arquivos eram lidos, que mudava de uma execução para outra.
Nada do estado de revisão se perde em silêncio.extract --locales es deixa os outros idiomas em paz, o arquivo de rascunhos antigo de um colega é mesclado em vez de descartado, e um arquivo de estado ilegível para os comandos que escrevem rascunhos antes que escrevam qualquer coisa.
--prune mantém as traduções que um t com outro nome lê, também em arquivos .vue, .svelte e .astro, e agora o aviso aparece lá.
Os servidores de desenvolvimento dizem o que importa, uma vez. O Vite dev nunca escreve um texto velho de volta por cima de um checkout, um catálogo salvo pela metade é uma pausa de uma linha nos dois servidores, e um aviso volta se o problema voltar.
Adicionado · 4
syncProject, the one path from your code to the catalogs, used by the CLI, the MCP server, Studio and the dev servers
review shows each translation next to its source text, and --approve takes keys to accept only those
verbaly_extract returns replaced texts, nameless values and escaped blocks, and status and missing report a broken state file
Vite dev reports outdated translations and a t under another name
Alterado · 4
Breaking for code that reads it: syncCatalogs().replaced lists each key with the text it had, and added no longer counts a replaced text
extract prints one line per text that followed the code, with the text it had, instead of a warning
A t under another name counts only when it comes from Verbaly
Every line in a report comes from the parse, so it matches the code that was read
Corrigido · 9
extract --locales no longer erases the review state of the other languages
The text that wins when one key has two texts no longer depends on file order
A translation is stamped when it is written, so a later source change is never missed
--prune keeps the translations read by a t under another name, in components too
Vite dev never writes an old text back after a checkout, and survives a broken catalog
check --outdated reads the text that ships, and lists outdated translations with the failures
A broken state file warns where it is only read, and stops writes before they happen
Dev warnings come back when their problem does, a few at a time
next typegen works under Yarn PnP, and a failed gate prints its report once
O Verbaly deixa de esconder coisas de você. Uma tradução escrita para um texto que já mudou fica marcada, dois textos com a mesma chave são reportados com os dois lugares, e dev e build sempre mostram as mesmas palavras. No Next.js, next typegen não para mais por traduções faltando, e agentes podem salvar as próprias traduções como rascunhos. Nada novo quebra o seu build.
Destaques
Traduções desatualizadas ficam marcadas. Mude um texto fonte e as traduções escritas para o anterior aparecem em status, check e doctor até alguém atualizá-las ou mantê-las com verbaly review --approve. check --outdated pode fazer isso falhar no seu CI.
Dev e build sempre mostram o mesmo texto. Um texto escrito no seu código vence uma edição à mão no catálogo, no dev e no build da mesma forma, e o Verbaly diz onde esse texto vive em vez de substituir a sua edição sem avisar.
Dois textos com a mesma chave são reportados, com os dois lugares. Antes o segundo sumia sem aviso.
next typegen funciona mesmo com traduções faltando. O gate do Next.js agora roda quando o build já compilou, não ao carregar a config, e next experimental-analyze não precisa mais de um next dev antes.
extract --prune também limpa os rascunhos, e agentes salvam as próprias traduções como rascunhos com a nova ferramenta MCP verbaly_write_drafts, assim ninguém edita à mão o arquivo de rascunhos. Esse arquivo agora é .verbaly-state.json, e o antigo migra sozinho.
No React, useT() entrega um t novo quando o idioma muda, assim useMemo(…, [t]) acompanha.
Adicionado · 5
Outdated translations: status counts them, check warns, check --outdated fails, review lists them and review --approve keeps them
verbaly_write_drafts, the MCP tool an agent saves its own translations through, as drafts
import --draft keeps what a file brings as drafts
extract and doctor name a key written with two texts, a t under another name and a value a translator would see as {_0}
verbaly_extract, verbaly_missing and verbaly_status return the new findings as data
Alterado · 4
The drafts file is now .verbaly-state.json, shared with the fingerprints, and the old one moves over on its own
Breaking for code that imports it: DRAFTS_FILE is now STATE_FILE in @verbaly/compiler
A text written in your code wins over the catalog in the build too, and check validates translations against it
The Next.js gate runs after the compile
Corrigido · 8
extract --prune takes the drafts of the keys it removes
Two t.id texts under one key are reported with both places
A translation older than its source text is no longer silent
Dev and build no longer show different text after a hand edit of a text the code owns
next typegen no longer fails on missing translations
next experimental-analyze works without a previous next dev
useT() in React returns a new t when the language changes
A t under another name is reported instead of skipped in silence
Um arquivo com um erro não deixa mais o extract --prune apagar traduções, chaves com nomes como toString ou constructor não derrubam mais o gate, e a tradução automática funciona com qualquer modelo atual do Claude, com o Sonnet 5.5 por padrão. O Next.js para de baixar um catálogo duas vezes, e o seu build agora diz em uma linha quando o check tem avisos. Nada novo faz o seu build falhar.
Destaques
O extract --prune não apaga mais uma tradução porque um arquivo tem um erro. Enquanto algum arquivo fonte não puder ser lido, o prune espera e aponta o arquivo. Antes, cada chave que só aquele arquivo usava perdia a tradução em todos os idiomas.
Chaves com nomes como toString ou constructor não derrubam mais o check, o doctor nem o seu build. Uma tradução que tinha uma parava o gate com um erro sobre matchAll. Agora é uma chave como qualquer outra.
A tradução automática usa o Claude Sonnet 5.5 por padrão, e funciona com qualquer modelo atual do Claude. Escolher o Sonnet 5.5 ou o Opus 5.5 com --model fazia cada batch falhar. Um batch que o modelo recusa agora passa para um modelo de reserva em vez de voltar sem tradução.
O Next.js baixa cada catálogo uma vez só. A página não pede de novo o catálogo que o servidor já mandou, e o build só reescreve os arquivos que o verbaly extract lê.
O seu build agora avisa quando o check tem avisos, em uma única linha, e continua passando.
Árabe ou hebraico escritos como ar_EG ou he_IL são lidos da direita para a esquerda, e um armazenamento do navegador cheio não bloqueia mais uma troca de idioma.
Adicionado · 4
One line in the build when check has warnings
doctor warns on routing prefix-all next to a render section, and on a catalog file that is not an object of messages
A batch the model declines goes to a fallback model, and a decline names its category
verbaly_extract returns the files it could not read
Alterado · 3
The default translation model is claude-sonnet-5-5, at the same price
writeDts follows the dts option of your config when no file is named
Supported: SvelteKit 2 and 3, Preact 10 and 11
Corrigido · 10
extract --prune no longer deletes translations while a source file does not parse
Keys named like toString, constructor or __proto__ no longer crash check, doctor or the build
doctor reads a catalog with a byte order mark the way the build does
A catalog file that is JSON but not an object is reported instead of overwritten
The Claude provider works with Sonnet 5.5, Opus 5.5 and Fable 5.1
The Next.js client no longer downloads the catalog the server already sent
The Next.js loader only rewrites the files verbaly extract reads, and dts: false writes no types file
A directory the watcher cannot open no longer stops next dev or extract --watch
Arabic and Hebrew written with an underscore read right to left
A full browser storage no longer blocks a language switch
A tradução automática não sobrescreve mais uma mensagem que você corrigiu enquanto ela rodava, os nomes que os objetos de JavaScript já trazem não podem mais quebrar uma página, e um idioma escrito como pt_BR deixa de quebrar números e datas. Três problemas que passavam despercebidos agora vêm com um aviso, e nenhum deles faz o seu build falhar. Se você usa mensagens ICU com TypeScript, os parâmetros delas agora têm tipo, então uma chamada que os omitia aparece como erro de tipo.
Destaques
A tradução automática nunca sobrescreve o seu trabalho. Se você corrige uma mensagem enquanto verbaly translate, o Studio ou um agente estão traduzindo, o seu texto fica, e a execução diz quantas deixou como estavam.
Os nomes que os objetos de JavaScript já têm não podem mais quebrar uma página. Um idioma, um formato, uma tag rich ou um grupo do catálogo chamado constructor, toString ou __proto__ podia derrubar um render ou virar um link vazio. Agora é um nome como qualquer outro.
Um idioma escrito como pt_BR não quebra mais números, datas e plurais. Eles o leem como pt-BR e avisam uma vez. O doctor aponta, o init escreve certo, e o import preenche o seu pt-BR a partir de um arquivo pt_BR do gettext.
Três problemas silenciosos agora vêm com um aviso, e nenhum deles faz o seu build falhar: uma chave que só uma tradução tem (o Studio também a mostra no resumo), um nome de idioma que o navegador não consegue ler, e um app Next.js cujas URLs levam o idioma enquanto a config diz que não.
No Next.js, trocar de idioma segue as suas URLs. Com routing: 'prefix-all' na sua config, o useSwitchLocale() vai para a mesma página no novo idioma, sem opções para passar.
Observar mudanças no Linux ficou bem mais leve. O next dev e o verbaly extract --watch deixam de percorrer node_modules, o que podia esgotar o limite de arquivos observados do sistema antes de chegar ao seu código.
Adicionado · 4
A warning for a key that only one translation has, in check, doctor, the MCP server and Studio's overview
doctor names a language code the browser cannot read, and init writes a typed pt_BR as pt-BR
import reads a file's pt_BR as your pt-BR, and starts a new language under its proper code
useSwitchLocale follows the routing in your config, and setRequestLocale warns when that routing contradicts a [locale] segment
Alterado · 2
Two runtime warnings got shorter, and their explanation moved to the troubleshooting page
The runtime is 3.31 KB, and a site with no framework ships 6.09 KB
Corrigido · 10
A translate run no longer overwrites a message someone saved while it ran
Names like constructor, toString or __proto__ in languages, formats, loaders, rich tags and catalog groups
A language code Intl cannot read no longer throws when formatting numbers, dates or plurals
The tagged template no longer throws on a value that cannot become text
switchLocale without supported builds the right URL when the language is in the URL
A page's own catalog can no longer swallow the rest of the page
extract --prune no longer deletes the translations of keys written in backticks
ICU messages get their parameter types
A batch the model declined is reported as declined, and not retried
next dev and extract --watch no longer walk node_modules on Linux
Um parâmetro ruim deixa de derrubar a renderização
Um parâmetro que o JavaScript se recusa a transformar em texto fazia o Verbaly lançar, e o caminho que deveria absorvê-lo lançava também. Agora a mensagem é renderizada sem ele e o Verbaly avisa uma vez.
Destaques
Um parâmetro ruim já não pode derrubar uma renderização. Se um valor não pode virar texto, a mensagem é renderizada sem ele e o Verbaly avisa uma vez, do mesmo jeito que faz com qualquer outro valor ruim.
O JSON te dá essa forma de graça. Um payload com um campo chamado toString contendo um objeto é JSON válido, então um CMS ou um catálogo carregado em tempo de execução podia trazê-lo até a sua página.
Nada muda num projeto que estava bem. A verificação só roda onde um parâmetro já era inutilizável.
Corrigido · 1
A parameter that cannot be turned into text no longer throws, in every message shape: plain interpolation, the numeric formats, date, time, list, relative time and plurals
Cada linha de mensagem no Studio agora tem o seu menu. Copie a chave, copie o texto original, edite ali mesmo, veja quais arquivos usam uma mensagem, e veja o commit que a mudou pela última vez, que é a única coisa que o painel nunca soube responder.
Destaques
Cada linha de mensagem tem o seu menu. Copie a chave, copie o texto original ou comece a editar, sem sair da tabela.
Veja o commit que mudou uma mensagem pela última vez. O Studio lê o histórico dos seus catálogos e nomeia o commit, quem o escreveu e o que ele dizia. Ao clicar, o sha curto é copiado, então um git show no seu terminal fica a uma colagem de distância.
Veja quais arquivos usam uma mensagem, direto da linha. Quando é mais de um, ele diz quantos, e abre na lista inteira.
Quando não há resposta, o menu diz de que tipo é esse não. Uma mensagem que você ainda não commitou, uma mais velha que o histórico que o Studio leu, e um projeto sem git são três coisas diferentes, e são lidas como três coisas diferentes.
No menu não há nenhum botão que não faça nada. A entrada de IA que o desenho pede não está lá, porque o assistente que ela chamaria ainda não existe.
Adicionado · 2
A menu on every message row: edit here, copy the key, copy the source text, the commit that changed it, and where it is used
An address that answers which commit last changed one message, or why there is none
Alterado · 1
Where it is used tells a config that turned scanning off apart from a key no file in your code mentions
Marque um único idioma e o Studio para de comparar. Ele diz que o trabalho já foi ao ar e que nada está quebrado, e coloca no topo os poucos que merecem leitura, com o motivo escrito ao lado de cada um.
Destaques
Você marca um idioma e recebe aquele idioma. Uma barra sobre a tabela diz quantas mensagens ele tem, que elas já estão no seu site, e que a verificação que o seu build roda passa. A tranquilidade vem primeiro porque é a parte verdadeira.
Cada linha que merece uma olhada diz por quê, com palavras, bem ao lado. Não que um link mudou, mas qual. Não que os números se mexeram, mas que a fonte diz 20 e esta diz 22.
Marque um idioma inteiro como lido com um clique, e desfaça. Não há diálogo de confirmação, porque você continua editando na linha e o desfazer espera na barra lateral.
Um idioma na barra lateral mostra tudo o que falta, não apenas o pior. Antes lia uma quebra o seu site para um idioma que também tinha uma faltando, então a segunda ficava invisível.
Adicionado · 2
A view for a single language: its own bar, three filter chips and a reason beside each flagged row
A nothing odd filter, the exact opposite of worth a look, so the two together are the whole language
Alterado · 2
A reason names its evidence: the language and both renderings, the sibling key, the number or the link that moved
A language is called by its own name in the rail and in the bar, with its tag kept beside it
Três verificações que não eram tão rígidas quanto pareciam
Uma revisão da própria rede de segurança do Verbaly encontrou três coisas que ele prometia e não cumpria por completo: uma verificação de URL que o navegador ignora sem perceber, uma busca de mensagem que podia responder com algo que não é uma mensagem, e formatos de número que imprimem NaN sem dizer nada. As três estão fechadas.
Destaques
Um link que vem do seu catálogo já não pode levar uma URL javascript: para a sua página. A verificação lia o texto como estava escrito, e o navegador apaga tabulações e quebras de linha de uma URL antes de lê-la, então um link podia passar. Agora é verificado do jeito que o navegador lê.
Uma mensagem chamada toString ou constructor está faltando, não vazia. Esses nomes pertencem a qualquer objeto de JavaScript, então a busca encontrava o do objeto em vez do seu, e você recebia uma string vazia sem nenhum aviso.
Um formato de número que recebe algo que não é um número avisa. Um preço com um valor de texto renderizava NaN, e um preço sem valor nenhum renderizava um 0,00 cheio de confiança. Os dois agora mostram o valor puro e dizem de qual mensagem vieram.
Nada muda em como você escreve suas mensagens. Tudo isso só roda quando algo já está errado, então um projeto que estava bem continua exatamente igual.
Alterado · 2
The blocked-href warning names the scheme instead of the URL, so its dedupe set stays bounded
A malformed data-verbaly-attr names itself in the warning instead of naming data-verbaly-args
Corrigido · 4
safeHref checks the URL the way a browser reads it: tab, line feed and carriage return removed from anywhere, leading control characters trimmed
flatten hands back a null-prototype map, and addMessages no longer undoes it
The five numeric formats validate their argument and degrade with a warning instead of rendering NaN
An auto-formatted NaN warns too, which covers the number inside a plural
A pesquisa só olhava para os idiomas que você tinha marcados, por isso uma palavra espanhola com espanhol desmarcado não encontrava nada e nunca dizia por quê. E os grupos que as suas chaves já declaram não estavam em tela nenhuma. Os dois estão corrigidos, e funcionam juntos.
Destaques
A pesquisa encontra uma palavra em qualquer idioma, não só nos que você marcou. Antes o campo filtrava a tabela, por isso só via o que a tabela mostrava. Agora lê o seu catálogo inteiro.
Cada resultado diz em que idioma o encontrou. É isso que uma tabela filtrada não te pode dizer: a mesma palavra costuma existir só num dos seus idiomas.
Command K abre a busca, as setas movem, enter te leva à mensagem. Desce até à linha esteja onde estiver, mesmo muito abaixo do que a tela tinha carregado.
As suas chaves já tinham grupos, e agora o painel os mostra. Você escolhe um na barra e a tabela, as suas contas e os comandos se restringem a ele. Um resultado de pesquisa diz em que grupo vive.
Adicionado · 3
Groups: the first segment of a key, as a filter in the rail and a label on a search result
A search sheet that reads every language and marks what you typed
Keyboard throughout: Command K to focus, arrows to move, enter to open, esc to close
Alterado · 1
The box in the bar opens the sheet instead of filtering the table
Antes abria na tabela, sem te dizer quais das suas mensagens estavam à espera nem se o seu projeto estava saudável. Agora a primeira tela o diz, e a última coisa que mostra é real: os commits que tocaram nos seus catálogos.
Destaques
O Studio abre num resumo, não numa tabela. O que está à sua espera, uma linha cada coisa com o seu próprio botão, e se o projeto está saudável. Clicar em uma te leva exatamente a essas mensagens.
As últimas alterações dos seus catálogos, a partir do git. Commits a sério sobre o seu diretório de catálogos, com quem e quando. Um projeto sem git simplesmente não mostra o cartão, em vez de o mostrar vazio.
Uma chave que o seu código chama e que nenhum catálogo define finalmente aparece. Já fazia falhar o seu build, e até agora o único lugar onde você podia vê-la era a linha de comandos.
Adicionado · 3
An overview as the panel's first screen, with what is waiting for you and the project's health
The recent commits over your catalog directory, read from git
A rail you can navigate: Overview, Messages and Health
O seu catálogo mantém a ordem em que você o escreveu
Dois lugares onde o Verbaly fazia em silêncio algo diferente do que dizia. Reescrevia o seu catálogo por ordem alfabética sem o mencionar, e te dizia que uma tradução estava verificada sem nunca ter olhado para dentro de uma mensagem ICU. Os dois estão corrigidos na origem.
Destaques
O seu catálogo mantém a ordem em que você o escreveu. Tudo o que escrevia um catálogo reordenava o arquivo inteiro por ordem alfabética, por isso a primeira gravação transformava um arquivo ordenado à mão num diff de todas as suas linhas. No catálogo deste próprio site eram 1817 de 1823 linhas, e agora são zero.
As verificações finalmente olham para dentro de uma mensagem ICU. Uma tradução que achatava um plural ICU em texto simples, ou que lhe tirava um parâmetro, saía limpa. Agora é detectada, no verbaly check, no que uma tradução automática pode devolver e no que um arquivo importado pode trazer.
A pré-visualização ao vivo do Studio diz o mesmo que diz o build, ICU incluído. Antes ficava verde sobre uma mensagem que o servidor depois recusava.
Corrigido · 4
A catalog is written back in the order its file already had, deciding level by level
verbaly migrate stops reformatting the very file it is migrating
The checks read an ICU message with the ICU parser, so its parameters and plurals are compared
verbaly check no longer tells you to pass an icu option to createVerbaly
Há três versões o Studio era uma só coisa que você executa. Depois ganhou três pontos de entrada, um peer opcional e um capítulo do README sobre desenhar o painel à mão, e tudo isso existia para que uma página deste site o pudesse importar. Já não está, e o que você instala volta a ser um comando.
Destaques
Você instala @verbaly/studio e não há nada para importar. Um comando, nenhum peer para acrescentar, e nenhum .svelte que o seu bundler tenha de compilar. O pacote volta a ter uma só entrada.
Quebra: saem três pontos de entrada, e svelte deixa de ser uma dependência peer. Saíram na 0.56.0 e tinham um único consumidor no mundo, a página de demonstração deste site.
Nada mudou na forma de executar o Studio.npx verbaly-studio abre a mesma tela, sobre os mesmos arquivos, com os mesmos comandos.
Corrigido · 2
The panel was see-through inside another page, so you read your own site through it
The README and the API quoted a catalog size that ages with every release
O Studio abria sobre um projeto ainda por configurar e te dizia para marcar um idioma que não existia. Agora cada tela vazia e cada botão desligado diz o que se passa de fato, que é a parte de o levantar que uma pessoa realmente lê.
Destaques
A tabela vazia deixou de pedir o impossível. Com um só idioma na sua config não há nada para marcar, por isso te diz que você tem um idioma e onde acrescentar o seguinte.
Quatro telas vazias, uma frase cada uma: sem catálogos, um só idioma, nenhum marcado, e um filtro que não encontrou nada. Cada uma nomeia um fato, não um botão.
Um comando que não pode rodar está desligado, e diz por quê. Com a leitura do código desativada na sua config, Procurar texto novo já não espera que você clique nele para te devolver um erro.
Corrigido · 3
The empty table told you to tick a language when there was none to tick
Find new text was offered on projects whose config turns scanning off
Translate what is missing gave the wrong reason when a project has one language
Ao Studio entrega-se aquilo com que fala em vez de ele ir buscá-lo, e é isso que transforma o painel de uma página que o comando serve em algo que você pode pôr na sua. E finalmente abre escuro numa máquina escura.
Destaques
O painel abre no tema da sua máquina. Tinha uma paleta escura e nenhuma forma de lá chegar, por isso o npx verbaly-studio abria claro num ambiente escuro.
Já nada dentro do painel sabe da rede. Ele recebe o que deve chamar, por isso os mesmos componentes rodam sobre um servidor de verdade ou sobre qualquer outra coisa que responda igual.
O painel pode ser desenhado na sua própria página, se a sua página compilar Svelte 5: os componentes a sério, sobre qualquer coisa que responda como o servidor responde.
Tudo o que desenha vive numa só classe. As suas cores e o seu modelo de caixa já não conseguem chegar à sua página, que foi o que tornou possível metê-lo dentro de outro site.
Instalá-lo não mudou nada. O npx verbaly-studio não traz Svelte nem pede nada de novo: o painel que serve já vem construído.
Adicionado · 2
The panel components, for a page that compiles Svelte 5
The panel stylesheet, on the single class verbaly-studio
Corrigido · 3
The panel had a dark palette that nothing ever turned on
Its stylesheet painted the host page rather than only itself
Its shell measured itself against the window instead of the box it was given
O Studio publicou o seu servidor há duas versões e dizia, no seu próprio README, que faltava a tela. Esta é a tela. Abre com as suas mensagens, te deixa corrigir uma onde você está lendo, e roda os dois comandos que mudam os seus catálogos, com o orçamento à frente do que custa dinheiro.
Destaques
A tela que a versão anterior do Studio prometeu.npx verbaly-studio abre agora uma página com todas as mensagens do seu projeto, nos idiomas que você marcar, e o estado de cada uma.
Você corrige uma tradução na própria linha onde ela vive. Não se abre nada: a linha que você está lendo passa a ser o campo onde você escreve, e te diz o que está errado enquanto você escreve.
Os estados se chamam pelo que significam para você: pronta, em falta, escrita por uma máquina e ninguém a leu, ou quebra o seu site. Cada um tem a sua própria forma além da cor.
Da página rodam dois comandos. Um lê o seu código e acrescenta o texto que os seus catálogos não têm. O outro traduz o que falta, e como esse gasta dinheiro te mostra o orçamento antes de chamar seja o que for.
Uma tiragem de tradução é algo de que você pode ir embora. Recarregue a página e a barra de progresso volta, porque pergunta à tiragem como vai em vez de ficar escutando.
O que uma máquina escreve continua sendo um rascunho. Uma tiragem terminada te deixa uma lista para ler, não um trabalho dado por concluído.
Adicionado · 4
The Studio panel: the list, editing in place, drafts, health and filters
Find new text and Translate what is missing, run from the page
The plan is its own address, so seeing the cost cannot start the spending
A run in progress survives a reload of the page
Corrigido · 3
Progress counted batches, which run in parallel, so the bar could walk backwards
The panel translated with different settings than the command uses
Finding new text reported a count that summed every language
Alguém perguntou quanto é preciso aprender antes de o Verbaly servir, e a resposta acabou sendo um problema de documentação e não de produto. Três das quatro coisas que a nossa página de migração pedia nunca foram necessárias: um catálogo tal como sai do i18next já passa, com os grupos e tudo. Esta versão apaga esse trabalho da página e passa a única mudança real para um comando.
Destaques
Um comando novo: npx verbaly migrate. Aponte-o para um projeto que use outra biblioteca de i18n e ele te passa os catálogos que você já tem. Primeiro mostra o que faria, e --write aplica.
Os seus arquivos mantêm a forma. Os grupos continuam sendo grupos, e o comando devolve exatamente a disposição que o seu arquivo já tinha. Não se reformata nada.
Uma só coisa tem mesmo de mudar, e você já não a faz à mão: {{name}} passa a {name}. Uma chave duplicada é como o Verbaly escreve uma chave literal, por isso as duas formas não podem significar o mesmo.
O que não vai adivinhar, ele te diz. Um formato dentro das chaves, um valor sem escape, ou uma junção que apagaria uma key que você usa ficam listados com o motivo, e essas mensagens ficam exatamente como estavam.
Juntar as suas keys de plural é opcional.--plurals junta _one e _other numa só mensagem, que é o que liga a seleção de plural automática, e então o número se escreve já localizado. Deixe-o desligado e essas keys continuam funcionando.
A nossa página de migração deixou de pedir trabalho que nunca foi preciso. Antes te dizia para achatar os seus grupos, juntar as suas keys de plural e renomear os seus namespaces. Nenhuma das três foi alguma vez obrigatória.
Adicionado · 2
verbaly migrate: ports catalogs from i18next, vue-i18n, react-intl and friends
It reads both i18next plural spellings, including the one used before v21
Corrigido · 3
The migration guide asked for three transformations that were never required
The same wrong claim lived in eight places across the docs and the package READMEs
The editor tip recommended one catalog style to everyone; it now tells you to match your own
Você já pode ver o seu projeto inteiro num endereço da sua própria máquina. npx verbaly-studio lê todos os seus catálogos de uma vez e te deixa escrever uma tradução de volta, verificada da mesma forma que o seu build a verifica. Os seus arquivos JSON são o banco de dados e o git é o histórico, por isso não pode se desalinhar do seu código: não é dono de nada. Esta primeira versão traz a parte de baixo, não a tela de cima, e o diz ela mesma.
Destaques
Um pacote novo: @verbaly/studio. Rode npx verbaly-studio dentro do seu projeto e ele te serve tudo o que o Verbaly sabe sobre ele na sua própria máquina: cada catálogo, o que falta, o que está quebrado, o que uma máquina escreveu e onde cada mensagem é usada no seu código.
Esta versão é o servidor, não a tela. Ainda não há painel. O que funciona hoje é o endereço que serve e --json, que imprime o mesmo que a tela vai ler, por isso você já pode passá-lo por um script. A tela vem a seguir.
Nunca mexe no seu texto de origem. Esse texto vive no seu código e a key vem dele, por isso escrever por cima aqui seria desfeito da próxima vez que você extrair. Salvar no seu idioma de origem é recusado, e uma key que a sua origem não tem também.
Uma tradução que você salva é verificada antes de entrar. Passa as mesmas duas verificações que o seu CI passa, por isso um {name} perdido, uma etiqueta perdida ou um plural sem o caso geral é recusado com o motivo, em vez de passar aqui e quebrar o seu build depois.
Nada do que lê o consegue derrubar. Um catálogo que não consegue ler, um arquivo de rascunhos que não consegue ler, um arquivo de código que não compila, ou apontá-lo para a pasta errada são avisados pelo nome, e o resto carrega mesmo assim. É o que você abre para corrigir esses arquivos, por isso tem de abrir.
Te diz quais traduções automáticas vale a pena ler primeiro. Acrescentar um idioma escreve centenas de uma vez, e lê-las uma a uma é um muro. Seis sinais apontam para as poucas que pedem os seus olhos: no nosso próprio site são 18 mensagens em 1425 por idioma.
Adicionado · 4
A new package, @verbaly/studio, with the verbaly-studio command
Four addresses it answers on: the whole project, its health, writing one translation, and approving drafts
Three defences on by default: it listens only to your own machine, it checks who is asking, and it mints a fresh key every time it starts
Triage: six signals that point at the machine translations worth reading first
Alterado · 2
The compiler hands out seven more pieces, each one because the new package needs it
Its API table and what it actually exports are now checked against each other, and six names had been missing
Corrigido · 1
A sentence in one of our own error messages did not agree with itself
Um link dentro de uma frase te deixa no seu idioma
Num site publicado em vários idiomas, todos os links escritos à mão já levavam o idioma do leitor, e os escritos dentro de uma frase traduzida não. Clicar num deixava um leitor em espanhol nas páginas em inglês, e por isso parecia tão estranho: o resto da página estava bem. Era assim desde que existem links dentro de mensagens, escondido atrás de dois testes que o davam como certo.
Destaques
Clique num link dentro de uma frase traduzida e você fica no seu idioma. Até agora esses links apontavam para o seu idioma de origem, por isso quem clicava em "veja o guia" no meio de um parágrafo em espanhol ia parar na página em inglês.
Estava escondido atrás de dois testes que o afirmavam. Um deles percorre o site traduzido inteiro com um visitante, por isso a suite continuava verde enquanto o problema era publicado. Os dois esperam agora o endereço correto.
Uma página traduzida leva os seus próprios links. Já não precisa da lista de links da sua configuração quando chega ao navegador, por isso nada consegue reconstruir um link sem o seu idioma.
Os formulários vão com eles. Submeter é navegar, por isso um formulário que aponta para uma página que você publica em todos os idiomas fica dentro desse idioma.
Alterado · 1
Form targets get the same treatment as links, and what must never be rewritten is now pinned by a test
Corrigido · 2
Links written inside a translated sentence sent the reader to your source language
And the browser rebuilt them without the language even when the page had them right
Uma página traduzida continua traduzida ao navegar
A versão anterior fez cada página levar as suas próprias mensagens, e errou na segunda: num site com routing de cliente, ao clicar num link o texto aparecia no seu idioma de origem até o visitante recarregar. Não era uma falha mas três, e por isso parecia tão total. As três estão corrigidas, e em Astro você não tem de escrever nada.
Destaques
A regressão da 0.50.0 acabou. Ler um site em espanhol e navegar por ele fica em espanhol: de página para página, de uma seção para o início, e ao trocar de idioma.
Eram três falhas, não uma. As mensagens que uma página levava eram lidas uma vez e nunca mais, o runtime não distinguia "esta página não trazia a palavra" de "este idioma não tem palavra para isso", e o intérprete de texto tratava a página que o router inseria como texto escrito por ele.
Em Astro se corrige sozinho. Ligar inlineCatalog passa a ligar também o router de cliente, por isso você não escreve nada. Qualquer outra montagem tem uma chamada, adoptPage, a partir do seu hook de navegação.
Trocar de idioma ficou mais barato pelo caminho. Passar de espanhol para português baixava o catálogo português inteiro; agora a página onde você chega já traz o que mostra, por isso a troca não custa nada a mais.
Adicionado · 2
A way to hand the runtime the next page’s messages when your router swaps the document
An option on the runtime merge so a page’s worth of messages does not count as the whole language
Alterado · 1
Dependencies to their latest stable versions in both repositories, pnpm included, with the whole suite green
Corrigido · 3
A page’s messages were read once per visit instead of once per page, so every page after the first read in your source language
A message the page did not carry looked like an ordinary fallback, so the rest of the language was never fetched
Text rendered by the server and swapped in by a router was overwritten with a fallback
Uma página traduzida para de baixar o dicionário inteiro
Até agora, abrir uma página em espanhol baixava todas as mensagens em espanhol que seu site tem, e a maioria essa página nunca mostra. Agora o mirror escreve em cada página exatamente as mensagens que ela renderiza, então a página não precisa de mais nada. Neste site, uma primeira visita à home deixa de baixar uns 50 KB, cerca de nove vezes o que custa o runtime inteiro do Verbaly.
Destaques
Uma primeira visita fica bem mais leve. Um visitante baixava 53 KB de mensagens em espanhol para ler uma página que usa 2.8 KB delas. Agora recebe os 2.8 KB, e eles chegam com a página em vez de como uma segunda requisição.
A economia é por página, e é quase o arquivo inteiro toda vez. Medido neste site: 50 KB a menos na home, 49 numa página de docs, 32 em novidades, que é a página mais pesada daqui.
Nada falta quando alguém interage. Se sua página pedir depois uma mensagem que não mostrou, o Verbaly busca o resto uma vez e atualiza, em vez de mostrar seu idioma de origem sem avisar.
É uma linha e vem desligado. Adicione inlineCatalog às suas configurações de render. Um projeto que não o liga é construído exatamente como antes.
Adicionado · 2
A render setting that writes into each page the messages it renders, so it downloads no others
A way to tell the runtime that a language arrived with the page, so it fetches nothing until something is actually missing
Alterado · 1
Dependencies to their latest stable versions, including three major ones, with the whole suite green
O servidor MCP conseguia contar suas mensagens, dizer quais faltavam e traduzi-las, e não conseguia te mostrar uma única frase. Isso tornava uma coisa impossível: revisar uma tradução de máquina através de um agente, porque te davam uma chave e pediam para aprovar. Agora um agente pode ler seus arquivos de idioma e suas configurações diretamente, e cada tradução que te espera vem com a frase de onde saiu.
Destaques
Um agente já pode ler o que uma mensagem realmente diz. Antes ele podia dizer que faltavam catorze traduções e não te mostrar nenhuma. Seus arquivos de idioma e suas configurações são lidos diretamente, e olhá-los não gasta uma das ações dele.
Revisar uma tradução de máquina finalmente funciona através de um agente. Você recebe cada uma que te espera ao lado da frase original, então pode ler as duas e decidir. Aceitar continua sendo só seu, de propósito: nenhuma ferramenta daqui pode aprovar uma tradução, e nenhuma poderá.
Um agente pode montar o Verbaly em um projeto do zero. Cria seu arquivo de configuração e seus arquivos de idioma, descobre qual bundler ou framework você usa, e te diz a única linha que você ainda precisa adicionar.
Nada do que você já usa mudou. Todas as ferramentas respondem exatamente como antes.
Adicionado · 3
Two addresses an agent can read: your settings, and every message of one language
A list of the machine translations waiting for you, each next to the sentence it came from
A way for an agent to set Verbaly up in a project from nothing
Alterado · 2
The tools are handed over in the order you meet a project, starting with setting it up
The dependency tree carries no known vulnerabilities: three were reported and all three are resolved
Quando suas páginas ficam em endereços como /es/dashboard, esse endereço é o que diz em qual idioma a página está. Até agora as integrações de servidor do Verbaly nunca olhavam para ele: perguntavam pela escolha salva do visitante e pelo navegador dele, então o mesmo link podia chegar em inglês para uma pessoa e em espanhol para outra. Agora o endereço manda, porque um endereço é compartilhado, linkado e cacheado enquanto uma escolha salva é de uma pessoa só.
Destaques
Uma página em /es/dashboard agora chega em espanhol, sempre. Antes o Verbaly perguntava pela escolha salva e pelo navegador em vez de ler o endereço, então o mesmo link podia mostrar dois idiomas diferentes para duas pessoas.
Suas páginas em inglês param de ser traduzidas por acidente. Quem escolheu português uma vez recebia português também nas suas páginas sem prefixo. Um endereço simples agora significa seu idioma de origem, para todo mundo.
As páginas do Next.js voltam a poder ser construídas com antecedência. O Verbaly lia os headers da requisição em cada página, o que em silêncio transformava cada página traduzida em uma que se reconstrói a cada visita. Entregue o idioma a partir do nome da sua pasta e a página volta a ser construída uma só vez.
Suas páginas traduzidas também podem falar umas das outras para os buscadores a partir de um servidor. Os links de idioma e o endereço canônico existiam só para sites construídos estaticamente, e o mesmo conjunto agora está disponível onde quer que você renderize.
As rotas do SvelteKit continuam simples. Uma linha e /es/docs é servido pela sua rota /docs, então você não duplica suas pastas de rotas por idioma.
Nada muda se seus endereços não levam idioma. Tudo isso é ativado com a configuração de URL que você já tem.
Adicionado · 4
A way to tell your server integration that the address carries the language, so the address decides
A hook for SvelteKit that serves every language from a single route tree
A way to hand Next.js the language from your folder name, which is what keeps the page built ahead of time
A helper that gives you one page’s address in every language, for the head of a server-rendered page
Alterado · 2
Nuxt reads the address on its own, with nothing extra for you to write
A statically built site and a server-rendered page now get their language links from the same place, so they cannot disagree
Corrigido · 3
A page with the language in its address could be served in another language, if the visitor had picked one before
Every translated Next.js page was being rebuilt on each visit instead of built once
Two setup examples in the package guides did not work as written
O normal no Verbaly é que você escreva texto e nunca veja uma key, e isso não muda. Esta versão cobre o outro caso real: keys que são um contrato com algo fora do seu app, um cliente móvel ou uma memória de tradução, escritas uma vez num módulo e lidas de qualquer lugar. Até agora o Verbaly não via essas keys, então limpar as mensagens sem uso as apagava e nada verificava que existiam. A segunda metade é o sitemap, que publicava redirecionamentos e páginas de erro como se fossem resultados.
Destaques
Você pode manter as suas keys num módulo e o Verbaly continua a verificá-las. Um arquivo que associa nomes a keys é uma forma que muitos projetos já escrevem. Antes o Verbaly não via essas keys: limpar as mensagens sem uso as apagava, e nada verificava que existiam.
Uma key que nenhum catálogo tem é um erro onde você a declara, não um espaço em branco que você descobre na interface mais tarde. O seu editor completa a partir do seu próprio catálogo enquanto você escreve o módulo.
O seu sitemap deixa de listar páginas que pedem para não serem indexadas. Os redirecionamentos e as páginas de erro eram publicados como se fossem resultados. Neste site eram 21 endereços de 81, e a lista agora são apenas as 60 páginas reais.
Essas páginas continuam sendo traduzidas e publicadas exatamente como antes. O que mudou foi só a lista de endereços, então quem chegar a uma continua recebendo a página no seu idioma.
Nada muda se você não usar nenhuma das duas. São adições, e um projeto que não escreva nenhuma comporta-se exatamente como antes.
Adicionado · 2
A way to declare your keys in a module, so Verbaly checks them and your editor completes them
A setting to leave a page out of the sitemap by name
Alterado · 1
The sitemap lists only pages a search engine should index, while every page is still translated and published
Corrigido · 1
An unknown key was reported with a long absolute path instead of the file you edit
Tudo o que se corrige aqui está no caminho que você percorre uma só vez, quando adiciona o Verbaly a um projeto que já existe: instalar, criar a estrutura, passar a verificação, envolver os seus textos e extraí-los. Nada disso está no caminho que você percorre todos os dias, e por isso mais de mil testes nunca viram. O comando que cria a estrutura ignorava a configuração que você já tinha escrito e criava um segundo conjunto de catálogos. Um arquivo solto na sua pasta de catálogos virava um idioma que você não conseguia remover. O comando que envolve os seus textos podia deixar um projeto sem compilar. Tudo isso fica resolvido, e uma verificação nova faz uma instalação real com dois gestores de pacotes para que continue resolvido.
Destaques
O verbaly init agora lê a configuração que você já escreveu. Antes ele a ignorava e criava um segundo conjunto de catálogos na pasta padrão e no idioma padrão. Se a sua configuração dizia espanhol em locale/, você recebia inglês em locales/.
Mudança importante: os idiomas que você lista na configuração são agora a lista inteira. Um arquivo JSON esquecido na sua pasta de catálogos virava um idioma que você nunca conseguia remover, e bloqueava compilações pedindo traduções que você nunca quis. Se você não os listar, os arquivos da pasta continuam decidindo, exatamente como antes.
O verbaly wrap --write já não deixa o seu projeto sem compilar. Antes ele envolvia texto em arquivos onde t não estava disponível. Agora ele pula esses arquivos, diz quais são e quantos textos esperam em cada um, e se são componentes de cliente para você saber que linha adicionar.
O envolvimento deixa de coletar coisas que não são texto de interface: o conteúdo dos blocos de código, palavras isoladas em minúscula como usuários de demonstração e nomes de arquivo, e frases que começam com um valor em vez de com palavras.
Quando o comando verbaly não está instalado, o Verbaly diz isso em vez de pedir que você o execute. A compilação nomeia o pacote a adicionar, e a verificação tem uma linha para isso.
Adicionado · 2
A health check that tells you whether the verbaly command is actually available in your project
A list of the files wrap refused to touch, with how many texts wait in each and whether it is a client component
Alterado · 5
Breaking: the languages listed in your config are the whole list, and a stray catalog file is no longer adopted
Scaffolding reads the config file you already wrote instead of falling back to its defaults
Wrapping writes only into files where t is already available, so the project always still compiles
Wrapping leaves code blocks, single lowercase words and sentences that open with a value alone
A build that blocks on missing translations names the package to install when the command it suggests is not there
Corrigido · 2
Asking for help with no command reported a failure
A catalog handed to the provider for the source language was quietly ignored
Um catálogo só cresce, e todas as páginas pagavam o catálogo inteiro
O texto que vive em uma única página, uma lista de versões, um arquivo de blog, uma lista longa de perguntas, era baixado por cada visitante em todas as páginas. Esta versão deixa você nomear esses grupos de mensagens e mantê-los no build. As páginas que os usam continuam saindo traduzidas, porque esse texto já está escrito no HTML, e o navegador para de baixá-lo. Procurar a prova revelou ainda um defeito real por baixo. Depois da primeira passagem, o Verbaly podia trocar texto traduzido correto da página pelo nome interno da mensagem quando essa mensagem faltava. Fica corrigido aqui, e importa para qualquer um que pré-renderize o seu site.
Destaques
O texto que só uma página precisa para de viajar para todas. Nomeie esse grupo de mensagens na sua configuração e o navegador não o baixa mais. As páginas que o usam continuam saindo traduzidas, porque esse texto já está no HTML.
O texto pré-renderizado não é mais destruído. Se uma mensagem faltar, o Verbaly mantém o texto que já está na página em vez de trocá-lo pelo nome interno da mensagem. Antes isso podia acontecer um instante depois de a página carregar.
Medido neste site: o arquivo que cada página carrega passou de 46,3 KB para 33,5 KB comprimido, e as árvores em espanhol e português baixaram cerca de 14 KB cada uma. Nada se perdeu na tela.
Nada muda se você não ativar. É uma opção nova, e um projeto que não a escreva se comporta exatamente como antes.
O build avisa quando algo parece errado, nomeando um grupo que não corresponde a nada do seu catálogo, ou um que o seu código lê diretamente.
Adicionado · 1
An option that keeps the groups of messages only the build needs out of the browser
Corrigido · 1
Pre-rendered text is no longer replaced by a message’s internal name when that message is missing
As nossas próprias verificações mediam a máquina, não o código
O job que verifica a nossa cobertura de testes falhava ao acaso, e a causa não era um teste lento. Um teste que leva 22 milissegundos era derrubado por um limite de 5 segundos, porque esse limite conta tempo real e o nosso comando de testes levanta doze processos sobre os mesmos núcleos. Duas vezes isso bloqueou uma publicação. Esta versão corrige na raiz, e dedica o resto à mesma ideia aplicada à nossa cadeia de suprimentos: o que o nosso build pode fazer, quais ferramentas ele roda exatamente, e código que nunca poderia ser executado. Nada do pacote muda.
Destaques
Nada do que você instala muda. O runtime é idêntico ao da 0.43.0 e toda a API publicada se comporta igual. Esta versão é sobre a maquinaria que nos verifica.
O nosso build parou de falhar ao acaso. A suíte podia derrubar um teste perfeitamente saudável só porque a máquina estava ocupada, e duas vezes isso bloqueou uma publicação.
Cada ferramenta que o nosso build roda está fixada em um commit exato. Uma tag pode ser movida por quem a controla, mas um commit não, então nada pode mudar em silêncio o que constrói o seu pacote.
O job que publica as versões pede permissão de escrita só onde precisa, em vez de dá-la a todo o fluxo.
A análise estática roda a cada mudança, e a sua configuração agora vive no nosso repositório, fixada e legível, em vez de ser um ajuste que só nós víamos.
Adicionado · 1
A CodeQL workflow, so the configuration of our static analysis lives in the repository instead of in a setting
Alterado · 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
O badge do nosso README diz ~3KB desde o começo, enquanto o runtime pesava na verdade 3,68 KB. Em vez de enfraquecer a afirmação, esta versão remove a última peça que valia a pena remover: o formato de tempo relativo são 318 bytes que quase nenhum aplicativo escreve, e agora só viaja quando alguma das suas mensagens o pede. O resto da versão é a mesma ideia apontada para tudo o mais que o projeto diz de si mesmo.
Destaques
O runtime pesa 3,00 KB. O formato de tempo relativo se junta ao ICU como algo que só viaja quando alguma das suas mensagens realmente o usa, e não há nada que você tenha que configurar.
Um formatador que você mesmo escreva agora sabe para qual mensagem foi chamado. Ele recebe o nome do parâmetro e a chave da mensagem, então os seus próprios erros podem dizer onde aconteceram, o que antes não dava.
A política de segurança cobre os doze pacotes, não os sete que existiam quando foi escrita, e agora explica como verificar que uma versão saiu mesmo do nosso CI.
A nossa postura de segurança é algo que você pode conferir em vez de algo que afirmamos: uma pontuação da OpenSSF roda a cada mudança e o badge do README a lê.
Adicionado · 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
Alterado · 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
A sintaxe própria do Verbaly cobre plurais, selects e formatos, e a sintaxe ICU é a saída para o que ela não cobre. Essa saída sempre foi descrita como algo opcional, e nunca foi: o parser entrava em todo aplicativo usando ICU ou não. O nosso próprio site de documentação não tem nenhuma mensagem ICU e o publicava em cada página. O Verbaly já lê os seus catálogos, então agora só manda o parser onde alguma mensagem realmente precisa dele.
Destaques
O runtime é 11% menor para quem não usa sintaxe ICU, que são quase todos os projetos. O parser só viaja quando alguma das suas mensagens realmente precisa dele, e não há nada que você tenha que ligar.
Nada muda se você usa ICU. O Verbaly vê isso nos seus catálogos e leva o parser junto, exatamente como antes.
Uma mensagem que chega ao seu aplicativo depois do build e usa ICU agora mostra o seu próprio texto e diz por quê, em vez de ficar meio renderizada em algo que parece quase certo. Se o seu texto vem de um CMS, um ajuste manda o parser mesmo assim.
Adicionado · 1
A setting that ships the ICU parser anyway, for text that only reaches your app after the build
Alterado · 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
Uma linha para trocar, e a sua escolha finalmente fica
O Verbaly trazia um trocador de idioma completo para uma forma de fazer os endereços e uma peça solta para a outra, então todo projeto escrevia a segunda à mão, o nosso incluído. Reescrever o nosso próprio site sobre o helper da biblioteca encontrou uma falha que estava lá desde que o trocador entrou no runtime: quem escolhia um idioma voltava ao do seu navegador na carga seguinte. A outra metade é que o Verbaly tinha começado a supor que você queria o idioma nos seus endereços; agora ele lê a sua montagem em vez de adivinhar.
Destaques
Trocar de idioma é uma linha, e é a mesma linha funcionem como funcionarem os seus endereços. Vai para o outro endereço quando o idioma mora lá, e muda o texto onde está quando não.
A sua escolha de idioma sobrevive à carga seguinte. Escolher inglês numa página em espanhol podia devolver você ao espanhol, porque a troca guardava a sua escolha num lugar e a página que recebe você lia outro.
O Verbaly deixa de supor que você quer o idioma nos seus endereços. Ele lê a sua montagem: se você constrói uma versão do seu site por idioma tem endereços por idioma, senão um só serve para todos. Você só escreve isso para discordar.
verbaly doctor diz se leu a sua escolha ou deduziu, para que um ajuste que ninguém escreveu não pareça uma decisão que alguém tomou.
A verificação de tamanho agora mede o que um aplicativo real embarca de verdade, e não só a importação mais pequena possível e a maior impossível.
Adicionado · 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
Alterado · 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
Corrigido · 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
Diga onde o idioma mora, e traduza também o cabeçalho
O Verbaly tem há muito tempo duas formas de carregar o idioma e nunca nomeou nenhuma delas, então qual você recebia era decidido por você lembrar de passar um campo opcional. Nomeá-las revelou o que fazia a nomeação importar: uma página podia estar traduzida em tudo o que um visitante olha e ainda assim dizer a um buscador que está em inglês, porque o título e a descrição moram no cabeçalho, onde ninguém os lê. A nossa própria documentação publicava 27 de 27 páginas assim.
Destaques
Agora você pode dizer onde o idioma mora nos seus endereços, uma vez, na configuração: /docs e /es/docs, um prefixo em todos os idiomas, ou um único endereço para todos. Antes a resposta dependia de qual helper você chamava e do que passava a ele.
O seletor de idioma é uma linha e não dá para escrever errado. O Verbaly te dá um helper que já conhece os seus idiomas, a sua fonte e o seu modo, e a mesma linha continua funcionando se você mudar de ideia sobre o modo.
O título e a descrição das suas páginas também são traduzidos. Eles moram no cabeçalho, ninguém os lê na página e são o que um resultado de busca mostra, então uma página podia parecer inteiramente traduzida e aparecer listada em inglês.
verbaly render conta as páginas cujo título ainda nunca muda e te diz uma vez, com a correção. Nunca derruba um build: o nome de um produto pode não se traduzir.
verbaly doctor diz em que modo estão os seus endereços, e avisa quando a sua configuração pede duas coisas que não podem ser verdade ao mesmo tempo.
Breaking: pedir um caminho sem nomear o seu idioma fonte não compila mais. Antes colocava prefixo em todos os idiomas incluindo o seu, em silêncio, o que quase nunca era o que alguém queria.
Adicionado · 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
Alterado · 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
Corrigido · 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
Traduzir sobrevive a uma conexão ruim, e os agentes recebem o ciclo inteiro
O Verbaly deixa um agente de código executá-lo há um tempo, mas dos seus doze comandos só quatro chegaram a ficar disponíveis, e os dois que faltavam são os dois primeiros de que um agente precisa: descobrir o que falha em um projeto e envolver o texto que já está escrito nele. Olhando para isso apareceu algo pior ao lado. verbaly translate é o único comando que custa dinheiro e minutos, e uma única resposta ruim jogava fora a execução inteira: lotes já pagos e traduzidos nunca chegavam ao disco.
Destaques
verbaly translate não perde mais o trabalho que você já pagou. Uma requisição que não volta é tentada de novo, e se ainda assim falhar a execução continua e salva todo o resto. Rodar de novo pede só o que falta, em vez de pagar tudo outra vez.
Traduzir é umas quatro vezes mais rápido. Agora as requisições saem juntas em vez de uma atrás da outra, e uma execução longa vai contando o que chegou enquanto trabalha, em vez de ficar calada por minutos.
Você pode dizer o que nunca se traduz. Coloque os nomes do seu produto e qualquer forma que já tenha decidido em translate.glossary, e como você trata o leitor em translate.instructions, em vez de corrigir a mesma palavra à mão depois de cada execução.
Seu agente de código recebe as duas ferramentas que faltavam: uma para descobrir por que um projeto não funciona, e outra para encontrar o texto escrito direto nos seus componentes e envolvê-lo. Levar um aplicativo existente para o Verbaly já não precisa de um terminal.
Agora os agentes leem números, não frases. Cada ferramenta responde com dados simples além do texto, então um agente para de adivinhar uma redação que pode mudar entre versões.
Aceitar uma tradução automática continua sendo algo que só uma pessoa pode fazer, e isso não mudou.
Adicionado · 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
Corrigido · 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
As traduções escritas por grupos já estão seguras em todo lugar
Você pode guardar suas traduções como grupos aninhados em vez de uma lista plana só, e o Verbaly já lê essa forma há um tempo. Só que apenas metade dele lia: os comandos que escrevem seus catálogos tomavam os nomes de grupo como se fossem mensagens. Então o extract adicionava uma segunda cópia de cada mensagem, o --prune apagava grupos inteiros com todas as traduções dentro, os exports chegavam quebrados ao seu tradutor e o translate dizia que não havia nada a fazer sobre um app pela metade. Para um catálogo plano nada muda.
Destaques
As traduções guardadas por grupos estão seguras de ponta a ponta. Agora todos os comandos leem e escrevem elas do mesmo jeito, e seu arquivo mantém a forma que você deu em vez de ficar achatado pelas suas costas.
O verbaly extract --prune não apaga mais traduções. Num catálogo escrito por grupos ele lia o nome de cada grupo como uma mensagem, não reconhecia e levava o grupo inteiro com todas as traduções dentro.
Seus arquivos para o tradutor param de chegar quebrados. O export escrevia [object Object] onde deveria ir o texto, e o verbaly translate dizia que não havia nada a fazer enquanto o verbaly status dizia que metade do app estava sem tradução.
Um idioma que você adicionar depois combina com o resto. Um catálogo novo assume a forma dos que você já tem, então um projeto nunca acaba metade por grupos e metade plano.
A ferramenta conta em inglês de verdade. Antes dizia 1 messages, 1 locales e 1 pages em nove lugares.
Um aviso repetido se diz uma vez só. Uma colisão de chaves era anunciada três vezes num único verbaly extract, uma delas depois de o resumo já ter sido impresso.
Alterado · 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
Corrigido · 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
A versão anterior deu nome às duas formas que um site tem de levar o seu idioma. Escrever a página que as explica revelou por que uma delas nunca tinha funcionado bem: se a sua app mantém um só endereço por página e carrega os idiomas sob demanda, o Verbaly sabia que idioma o visitante queria e simplesmente nunca o pedia. Uma linha, e o exemplo das nossas próprias docs vinha ensinando isso desde sempre.
Destaques
O idioma guardado já sobrevive a um F5 num site de um só endereço. Quem voltava recebia o idioma de origem outra vez, sem nada no console que o explicasse.
Não muda nada se o seu idioma vai no endereço, que é do que trataram as duas versões anteriores. Isto só estava quebrado onde o idioma vem do armazenamento ou do navegador.
Um aviso que dava um conselho impossível passa a dar o certo. Quando a sua página diz um idioma e o Verbaly está em outro, te dizia para ler o idioma do endereço. Num site de um só endereço não há nada para ler.
O React, o Vue e o Svelte foram testados um a um contra um idioma que chega quando a página já está na tela. Antes era um caminho raro e agora é o normal.
Corrigido · 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
O Verbaly publica o seu site em cada idioma, cada um no seu próprio endereço. A versão anterior deixou essas páginas certas, e esta é sobre como as pessoas chegam até elas, e sobre poder perguntar a partir do seu próprio código a que idioma pertence uma página. As duas coisas tinham de ser escritas à mão por cada projeto, este site duas vezes num dia. Também corrige uma forma de o nome de uma página ser confundido com um idioma.
Destaques
Perguntar em que idioma está uma página já não precisa de um ajudante seu. O Verbaly responde com o idioma que o endereço diz, ou com nada quando o endereço não diz nenhum. Essa é uma pergunta diferente de qual o visitante prefere, e misturar as duas é o que deixava uma preferência guardada pintar o idioma errado por cima de uma página.
O Verbaly já pode mandar o visitante para o seu idioma. Você ativa isso e quem chega à sua página inicial vai para o seu site no seu idioma antes de se desenhar seja o que for. Só a página inicial, por isso um motor de busca continua chegando direto a qualquer página do seu site.
Um site servido a partir de uma subpasta funciona. Você diz ao Verbaly qual é a pasta e os links dentro de cada idioma apontam para onde devem, em vez de apontarem para o nada em silêncio.
Uma página chamada /es-la-guia é uma página, não espanhol. O Verbaly lia o início de um endereço com demasiada vontade, por isso uma página cujo nome começava como um código de idioma podia ser traduzida para esse idioma. Agora só conta um código de idioma a sério.
O que esta versão não muda: uma app com um só endereço por página funciona exatamente como antes. Tudo isto é para sites onde cada idioma tem o seu próprio endereço.
Adicionado · 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
Corrigido · 1
A page whose name begins like a language code is no longer read as that language
O Verbaly publica o seu site estático em cada idioma, em /es/ e /pt/. Esta versão é sobre o que acontecia a quem chegava a uma dessas páginas: chegava em espanhol e piscava para inglês antes de voltar, nada dizia ao runtime que já estava numa página em espanhol, e todos os links apontavam para fora. A página estava certa e tudo o que havia entre ela e o visitante, não.
Destaques
Uma página pré-traduzida deixa de piscar para inglês. O Verbaly servia a página em espanhol e depois pintava o texto em inglês por cima até o catálogo espanhol acabar de carregar, precisamente nas páginas que esta funcionalidade existe para manter quietas.
Chegar em /es/ já basta. O Verbaly lê o prefixo que ele próprio escreveu antes de olhar para o armazenamento ou para o navegador, porque a página que você está vendo já está nesse idioma.
Cada idioma deixa de ser uma ilha. Os seus links apontavam para a raiz do site, por isso chegar em espanhol e clicar uma vez te devolvia ao inglês. Os links para páginas que esse idioma também tem ficam agora lá dentro.
O seu seletor de idioma leva ao seu site nesse idioma. É esse o endereço que se pode compartilhar e o que os motores de busca indexam, e a página chega já traduzida, por isso não pisca nada. Numa app com um só endereço por página, mudar de idioma continua mudando apenas o texto, tal como antes.
O que esta versão não faz: não encaminha ninguém. Quem chega à sua raiz está recebendo o idioma de origem, e mandá-lo para o seu idioma é uma regra na configuração da sua hospedagem.
Adicionado · 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
Alterado · 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
Corrigido · 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
O gate do build se recusa a compilar quando uma tradução não consegue renderizar o que a sua fonte renderiza, mas só vê o que está no seu projeto na hora de compilar. Esta versão vai atrás de tudo o que chega depois: um catálogo vindo de um gerenciador de conteúdo, um arquivo de código que o Verbaly não conseguiu ler e uma quebra de linha dentro de uma mensagem com formatação sobre a qual a página pré-renderizada e o navegador discordavam. Quatro erros reais, cada um uma forma de publicar algo errado com todos os comandos verdes.
Destaques
Uma quebra de linha dentro de uma mensagem com formatação já não duplica numa página pré-renderizada. O Verbaly escrevia-a de uma forma que os navegadores leem como duas quebras, e a página substituía-as por uma ao carregar. Um salto visível, justamente nas páginas que essa funcionalidade existe para manter quietas.
Uma tradução que chega como null já não derruba a sua aplicação ao iniciar. Um campo que ninguém preencheu num gerenciador de conteúdo parava tudo antes do primeiro render. Agora essa chave é ignorada, a aplicação roda e o console diz qual era.
Os comandos sobrevivem a um arquivo que não conseguem ler. Um arquivo com um erro de sintaxe terminava a execução inteira com uma posição e nenhum nome de arquivo. Agora o arquivo é nomeado, os seus textos são ignorados e todos os outros continuam sendo lidos.
O texto dentro de JSX escrito num arquivo .js é encontrado como em qualquer outro lugar. Uma aplicação React com componentes em .js não conseguia sequer rodar o comando extract, porque a primeira etiqueta o terminava.
Um aviso já não se repete porque um número mudou. Três deles imprimiam o valor que os causava, por isso um contador a subir podia encher a memória de cópias da mesma mensagem.
Adicionado · 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
Alterado · 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
Corrigido · 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
O pacote do compilador deixava você importar 132 coisas diferentes, e nenhuma estava escrita em lugar nenhum. Elas foram se acumulando conforme os pacotes de framework precisavam, e na versão 1.0 cada uma teria virado uma promessa que ninguém nunca revisou. Esta versão lê a lista inteira contra uma regra escrita, publica as 60 que passam, documenta elas e adiciona um teste que falha se a lista voltar a crescer sem querer.
Destaques
Se você usa a linha de comando ou qualquer um dos pacotes de framework, esta versão não muda nada para você. Nem configuração, nem imports, nada para editar. Tudo aqui acontece dentro de um pacote que só as integrações feitas à mão alcançam.
O pacote do compilador agora documenta o que você pode importar, em dois grupos: os tipos que o seu arquivo de configuração e o seu próprio provedor de tradução precisam, e as peças para construir uma integração que nós não publicamos. Todo o resto é interno e agora diz isso.
A lista foi de 132 nomes para 60. Cada um ficou porque uma integração real usa, porque é uma forma documentada de estender o Verbaly, ou porque outro precisa dele. Os 72 que não atendiam a nenhuma das três não estão mais lá.
Um plugin de build já não recebe a árvore interna com que o Verbaly lê o seu código. Antes chegava inteira só para ler dois campos dela, e agora ele recebe as mensagens que encontrou. Uma coisa menos que pode quebrar quando esse leitor mudar.
Os dois pacotes falham no próprio teste se a lista crescer, então tornar algo público é agora uma decisão que alguém revisa, em vez de algo que acontece no caminho de consertar outra coisa.
Adicionado · 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
Alterado · 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
Corrigido · 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
O Verbaly já se recusava a compilar quando uma tradução não conseguia renderizar o que a sua origem renderiza. Esta versão fecha a mesma história pelo outro lado: cada lugar onde o Verbaly fazia o seguro sem dizer nada agora te avisa, no momento em que você pode agir. Um plural que renderiza uma linha vazia, um preço sem moeda, um bloco escrito onde não pode funcionar e um nome importado de onde não existe: quatro formas de publicar o texto errado com tudo verde.
Destaques
Um plural sem caso geral agora avisa no navegador, não só no build. A verificação do build já o recusava, mas um catálogo que chega por carregamento diferido ou de um gerenciador de conteúdo nunca passa pelo build, por isso a linha vazia ainda podia chegar a uma página real. Agora nomeia a mensagem e te diz o que acrescentar.
Um marcador sem o seu argumento deixa de renderizar um número seco. Um preço sem código de moeda, uma medida sem unidade, uma data sem unidade de tempo: cada um imprimia o valor simples e calava-se. Agora cada um diz o que precisa e mostra a forma da correção.
Escrever um plural dentro de um template t já não é publicado com as chaves à vista. Nesse template os valores vêm do seu código, por isso um plural ou um formato escrito ali torna-se texto que os seus usuários veem. O verbaly extract e o verbaly doctor apontam agora o arquivo e o texto exato.
Importar t do pacote recebe finalmente uma resposta que menciona o Verbaly. O t vem da sua instância ou do módulo gerado, nunca do pacote, e até agora só o bundler se queixava, com uma mensagem que não dava pista nenhuma de onde o t devia sair.
Cada erro da linha de comandos imprime o seu nome uma vez. Antes toda a falha lia-se [verbaly] [verbaly].
Adicionado · 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
Alterado · 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
Corrigido · 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
Um comando dizia que o projeto estava saudável enquanto outro bloqueava o build pelos mesmos arquivos. O doctor rejeitava catálogos escritos como grupos aninhados, mesmo o runtime sempre os tendo lido, e dizia a um projeto Astro ou Nuxt para instalar o pacote que o comando de setup tinha acabado de desaconselhar. O gate do build lia qualquer palavra entre sinais de menor e maior como markup, e derrubava traduções corretas por causa disso. Tudo isso agora conta a mesma história: o que um comando te diz é o que o seu projeto é.
Destaques
verbaly doctor para de contradizer o verbaly check. Uma tradução que está lá mas está quebrada agora também é um erro no doctor, então o comando que você roda quando algo parece errado não pode mais responder "o setup parece saudável" num projeto cujo build falha.
Catálogos escritos como grupos aninhados funcionam em todo lugar. O doctor os rejeitava como inválidos, e o gate só comparava os nomes dos grupos, então um grupo com uma linha sem tradução dentro contava como totalmente traduzido. Agora cada linha é checada sozinha, do jeito que o runtime já a lia.
O doctor aponta o pacote que o seu projeto realmente precisa: Astro, Nuxt, Next.js, SvelteKit, Vite ou o plugin do seu bundler. É a mesma resposta que o verbaly init dá, porque os dois agora leem uma tabela só.
O build para de falhar por texto que só parece markup. "Press <Enter> to continue" traduzido como "Pulsa <Intro> para continuar" era reportado como duas tags quebradas. Uma tag conta como estrutura só quando a mensagem a fecha, então a sua prosa continua prosa e uma tag de ênfase ou um link de verdade seguem protegidos.
Cada falha nomeia o passo que a repara, em vez de um único "rode extract" que só consertava as traduções que faltavam. E desligar a checagem de faltantes agora significa o que diz: você pode buildar com texto sem tradução, e o Verbaly continua se recusando a publicar uma tradução que renderiza errado.
Um valor que falta diz de qual mensagem veio. O aviso imprimia só o nome do placeholder, uma vez por nome, então a segunda mensagem com a mesma lacuna ficava calada.
Adicionado · 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
Alterado · 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
Corrigido · 1
A stray invisible character made one compiler source file unreadable to git, which had been hiding its diffs since it was added
O gate do build deixa de confiar numa tradução preenchida
Até agora o check fazia uma única pergunta: existe um valor para cada key? Uma tradução podia deixar de fora o seu placeholder de nome, perder uma tag de ênfase ou achatar um bloco de plural, e o build seguia verde enquanto produção mostrava em silêncio o texto errado, ou nada. Agora o gate lê cada tradução contra o original e falha diante de tudo que não consegue mostrá-la, com o motivo em palavras simples e a linha do fonte para clicar. O runtime deixa de silenciar o mesmo tipo de bug, e o pacote de React fica verificado contra o Preact.
Destaques
O build agora pega traduções que existem mas estão quebradas. Um placeholder que falta, uma tag perdida, um bloco de plural transformado em texto simples, ou um plural sem caso curinga: cada um para o build com uma frase dizendo o que aconteceu e por que importa. Antes disto, um catálogo editado à mão não tinha verificação nenhuma.
O bug do texto vazio acabou. Um bloco de plural que perdia o caso curinga não mostrava nada para cada quantidade que não listava. Em polonês, uma mensagem com só "one" e "few" mostrava uma string vazia para 5 itens. Isso agora falha o build em vez de ir para produção.
O Verbaly diz a quem traduz quais formas plurais o idioma realmente precisa. Um catálogo polonês ou russo com só duas formas recebe um aviso nomeando as que faltam. É um conselho, não uma falha: o texto ainda é mostrado. As formas que nenhum contador real alcança nunca são pedidas, então espanhol, francês, português e italiano ficam em silêncio.
verbaly status mostra uma contagem de quebrados por idioma, então você vê o estado de um catálogo sem rodar o gate.
Um valor que falta agora avisa no console. Mostrar um placeholder cru porque ninguém passou o valor era o único caso de dado ruim que o Verbaly não reportava. Todos os outros já reportavam.
O Preact funciona, e agora está provado. O pacote de React roda a suite completa uma segunda vez com o React resolvido para preact/compat: hooks, troca de idioma, texto rico e render no servidor passam todos. Sem pacote separado e sem mudanças no seu código.
O VS Code pode mostrar as suas traduções ao passar o mouse. O README do repositório traz a configuração do i18n-ally que transforma as keys com hash em texto legível enquanto você programa.
Adicionado · 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
Alterado · 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
Seu agente de código já pode rodar todo o ciclo de tradução
Um novo servidor MCP dá ao Claude Code, ao Cursor e a qualquer cliente MCP quatro ferramentas: ver a cobertura, listar o que falta, extrair texto novo e traduzir as lacunas por máquina. Tudo o que o agente traduz continua esperando sua revisão. Uma Agent Skill pública e um llms.txt na documentação completam o canal, projetos Nuxt mantêm a raiz limpa e trechos de código que só são exibidos não podem mais virar chaves fantasma.
Destaques
O ciclo de tradução como ferramentas de agente. Um comando (claude mcp add verbaly -- npx -y @verbaly/mcp) e seu agente de código pode conferir a cobertura, listar traduções faltantes, extrair texto novo e preencher as lacunas com tradução de máquina. O que ele traduzir é salvo como rascunho, então nada é publicado sem uma pessoa dizer que sim.
Uma Agent Skill pública ensina Verbaly ao seu agente. Instale skills/verbaly do repositório no seu projeto e o agente conhece o ciclo de escrever, extrair, verificar e traduzir, e as regras que o mantêm seguro.
A documentação agora fala LLM. Este site publica um índice llms.txt, assim os agentes que leem documentação se orientam no Verbaly sem raspar HTML.
Projetos Nuxt mantêm a raiz limpa. Os tipos gerados agora vivem dentro de .nuxt/ e se registram sozinhos, exatamente como a integração do Astro já fazia. Nenhum arquivo na raiz do projeto e nenhuma mudança no tsconfig.
Código que só é exibido não pode mais virar uma chave de tradução. Páginas que mostram exemplos de t como texto visível em arquivos Vue, Astro ou Svelte corriam o risco de esses trechos serem extraídos como chaves reais. Agora só conta o código dentro de expressões de verdade.
Adicionado · 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
Alterado · 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 e um runtime mais sólido
O kit para tradutores está completo: exporte e importe arquivos gettext PO, e o XLIFF agora protege seus placeholders e tags para que um tradutor não consiga quebrá-los por acidente. O nome custom do sitemap no render enfim funciona, um crash raro com datas inválidas sumiu, e o runtime não pode mais crescer em silêncio acima do seu orçamento de tamanho.
Destaques
Exporte e importe arquivos gettext PO. verbaly export --format po escreve um arquivo .po por idioma, pronto para Poedit, Weblate ou qualquer editor PO. verbaly import os lê de volta com a mesma rede de segurança de todos os formatos: uma tradução que quebra um placeholder é rejeitada, não publicada. Entradas que uma ferramenta marca como fuzzy contam como não traduzidas.
Tradutores não podem mais quebrar seus placeholders no XLIFF. Placeholders e tags viajam como códigos protegidos com nomes com sentido, então as ferramentas de tradução os mostram como fichas intocáveis em vez de texto editável. As palavras de plural e select seguem editáveis de propósito: essas sim se traduzem.
Nomes custom de sitemap agora funcionam. Configurar um nome próprio para o sitemap no render era ignorado: sempre escrevia sitemap-i18n.xml. O nome que você configura é o nome que você recebe.
Um crash raro sumiu. Passar uma data inválida a uma mensagem podia lançar um erro em vez de degradar com graça. Ele foi encontrado por uma suíte nova de testes aleatórios que castiga o parser com lixo em cada execução, então essa classe de bug fica corrigida.
O runtime não pode mais crescer em silêncio. Cada push mede o bundle do core e falha se ele passar do orçamento de tamanho. A promessa de ~3 KB é garantida por uma máquina, não por um costume.
Adicionado · 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
Corrigido · 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
Traduções por máquina que você revisa antes de confiar
As traduções por máquina agora chegam como rascunhos que você revisa, não como trabalho pronto em que confia às cegas. Um comando novo as aprova, o gate do CI pode esperar um humano, e o modelo traduz com contexto do seu código.
Destaques
A saída da máquina é um rascunho até você dizer o contrário. verbaly translate continua preenchendo as lacunas, mas tudo o que escreve fica marcado como rascunho sem revisar. Seus catálogos ficam tão limpos quanto antes: o estado de revisão vive num arquivo .verbaly-drafts.json à parte, ao lado deles.
Aprove as traduções depois de lê-las. verbaly review lista tudo o que espera um humano; verbaly review --approve aceita, tudo ou um idioma por vez. Importar o arquivo de um tradutor também conta como revisão, então a marca de rascunho se limpa sozinha.
Bloqueie merges com texto de máquina sem revisar. verbaly check --drafts faz o CI falhar enquanto restar alguma tradução por máquina sem revisar. O verbaly check normal não muda, então nada quebra até você ativar.
Traduções melhores, porque o modelo recebe contexto. verbaly translate agora diz ao provider em quais arquivos fonte cada texto aparece, então o tom e o tamanho combinam com onde o texto é usado.
Veja o que falta revisar num relance. verbaly status (e --json) agora reportam quantos rascunhos sem revisar há por idioma.
Adicionado · 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
Alterado · 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
Suporte a Astro, um codemod wrap e anotações no CI
O Astro entra para a família: uma linha conecta tudo e o rendering por idioma roda sozinho. Um novo comando wrap envolve seu texto JSX hardcoded por você, e as falhas de CI viram anotações direto nos seus pull requests.
Destaques
Suporte a Astro, uma linha. Adicione verbaly() às integrations do astro.config e tudo fica conectado: extração ao vivo enquanto você programa, chaves type-safe e o gate do build. As chaves tipadas vivem dentro da pasta .astro própria do Astro, então nenhum arquivo extra cai no seu projeto. No fluxo de espelho, verbaly render roda sozinho depois de cada build.
Escreva seu texto direto em arquivos .astro. O mesmo t`…` que você já usa em .js, .tsx, .svelte e .vue agora funciona no frontmatter e no markup dos componentes Astro.
Migrando um app existente? Deixe o verbaly wrap fazer a parte chata. Ele escaneia seu JSX, encontra o texto visível hardcoded e o envolve em t`…` por você. Primeiro reporta; nada é tocado até você passar --write.
As falhas de CI agora apontam para o seu código. verbaly check --reporter github transforma cada tradução faltando em uma anotação no arquivo e na linha exatos, direto no pull request.
verbaly status --json entrega os números de cobertura em formato machine-readable, prontos para badges e dashboards.
Adicionado · 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
Alterado · 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
Corrigido · 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, nomes de idioma reais e contexto para tradutores
Adicionar árabe ou hebraico agora simplesmente funciona: a direção da página segue o idioma em todo lugar. Seletores de idioma recebem nomes reais da plataforma, e os arquivos de tradução dizem onde cada texto vive.
Destaques
Idiomas da direita para a esquerda simplesmente funcionam. Adicione árabe, hebraico ou persa e a direção da página segue o idioma por conta própria: quando o usuário troca, quando o servidor renderiza e nas páginas estáticas pré-renderizadas. Sem atributo dir para administrar, nunca.
Seletores de idioma sem nomes fixos. localeName('es') devolve 'español' e localeName('de', 'en') devolve 'German'. Os nomes vêm da plataforma, então qualquer locale funciona sem manter uma tabela.
Precisa da direção você mesmo? localeDirection('ar') devolve rtl. É o mesmo helper que o resto do toolkit usa, exportado para os seus próprios layouts.
Tradutores agora veem onde cada texto vive. O verbaly export marca cada mensagem com os arquivos fonte de onde veio: o XLIFF recebe notas de localização padrão e o CSV uma coluna de localização, então o contexto deixa de ser adivinhação.
Adicionado · 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%
Alterado · 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
Chaves literais e páginas pré-renderizadas mais seguras
Mensagens rich finalmente podem mostrar uma chave literal, e páginas pré-renderizadas com verbaly render aplicam as mesmas regras de segurança do navegador.
Destaques
Mensagens agora podem mostrar chaves literais. Escreva { e } em uma mensagem rich e elas renderizam como { e }. Formas hex como { também funcionam, no navegador, em cada <Trans> e em páginas pré-renderizadas.
Páginas pré-renderizadas agora são tão seguras quanto o navegador. Atributos traduzidos passam pelos mesmos guards, então links inseguros e atributos perigosos de um catálogo nunca chegam ao HTML estático.
Adicionado · 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
Alterado · 1
Internal: render link handling reuses normalizeLink, the same helper every adapter uses
Corrigido · 1
verbaly render now applies the runtime attribute guards: unsafe URLs are blocked and style/srcdoc are never written from translations
Um <Trans> para tudo, extração ao vivo e uma visão de cobertura
Os componentes <Trans> de React, Vue e Svelte agora compartilham as mesmas props e as mesmas regras de render, a CLI aprende dois comandos do dia a dia e os últimos breaking changes planejados chegam antes da 1.0.
Destaques
<Trans> agora é o mesmo componente em React, Vue e Svelte: mesmas props, mesmas regras de render. Seu componente próprio vence, depois os links nomeados, depois a whitelist segura de tags; o desconhecido vira texto puro.
Breaking: os <Trans> de React e Vue agora renderizam tags da whitelist como em e code como elementos reais, igual ao Svelte e ao interpretador de DOM. Passe uma lista richTags vazia para manter o comportamento antigo de achatar para texto.
Breaking: @verbaly/svelte agora exige Svelte 5. Em troca o <Trans> ganha a prop components: mapeie um tag da mensagem para o seu próprio componente. No Svelte 4, fique na 0.22.0.
verbaly status mostra quanto falta traduzir, uma linha por idioma, sem falhar nada. verbaly check continua sendo o gate do build.
verbaly extract --watch mantém catálogos e tipos em dia enquanto você escreve código, pensado para setups de webpack, Rspack e Rollup onde o plugin do Vite não está disponível.
Dar feedback ficou mais fácil: o README leva os reportes de bugs e de atrito ao lugar certo, e os formulários de issues cobrem os dez pacotes.
Adicionado · 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
Alterado · 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
O comando export aprende dois formatos mobile: pastas de recursos do Android e arquivos de strings do iOS. Um app web e seu companheiro mobile agora podem compartilhar um único conjunto de traduções.
Destaques
Exporte suas traduções para apps mobile: verbaly export --format android-xml escreve pastas que você pode soltar em res/, e --format ios-strings escreve pastas .lproj para o Xcode.
Padrões sensatos por plataforma: seu idioma fonte vira o padrão da plataforma, e as keys sem tradução ficam de fora para o app cair nele em vez de mostrar texto vazio.
Catálogos mais seguros: um catálogo com JSON quebrado agora para o comando e aponta o arquivo, em vez de ser lido em silêncio como vazio. Um BOM do Windows no início do arquivo é simplesmente tolerado.
Adicionado · 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)
Alterado · 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
Uma limpeza a fundo nos dez pacotes, mais opções totalmente tipadas na sua config do Nuxt. Os internos ficaram mais organizados e um pouco menores, sem mudar como você escreve Verbaly.
Destaques
A key verbaly do nuxt.config.ts agora é totalmente tipada: você tem autocomplete e checagem de typos, e o módulo continua sem somar dependências.
Um editor mais calmo no dev. verbaly.d.ts só é reescrito quando o conteúdo realmente muda, então seu servidor TypeScript para de recarregar tipos a cada salvamento.
Um runtime um pouco menor: o core tree-shaken agora pesa 3.28 KB gzip, antes 3.30.
Tipos gerados mais limpos: um valor usado como data e como texto puro já não aparece duas vezes em verbaly.d.ts.
Mensagens da CLI mais claras. Cada erro e dica se lê em palavras simples, e o check agora imprime o texto fonte bem ao lado da key faltante.
Alterado · 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)
Escreva seu texto também em arquivos .svelte e .vue
O texto natural agora funciona dentro de componentes Svelte e Vue: escreva no arquivo, script ou markup, e o compilador extrai com key estável e params tipados.
Destaques
Escreva t`Hello ${name}` diretamente em um template .vue ou {$t`Hello ${name}`} em markup .svelte. O compilador detecta como sempre fez em arquivos .ts: key estável, params tipados, catálogos por idioma.
A forma store do Svelte é entendida: $t`…`, $t('key') e $t.id('key')`…` funcionam em qualquer parte de um arquivo .svelte.
Ao vivo no dev, com gate no build: salve um componente com texto novo e os catálogos mais verbaly.d.ts se atualizam na hora. Traduções faltantes continuam parando o build.
Keys legíveis e keys de runtime também funcionam no markup: t.id('home.title')`…` extrai sob a sua key, e chamadas t('key') contam como keys usadas para o check e o prune.
verbaly extract varre mais por padrão: arquivos .svelte e .vue, mais a pasta app/ ao lado de src/ (onde vivem o Nuxt 4 e o App Router do Next.js). Seu próprio include continua vencendo.
Adicionado · 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
Alterado · 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 entra para a família: o ciclo está completo
A última grande integração de meta-framework. As páginas do App Router do Next.js renderizam já traduzidas, hidratam sem flash e funcionam no Turbopack e no webpack.
Destaques
Novo pacote @verbaly/next. Dois passos: envolva sua config com withVerbaly() no next.config.ts e solte <VerbalyProvider> no layout raiz. Server Components traduzem com await getT(); Client Components seguem usando useT e <Trans> como em qualquer app React.
Funciona no Turbopack (o padrão do Next 16) e no webpack. next dev extrai suas mensagens enquanto você digita, e next build para se faltar uma tradução.
Cada visitante recebe seu próprio idioma, resolvido uma vez por request a partir do cookie ou das preferências do navegador. As páginas chegam já traduzidas, nada pisca, e visitantes concorrentes nunca veem o idioma um do outro.
useSwitchLocale() troca o idioma na hora, lembra a escolha para a próxima visita e atualiza também os Server Components.
Mensagens rich agora podem exibir markup literal, então uma mensagem pode mostrar "<html lang>" como texto visível em vez de um escape quebrado.
Adicionado · 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
Corrigido · 1
HTML entities decode inside rich text (core), so a message can display <html lang> literally and pre-rendered HTML round-trips cleanly
A segunda integração de meta-framework: um módulo Nuxt sem config renderiza cada página no idioma do visitante e hidrata sem flash.
Destaques
Novo pacote @verbaly/nuxt. Uma linha na sua config (modules: ['@verbaly/nuxt']) liga tudo: extração ao vivo, idioma por visitante e hidratação com o mesmo locale e catálogo que o servidor usou. Sem flash, sem mismatch.
Sem lock de framework: o módulo não depende nem de nuxt nem de @nuxt/kit, e é verificado contra um app Nuxt 4 real.
switchLocale() agora é um export do core compartilhado por SvelteKit, Nuxt e setups manuais. Carrega o catálogo primeiro e troca depois, então nada pisca. Os imports existentes continuam funcionando.
Apps client-only também estão cobertos: com ssr: false o módulo ainda escolhe o idioma certo no navegador.
Apoie o Verbaly: o GitHub Sponsors já está ativo em github.com/sponsors/AronSoto.
Adicionado · 2
@verbaly/nuxt, the 9th package: zero-config module plus a runtime plugin (per-request language, payload hydration, reactive <html lang>)
switchLocale / SwitchLocaleOptions (core)
Alterado · 1
@verbaly/sveltekit re-exports switchLocale from core, with identical API and behavior
A release de hardening: uma auditoria completa dos oito pacotes corrigiu cada aresta que encontrou, e o SSR ganha sua peça que faltava.
Destaques
A tradução de atributos agora é XSS-safe de ponta a ponta: data-verbaly-attr sanitiza atributos de URL e bloqueia style e srcdoc por completo, então um catálogo comprometido não consegue injetar scripts.
t() nunca quebra por argumentos de formato ruins: um código de moeda, data ou estilo de hora inválido avisa uma vez e renderiza o valor puro.
createRequestInstance(locale) no virtual:verbaly: o padrão SSR per-request em uma chamada, com o catálogo já carregado e sem flash.
A CLI agora rejeita flags fora de lugar. verbaly translate --locale es antes traduzia todos os idiomas em silêncio; agora dá erro e sugere --locales. Além de --dry-run para extract --prune.
normalizeLink() e resolveRequestLocale() agora vivem uma única vez no core, compartilhados por cada adapter e integração SSR.
Breaking:instance.inspect(key) agora retorna { from, source } em vez de { locale, source }: um só nome para um só conceito em toda a API de observabilidade.
Adicionado · 2
normalizeLink, resolveRequestLocale, LOCALE_STORAGE_KEY (core) and createRequestInstance (virtual:verbaly)
failOnMissing opt-out for the Vite build gate; --dry-run on verbaly extract
A primeira integração de meta-framework: páginas SvelteKit renderizam no idioma do visitante no servidor e hidratam sem flash.
Destaques
Novo pacote @verbaly/sveltekit. SSR em três fios: verbalyHandle() nos seus hooks de servidor, um load de +layout e %verbaly.lang% no app.html. As páginas chegam traduzidas.
O idioma é decidido por request: cookie primeiro, depois o header Accept-Language (es-PE casa com es), depois seu fallback. Requests concorrentes nunca vazam o idioma um do outro.
switchLocale(): um switch client-side que carrega o catálogo primeiro e depois salva a escolha no cookie que o servidor lê.
negotiateLocale() no core: o matcher de Accept-Language é um export público que qualquer servidor Node pode usar.
createInstance() no virtual:verbaly: instâncias frescas por request sobre seus catálogos compilados, mais os exports locales e sourceLocale.
Adicionado · 2
@verbaly/sveltekit, the 8th package: verbalyHandle + switchLocale
negotiateLocale (core) and SSR exports in virtual:verbaly
Alterado · 1
The Release workflow now resumes per package after a partial run
O ciclo write→ship se abre a humanos: exporte arquivos prontos para tradutores, importe de volta validados.
Destaques
verbaly export escreve um arquivo pronto para tradutores por idioma: XLIFF 2.0 para plataformas de tradução, CSV para planilhas. --missing exporta só o que falta traduzir.
verbaly import valida cada entrada: uma tradução que perde um placeholder, uma variante ou um tag é rejeitada e reportada.
As traduções existentes são mantidas a menos que você passe --overwrite, e --dry-run pré-visualiza o import inteiro.
Você não precisa de plataforma de tradução: os catálogos são JSON puro, e Crowdin, Lokalise e Phrase leem nativamente.
Adicionado · 2
verbaly export: translator-ready XLIFF 2.0 / CSV files per locale
verbaly import: a validated round-trip back into your catalogs
Alterado · 2
GitHub Release notes are now short: theme, highlights and a link to the full changelog
Community docs pass: SECURITY and CONTRIBUTING read friendlier