Ir para o conteúdo

Referência

CLI

O comando verbaly vive em @verbaly/compiler. Adicione-o às suas dependências de desenvolvimento para que npx verbaly funcione: os gestores de pacotes só ligam um comando de um pacote que você mesmo instalou, e os plugins dependem do compilador sem o instalar por você.

Comandos

14 comandos, na ordem em que o ciclo os usa. Cada um leva à sua seção.

Scaffolding

verbaly init deixa um projeto montado num comando. Te dá uma config tipada (.ts se você tiver tsconfig, .mjs se não) e os seus catálogos: o de origem, mais um para cada idioma que você passar em --locales. Depois te diz o que falta ligar. Astro, Nuxt, Next.js, SvelteKit e Vite têm a sua própria integração; qualquer outro bundler usa @verbaly/unplugin.

npx verbaly init --locales es,pt
  1. created: verbaly.config.ts, locales/en.json, locales/es.json, locales/pt.json
  2. detected: vite
  3. next steps: 1. pnpm add verbaly @verbaly/vite
  4. 2. add verbaly() to the plugins in vite.config

Reexecutar é seguro: uma config ou catálogo existente é reportado como “kept” e fica intacto.

Checagem de saúde

verbaly doctor é o irmão do init para projetos já rodando: inspeciona todo o setup e reporta cada achado com o comando exato que o corrige. Verde significa saudável; problemas saem com 1.

npx verbaly doctor
  1. Correto config: verbaly.config.ts found
  2. Correto catalogs: 3 locales (en, es, pt) in locales/
  3. Correto plugin: @verbaly/vite installed for vite
  4. Aviso types: src/verbaly.d.ts is stale fix: run npx verbaly typegen
  5. Aviso orphans: 2 catalog keys are no longer referenced (old.title, hero.cta) fix: run npx verbaly extract --prune to drop them
  6. Aviso outdated: 1 translation written for an older source text (es: hero.title) fix: update them, or keep them with npx verbaly review --approve
  7. Erro imports: 1 file imports t from a verbaly package, which never exports it (src/app.ts) fix: t comes from your instance (React: const t = useT()) or from virtual:verbaly
  8. Erro translations: 1 broken translation (es): present but not rendering what the source renders fix: run npx verbaly check to read what each one lost

Um comando para responder a “por que isto não traduz?”. Olha para quatro coisas.

Um relatório limpo quer dizer que o check também passa. O doctor falha em tudo aquilo em que o check falha, mais as falhas de montagem como esse import, e nunca em algo que constrói e renderiza bem.

Envolver texto fixo

verbaly wrap encontra texto fixo no seu JSX e o envolve em t`…` por você. Primeiro informa, e --write aplica. O que for ambíguo é listado para um humano em vez de adivinhado, e um arquivo onde t não está disponível fica intacto e é informado, então o projeto continua sempre a compilar.

npx verbaly wrap           # report what it would wrap
npx verbaly wrap --write   # apply it

Passar de outra biblioteca

verbaly migrate passa os catálogos que você já tem. O seu arquivo mantém a forma, aninhada ou plana, e a única coisa que tem de reescrever é a interpolação: {{name}} passa a {name}, porque uma chave duplicada é como o Verbaly escreve uma chave literal. Primeiro reporta, e --write aplica.

npx verbaly migrate             # report what it would port
npx verbaly migrate --write     # apply it
npx verbaly migrate --plurals --write   # and merge _one/_other

--plurals é a metade opcional: junta _one e _other numa só mensagem com variantes, que é o que dá a seleção de plural automática, e lá dentro o número se escreve já localizado. Também entende a forma antiga key + key_plural. Sem a flag, essas keys continuam funcionando tal como estão.

O que não vai adivinhar fica listado: um formato do i18next dentro das chaves, um valor {{- sem escape}}, um aninhamento com $t(), e uma junção que apagaria uma key que você já usa. Essas mensagens ficam exatamente como estavam.

Extração

verbaly extract varre seu código (.js/.ts/.jsx/.tsx, mais .svelte, .vue e .astro), escreve as mensagens novas no catálogo fonte, adiciona lacunas "" ao resto e regenera os tipos. Aponta qualquer arquivo que não conseguiu analisar em vez de parar nele. Cada texto fonte que seguiu o seu código ganha uma linha com o texto que tinha antes, então uma edição que você fez no código se lê como uma mudança, e uma feita no catálogo mostra o que ela desfez. Depois avisa, com arquivo e linha, o que de outra forma passaria despercebido: uma chave escrita com dois textos, um t com outro nome, uma mensagem que ficou com um bloco plural ou de formato como texto literal, e um valor que um tradutor veria como {_0}. Com --watch, cada aviso é dito uma vez, e de novo só se voltar.

npx verbaly extract             # sync catalogs + types
npx verbaly extract --prune     # and drop keys nothing references
npx verbaly extract --dry-run   # say what it would change, write nothing

Geração de tipos

verbaly typegen escreve os tipos TypeScript das suas mensagens e nada mais, a partir do texto que o seu build publica, onde o seu framework os lê: src/verbaly.d.ts num app Vite ou SvelteKit, .verbaly/types.d.ts no Next.js, e a pasta de tipos própria do Astro e do Nuxt. O extract, os servidores de desenvolvimento e o build escrevem o mesmo arquivo, então você só precisa dele onde nenhum rodou: um clone novo, ou um job de CI prestes a rodar o tsc.

npx verbaly typegen && tsc --noEmit   # a fresh clone, or CI

Cobertura

verbaly status mostra num relance quanto está traduzido por idioma (es: 45/48 translated), quantas traduções automáticas ainda esperam revisão, quantas estão quebradas e quantas foram escritas para um texto fonte anterior. É apenas informativo e nunca falha; --json entrega os mesmos números a badges e ferramentas.

npx verbaly status          # es: 45/48 translated
npx verbaly status --json   # the same numbers, for badges and tooling

Pseudo-localização

verbaly pseudo preenche um catálogo de QA (en-XA por padrão) a partir do texto que o seu build publica no locale fonte: letras acentuadas, marcadores ⟦…⟧ e ~33% de padding. Texto que sai limpo no build pseudo está hardcoded; layouts que cortam se revelam antes de uma tradução real.

npx verbaly pseudo                 # locales/en-XA.json
# "Hello {name}" → "⟦Ĥéĺĺó {name} ~⟧"

Params, blocos de variantes e tags sobrevivem verbatim, garantido pela mesma validação estrutural do translate. Re-executar regenera o catálogo completo.

Tradução de máquina

verbaly translate fecha o ciclo: escrever → extract → translate → check verde. O provider padrão usa Claude (@anthropic-ai/sdk como peer opcional + ANTHROPIC_API_KEY); batches de 20 por request, cada um dizendo ao modelo em quais arquivos fonte o texto vive, então ele traduz com contexto. Qualquer modelo atual do Claude funciona com translate.model ou --model, e um batch que o modelo recusa passa para um modelo de reserva em vez de voltar sem tradução.

npx verbaly translate --dry-run        # list what's missing, write nothing
npx verbaly translate --locales es,pt  # fill only these locales
npx verbaly translate --model claude-opus-4-8  # override the default (claude-sonnet-5-5)

Cada tradução é verificada: os placeholders e as tags precisam sobreviver intactos. Se um não sobrevive, a tradução é rejeitada e a entrada fica em "", então o check continua sinalizando até você corrigir.

Sem lock-in: conecte seu próprio provider no verbaly.config.ts. Em TypeScript, TranslateProvider tipa ele para você, e origins diz em quais arquivos do código cada texto aparece, então você traduz pensando no lugar onde ele é usado:

verbaly.config.ts
import type { TranslateProvider } from '@verbaly/compiler';

const provider: TranslateProvider = async ({ sourceLocale, targetLocale, messages, origins }) => ({
  /* key → translation */
});

export default { translate: { provider } };

Revise o que está pendente

A saída da máquina é um rascunho, não trabalho revisado. O translate registra tudo o que escreve em verbaly.lock, ao lado da sua config (commitado com seus catálogos, nunca editado à mão), e o verbaly review fecha o ciclo: leia os rascunhos e aprove. O mesmo arquivo lembra para qual texto fonte cada tradução foi escrita, desde o momento em que é escrita, então quando você muda um texto, as traduções dele também esperam no review, como desatualizadas: atualize-as, ou aprove se ainda valem. Cada uma aparece com o texto que é publicado ao lado da sua tradução, para você julgá-la ali mesmo, e --approve seguido de chaves aceita só essas.

npx verbaly review               # each one with its source text and its translation
npx verbaly review hero.title --approve   # accept only the keys you name
npx verbaly review --approve     # accept everything after reading
npx verbaly check --drafts       # CI gate: fail while drafts remain
npx verbaly check --outdated     # and while a translation is older than its text

Quer bloquear o merge até que um humano aprove? Adicione --drafts ao check do seu CI: ele continua falhando enquanto restarem traduções automáticas sem revisar, e --outdated faz o mesmo com as traduções escritas para um texto fonte anterior. Um arquivo de tradutor trazido com import conta como revisão por si só.

Tradutores e TMS

Humanos no ciclo? verbaly export escreve arquivos XLIFF 2.0, CSV ou gettext PO por idioma prontos para o tradutor e verbaly import os traz de volta, validados estruturalmente com o mesmo gate do translate. O fluxo completo, opções de TMS incluídas, vive em Trabalhar com tradutores.

verbaly import valida cada entrada, e rejeita e informa as quebradas. Entradas PO marcadas como fuzzy contam como não traduzidas, e as chaves importadas deixam de contar como rascunhos sem revisar, a menos que você passe --draft para um arquivo que ninguém leu ainda. O idioma de cada arquivo é lido como um dos seus, então o pt_BR do gettext preenche o seu pt-BR. Um arquivo de um idioma novo começa o seu catálogo com o código bem escrito, a menos que a sua config liste os seus locales: aí um idioma fora da lista é pulado com um aviso e código de saída 1, porque o seu app nunca o carregaria.

O export também escreve recursos nativos de mobile: --format android-xml para a estrutura res/ do Android e --format ios-strings para o Xcode. As keys sem tradução ficam de fora para o app cair no seu idioma fonte (--missing vale só para os formatos de tradutor). Todos os formatos escrevem em verbaly-export/ a menos que você aponte --out para outro lugar.

O que o gate verifica

check faz quatro perguntas. Cada mensagem está traduzida? Cada chave que o código escreve existe? Cada chave tem um só texto, para que nenhum lugar mostre palavras escritas para outro? E cada tradução consegue renderizar o que a fonte renderiza? Uma tradução preenchida não é automaticamente uma que funciona, então essas também fazem o check falhar, venham de onde vierem: um tradutor, uma máquina ou uma edição à mão. Cada build lista os mesmos problemas e termina, então rode o check no CI.

A traduçãoPor que falha
perdeu um {param}, ou mudou o nome deleo valor nunca chega ao texto
perdeu um <em>, ou ganhou uma ênfase ou a marca do link desaparece
transformou um bloco de plural em texto simplesuma única redação para qualquer quantidade
tem um bloco de plural sem o caso othercada quantidade que não lista aparece vazia

Alguns achados são avisos: eles aparecem e o código de saída continua em 0, porque o texto ainda é mostrado.

Um build roda o mesmo gate, e quando encontra avisos imprime uma única linha dizendo quantos são, e passa.

Falhe o que falhar, o relatório termina dizendo como corrigir: criar e preencher uma mensagem que ainda não tem tradução, corrigir a chave de uma que não está em nenhum catálogo, dar a cada texto sua própria chave quando uma chave tem dois, ou reparar a própria mensagem quando ela está quebrada.

Exemplo de CI

.github/workflows/ci.yml
- run: pnpm install
- run: npx verbaly check --reporter github   # each finding becomes a PR annotation
- run: pnpm build

Com --reporter github, cada achado aparece como anotação no pull request, no arquivo e na linha onde o texto vive. Os erros chegam como erros e os avisos como avisos, por isso um aviso nunca põe o job a vermelho. Sem ele você tem a lista de sempre, com o mesmo código de saída.

Renderização estática (SSG)

verbaly render é o que mata o piscar de texto por traduzir num site estático. Percorre o seu HTML construído e preenche cada elemento data-verbaly, uma vez por idioma, usando o runtime a sério: plurais, formatação do Intl, data-verbaly-args, atributos e texto rico da whitelist. Dentro de um idioma, os links para páginas que esse idioma também tem mantêm o seu prefixo, por isso quem chega fica. Levá-lo até lá é o --redirect, aqui abaixo.

npx vite build              # or astro build, eleventy, …
npx verbaly render          # dist/index.html filled in the source locale
                            # dist/es/index.html, dist/pt/… for the rest
npx verbaly render --site out --locales es  # custom dir / locale filter

Flags

FlagPadrãoDescrição
--rootcwdRaiz do projeto
--dirlocalesDiretório de catálogos
--sourceenIdioma fonte
--localesdos arquivosSó estes idiomas, sempre com o fonte incluído (no init: os que cria)
--pruneoffRemove chaves sem referências (só no extract)
--watchoffRe-extrai quando os arquivos fonte mudam: extração viva para setups com webpack, Rspack e Rollup (só extract)
--localeen-XAId do pseudo-locale (só pseudo)
--sitedistDiretório do site compilado (só render)
--baseraiz do siteSubcaminho onde o site é servido (só render)
--redirectoffManda para o seu idioma quem chega à página inicial (só render)

As flags são validadas por comando: uma flag que pertence a outro comando termina com um erro acionável em vez de ser ignorada em silêncio: translate --locale es avisa que você queria --locales.

Arquivo de config

As flags vencem verbaly.config.{js,mjs,ts,mts,json} na raiz do projeto, e o plugin recebe as mesmas opções. Todas elas, com o seu valor padrão, vivem em Configuração.

Agentes de código

Seu agente de código pode rodar esse mesmo ciclo sem tocar no terminal, através do servidor @verbaly/mcp. Esse canal tem página própria. Agentes de código cobre o servidor, suas ferramentas e recursos, a Agent Skill instalável e o índice llms.txt que este site serve.

↑↓para navegarEnterpara abrir
Copiado para a área de transferência