Guias
Quando algo falha
Comece por npx verbaly doctor. Ele inspeciona o setup inteiro e imprime a correção exata ao lado de cada achado, então quase toda esta página é o que ele lhe teria dito.
O comando verbaly não existe
O comando vive em @verbaly/compiler. Os plugins dependem dele, mas um gestor de pacotes só liga o comando de um pacote que você mesmo instalou, então não basta um plugin trazê-lo. Adicione-o às suas dependências de desenvolvimento:
Apareceu um idioma que eu nunca pedi
Se você não listar locales, cada arquivo JSON da sua pasta de catálogos conta como um idioma, tirando o do pseudo-idioma. Por isso um que ficou de uma execução anterior também é, e o build começa a pedir as traduções dele. Liste os seus idiomas e a lista fica completa:
Um aviso diz que um idioma não é um código válido
pt-BR é como se escreve um código de idioma, com um hífen entre as suas partes. pt_BR, do jeito que o gettext e muitos backends escrevem, não é um código que o navegador consiga ler, então o Verbaly o lê como pt-BR para que números, datas e plurais continuem formatando, e avisa uma vez que fez isso. Um código sem correção segura formata no idioma padrão do navegador, com o mesmo aviso. O doctor nomeia cada um da sua config com o novo nome: mude o nome do arquivo do catálogo e a sua config juntos.
o wrap reportou arquivos que não escreveu
Um arquivo onde t não está disponível é listado e fica intacto, porque envolver texto ali deixaria o seu projeto sem compilar. O relatório diz quantos textos esperam em cada um e se é um componente de cliente, para você saber que linha adicionar. Adicione-a e execute de novo.
O build diz que uma tradução está quebrada
Não falta, está quebrada: a tradução está lá e não consegue renderizar o que a fonte renderiza. Perdeu um {value}, tirou um caso do plural ou mudou uma tag. Cada build as lista primeiro, porque renderizam errado, e o npx verbaly check dá o motivo exato de cada mensagem e falha com elas no CI.
O build compilou e depois listou traduções
É ali que a verificação roda. No Next.js, o next build compila o seu app primeiro e depois lista as chaves que faltam, as quebradas e as desconhecidas, então os comandos que só carregam o seu config, como next typegen, nunca a rodam. Preencha o que ele lista, ou rode npx verbaly check antes do build para ver a mesma lista antes. Com failOnMissing: true, o build para ali em vez disso.
Aparece uma key na tela em vez do texto
Uma mensagem que não resolve em lugar nenhum se renderiza como a sua própria key. Normalmente o catálogo desse idioma ainda não chegou, ou o grupo é um que você excluiu do navegador com bundle.exclude e algo o pede em runtime. O build avisa do segundo caso pelo nome. Se só acontece no seu idioma fonte, o mais provável é que a key esteja em uma tradução e não no seu catálogo fonte: npx verbaly check a lista como uma chave que só uma tradução tem.
Minha edição no catálogo fonte sumiu
Esse texto está escrito no seu código, com t`…` ou t.id, então ele é do código: o servidor de desenvolvimento, o extract e o build colocam o texto do código de volta. A mensagem diz qual arquivo o tem, e é lá que se muda. Se você quer editar um texto no catálogo, deixe só a chave dele no código, como t('key'). No terminal, o extract imprime uma linha para cada texto que colocou de volta, com o texto que tinha, para você ver exatamente o que ele desfez.
Uma tradução aparece como desatualizada
O texto fonte dela mudou depois que foi escrita, e ninguém a tocou desde então. Também pode aparecer logo depois de um import: o arquivo de um tradutor traz o texto fonte de onde partiu, então um arquivo feito para uma versão anterior já chega desatualizado. Atualize a tradução e o aviso some sozinho. Se ela ainda diz a coisa certa, mantenha com npx verbaly review --approve. Nunca quebra um build a menos que o seu CI rode check --outdated.
O verbaly.lock tem um conflito de merge
O verbaly.lock registra quais traduções são rascunhos da máquina e para qual texto fonte cada uma foi escrita. Quando duas branches traduziram em paralelo, um merge pode deixá-lo com um conflito, e não há lado para escolher: o Verbaly lê os dois e mantém todos os rascunhos de cada um. O próximo extract escreve o arquivo inteiro e avisa. Adicione-o ao commit que resolve o merge.
Se o arquivo continuar ilegível (um conflito editado pela metade, por exemplo), os comandos que só o leem avisam e seguem, e os que escreveriam rascunhos param antes de escrever qualquer coisa. Corrija-o à mão e mantenha as entradas dos dois lados: apagá-lo, ou ficar com um lado só, aprovaria rascunhos que ninguém leu.
Um texto fica no meu idioma fonte
O compilador só lê as chamadas que se chamam t, então de uma função de tradução com outro nome, como const tr = useT(), o texto nunca é extraído. O extract e o doctor apontam cada uma com o arquivo e a linha, também em arquivos .vue, .svelte e .astro: renomeie para t. Se o arquivo está fora do seu include, nada nele é lido também, e o seu build e o servidor de desenvolvimento o apontam ao começar, com o padrão a adicionar:
A página trocou de idioma logo depois de carregar
A página chegou em um idioma e a instância do navegador começou em outro, então o bindDom traduziu a página para o dele. Ele avisa uma vez, nomeando os dois. Quando o endereço leva o idioma, crie a instância com o locale que o localeFromPath lê dele; quando não, chame antes o persistLocale, para que a página e o navegador partam da mesma escolha.
Uma mensagem mostra o seu código ICU em vez do texto
A sintaxe ICU precisa do seu parser, e o compilador só o inclui quando algum dos seus catálogos usa essa sintaxe no build. Uma mensagem que chega depois, de um CMS ou pelo addMessages, não encontra parser, então mostra o seu próprio código e avisa uma vez. Coloque icu: true na sua config do verbaly para incluir sempre o parser, ou passe icu ao createVerbaly se você cria a instância.
As minhas keys não estão tipadas, ou os tipos estão velhos
Os tipos são escritos pelo extract, pelos servidores de desenvolvimento e pelo build, então um clone novo ou um job de CI não tem nenhum até que um deles rode: npx verbaly typegen os escreve sozinho, e é a solução para Cannot find module 'virtual:verbaly'. Eles vão para onde o seu framework já os lê, e um Cannot redeclare significa um verbaly.d.ts antigo que ficou na raiz, que a próxima execução remove. Um erro de digitação numa chave falha com a chave no erro.
O prune deixou chaves que você não usa mais
Enquanto algum arquivo fonte não puder ser lido, o extract --prune não remove nada e aponta o arquivo. Um arquivo que ele não consegue ler pode ser justamente o que usa essas chaves, e removê-las nesse momento apagaria as traduções delas. Corrija o erro de sintaxe e rode de novo.
Não se consegue importar t do verbaly
Nenhum pacote exporta t. Ele vem do módulo próprio do seu projeto, virtual:verbaly, ou do hook do seu framework. O doctor reporta este como erro porque nenhum bundler o consegue resolver.