Fluxo i18n no Vue 3 para 500+ chaves sem surpresas em produção
Um fluxo prático de i18n para Vue 3 em apps grandes: nomeação de chaves, plurais, checagens de QA e passos de release para evitar traduções faltantes em produção.

O que dá errado com mais de 500 chaves i18n
Quando seu app passa algumas centenas de strings, a primeira coisa que costuma quebrar raramente é o Vue I18n. É a consistência. As pessoas adicionam chaves em estilos diferentes, duplicam a mesma ideia com nomes distintos e ninguém tem certeza de quais mensagens são seguras para apagar.
Traduções faltantes também deixam de ser raras. Elas aparecem em fluxos normais do usuário, especialmente em telas menos usadas como configurações, estados de erro, telas vazias e notificações.
Quando falta uma tradução, os usuários geralmente veem uma de três falhas: uma UI em branco (um botão sem rótulo), chaves brutas (como checkout.pay_now) ou um fallback estranho em que parte da página muda de idioma. Nenhuma dessas situações parece um bug pequeno. Elas fazem o app parecer quebrado.
Por isso um fluxo i18n no Vue 3 importa mais do que a biblioteca específica. A biblioteca faz o que você pedir. Em escala, times frequentemente não concordam sobre o que significa “pronto”.
Um exemplo comum: um desenvolvedor entrega um novo fluxo “Convidar colega” com 40 novas strings. O arquivo em inglês é atualizado, mas o arquivo em francês não. Em staging, tudo parece bem porque o testador usa inglês. Em produção, usuários franceses veem uma mistura de UI traduzida e não traduzida, e o suporte recebe screenshots de chaves brutas.
A correção é definir o que significa “pronto” para UI traduzida. Não pode ser apenas “strings adicionadas”. Uma definição prática de pronto normalmente inclui: chaves seguem regras de nomenclatura, os locais compilam sem avisos de chave ausente, plurais e variáveis renderizam corretamente com dados reais, pelo menos uma localidade não padrão foi verificada e mudanças de texto são rastreadas para que chaves antigas não permaneçam.
Com 500+ chaves, você vence tratando localização como um processo de release, não como uma edição de arquivo no último minuto.
Defina algumas regras antes de adicionar mais strings
Depois de algumas centenas de strings, o trabalho de tradução não é a parte bagunçada. É a consistência. Um conjunto pequeno de regras torna seu fluxo i18n no Vue 3 previsível, mesmo quando várias pessoas mexem no texto toda semana.
Comece decidindo o que é um “conceito” e mantendo uma única fonte de verdade para ele. Se a mesma ideia de UI aparece em cinco lugares (por exemplo, “Salvar alterações”), você quer uma chave, não cinco variações como save, saveChanges, save_update e saveBtn. Chaves duplicadas divergem de significado com o tempo, e os usuários sentem essa inconsistência.
Em seguida, decida onde vive a formatação. Times frequentemente dividem isso por acidente: algumas mensagens incluem pontuação e caixa (maiúsculas/minúsculas), outras dependem do código para acrescentar isso. Escolha uma abordagem e mantenha-a.
Um padrão prático:
- Coloque gramática, pontuação e formatação visível ao usuário (como “(opcional)”) na mensagem.
- Mantenha formatação de dados pura no código (datas, moeda, unidades) e passe o resultado para o i18n.
- Use placeholders para nomes e contagens, não concatenação de strings.
- Trate HTML nas mensagens como um caso especial com uma regra clara (permitido ou não permitido).
Depois defina responsabilidades. Decida quem pode adicionar novas chaves, quem revisa o texto no idioma base e quem aprova as outras localidades. Sem isso, strings são adicionadas às pressas e nunca revisadas.
Por fim, escolha e documente uma estratégia de fallback. Se uma chave estiver faltando, o que os usuários devem ver: o nome da chave, o texto do idioma padrão ou uma mensagem genérica segura? Em produção, muitos times preferem recorrer ao idioma padrão e registrar o problema, assim usuários não ficam bloqueados enquanto você recebe um sinal de que algo está errado.
Se você constrói apps Vue 3 com um gerador como AppMaster (Vue3 web UI mais backend real), essas regras continuam válidas. Trate traduções como conteúdo de produto, não como “apenas texto de dev”, e você evitará a maioria das surpresas de última hora.
Convenções de nomenclatura de chaves que permanecem legíveis
Depois de algumas centenas de strings, consistência é o maior multiplicador. Escolha um estilo de chave (a maioria usa caminhos com ponto como billing.invoice.title) e torne isso uma regra. Misturar pontos, barras, snake_case e caixa aleatória torna busca e revisão lentas.
Use chaves estáveis que sobrevivam a mudanças de texto. Uma chave como "Please enter your email" vai quebrar no momento em que o marketing ajustar a frase. Prefira nomes baseados na intenção como auth.email.required ou auth.email.invalid.
Agrupe chaves por área do produto ou superfície da UI primeiro, depois por propósito. Pense nas mesmas categorias que seu app já tem: auth, billing, settings, support, dashboard. Isso mantém os arquivos de localidade mais fáceis de ler e reduz duplicatas quando duas telas precisam da mesma ideia.
Dentro de cada área, mantenha um pequeno conjunto de padrões para peças comuns de UI:
- Botões:
*.actions.save,*.actions.cancel - Rótulos:
*.fields.email.label,*.fields.password.label - Dicas/ajuda:
*.fields.email.hint - Erros/validação:
*.errors.required,*.errors.invalidFormat - Notificações/toasts:
*.notices.saved,*.notices.failed
Mensagens dinâmicas devem dizer o que muda, não como. Nomeie a mensagem pela intenção e use parâmetros para as partes variáveis. Por exemplo, billing.invoice.dueInDays com {days} é mais claro que billing.invoice.dueIn3Days.
Exemplo (funciona bem em um fluxo i18n Vue 3): orders.summary.itemsCount com {count} para o número, e orders.summary.total com {amount} para valores monetários. Quando alguém lê a chave no código, deve saber onde ela pertence e por que existe, mesmo que o texto final mude depois.
Regras de plural e formatação de mensagens sem surpresas
Texto plural quebra silenciosamente quando você trata todo idioma como inglês. Decida cedo quando usar a sintaxe ICU e quando um placeholder simples é suficiente.
Use substituições simples para rótulos e textos curtos que nunca mudam por número (por exemplo, "Welcome, {name}"). Passe para ICU para qualquer coisa baseada em contagem, porque ele mantém todas as formas em um só lugar e torna as regras explícitas.
{
"notifications.count": "{count, plural, =0 {No notifications} one {# notification} other {# notifications}}"
}
Escreva mensagens de contagem de modo que sejam fáceis de traduzir. Prefira uma frase completa e mantenha o placeholder do número (#) próximo ao substantivo. Evite atalhos criativos como reutilizar a mesma chave para “1 item” e “2 items” no código. Tradutores precisam ver a mensagem inteira, não adivinhar como ela será montada.
Planeje =0, one e other no mínimo, e documente o que você espera para 0. Alguns produtos querem “0 items”, outros preferem “No items”. Escolha um estilo e mantenha-o para que a UI pareça consistente.
Também fique atento a idiomas com mais categorias de plural do que você espera. Muitos idiomas não seguem “um vs muitos”. Se você adicionar uma nova localidade depois, uma mensagem que só tem one e other pode ficar gramaticalmente errada mesmo que renderize.
Antes de enviar, teste plurais com contagens reais na UI, não apenas olhando o JSON. Uma verificação rápida que pega a maioria dos problemas é 0, 1, 2, 5 e 21.
Se você constrói um app web Vue3 (por exemplo, dentro do AppMaster), faça esse teste na tela real onde o texto aparece. Problemas de layout, texto truncado e frases estranhas aparecem primeiro lá.
Organizando arquivos de localidade para crescer
Após algumas centenas de strings, um único en.json grande vira um gargalo. Pessoas mexem no mesmo arquivo, conflitos de merge crescem e você perde a noção de onde o texto vive. Uma boa estrutura mantém seu fluxo i18n no Vue 3 estável mesmo quando o produto continua mudando.
Estruturas sugeridas
Para 2 a 5 localidades, dividir por feature costuma ser suficiente. Mantenha a mesma organização de arquivos em cada localidade para que adicionar uma chave seja uma edição previsível.
locales/en/common.json,locales/en/auth.json,locales/en/billing.jsonlocales/es/common.json,locales/es/auth.json,locales/es/billing.jsonlocales/index.ts(carrega e mescla mensagens)
Para 20+ localidades, escale a mesma ideia, mas torne mais difícil o desvio. Trate o inglês como fonte de verdade e imponha que todo locale espelhe as mesmas pastas e nomes de arquivos. Se um novo domínio aparecer (por exemplo, notifications), ele deve existir para cada localidade mesmo que o texto seja temporário.
Dividir por domínio reduz conflitos de merge porque duas pessoas podem adicionar strings em arquivos diferentes sem se atrapalhar. Os domínios devem corresponder à forma como seu app é construído: common, navigation, errors, settings, reports, além de pastas de feature para áreas maiores.
Mantendo chaves consistentes
Dentro de cada arquivo, mantenha a mesma forma de chave entre as localidades: mesma hierarquia, mesmos nomes de chave, texto diferente. Evite chaves “criativas” por idioma, mesmo se uma frase for difícil de traduzir. Se em inglês existe billing.invoice.status.paid, toda localidade deve ter exatamente essa chave.
Centralize apenas o que realmente se repete em todo lugar: rótulos de botões, erros de validação genéricos e navegação global. Mantenha copy específica de feature próxima ao domínio da feature, mesmo que pareça reutilizável. “Salvar” pertence a common. “Salvar método de pagamento” pertence a billing.
Conteúdo longo
Textos longos de ajuda, passos de onboarding e templates de email ficam confusos rápido. Algumas regras ajudam:
- Coloque strings longas em seu próprio domínio (por exemplo,
helpouonboarding) e evite nesting profundo. - Prefira parágrafos curtos em vez de uma string massiva, para que tradutores trabalhem com segurança.
- Se marketing ou suporte edita o texto com frequência, mantenha essas mensagens em um arquivo dedicado para reduzir churn em outras áreas.
- Para emails, armazene assunto e corpo separadamente e mantenha placeholders consistentes (nomes, datas, valores).
Essa configuração facilita revisar mudanças, traduzir de forma constante e evitar lacunas de última hora antes do release.
Um fluxo passo a passo para adicionar e enviar strings
Um fluxo i18n estável no Vue 3 é menos sobre ferramentas e mais sobre repetir os mesmos passos pequenos toda vez. Novo texto de UI não deve chegar à produção sem uma chave, um texto padrão e um status de tradução claro.
Comece adicionando a chave ao seu locale base (frequentemente en). Escreva o texto padrão como copy real, não um placeholder. Isso dá a produto e QA algo legível para revisar e evita “strings misteriosas” depois.
Quando usar a chave em um componente, inclua parâmetros e lógica de plural desde o primeiro dia para que tradutores vejam a forma completa da mensagem.
// simple param
$t('billing.invoiceDue', { date: formattedDate })
// plural
$t('files.selected', count, { count })
Se as traduções não estiverem prontas, não deixe chaves faltando. Adicione traduções placeholder em outros locais ou marque-as como pendentes de forma consistente (por exemplo, prefixe o valor com TODO:). O importante é que o app renderize de forma previsível e os revisores consigam identificar texto incompleto.
Antes de mesclar, rode checagens automatizadas rápidas. Mantenha-as chatas e rígidas: chaves faltando entre localidades, chaves não usadas, discrepância de placeholders (falta de {count}, {date} ou chaves com chaves erradas), formas plurais inválidas para idiomas suportados e sobrescritas acidentais.
Por fim, faça uma passagem rápida na UI em pelo menos uma localidade não-base. Escolha um idioma com strings mais longas (frequentemente alemão ou francês) para pegar overflow, botões truncados e quebras de linha estranhas. Se sua UI Vue 3 for gerada ou mantida junto com outras partes do produto (por exemplo, um app web Vue3 produzido pelo AppMaster), esse passo ainda importa porque layouts mudam conforme features evoluem.
Trate esses passos como sua definição de pronto para qualquer feature que adicione texto.
Erros comuns que times repetem
A forma mais rápida de tornar localização dolorosa é tratar chaves i18n como “apenas strings”. Após algumas centenas de chaves, hábitos pequenos viram bugs em produção.
Chaves que derivam, colidem ou enganam
Typos e diferenças de caixa são causas clássicas de texto faltante: checkout.title em um lugar, Checkout.title em outro. Parece ok no code review, então seu idioma de fallback é enviado silenciosamente.
Outro problema comum é reaproveitar uma chave para significados diferentes. “Open” pode significar “Abrir chamado” em suporte e “Abrir agora” em uma loja. Se você reutilizar uma única chave, uma dessas telas estará errada em outros idiomas, e tradutores vão adivinhar.
Uma regra simples ajuda: uma chave = um significado. Se o significado muda, crie uma nova chave mesmo que o texto em inglês seja igual.
Bugs de layout causados por suposições de “formato de string”
Times frequentemente codificam pontuação, espaçamento ou pedaços de HTML nas traduções. Isso funciona até um idioma precisar de pontuação diferente, ou sua UI escapar/renderizar marcação de forma diferente. Mantenha decisões de marcação nos templates e mensagens focadas em texto.
Mobile é onde problemas se escondem. Um rótulo que cabe em inglês pode quebrar em três linhas em alemão ou transbordar em tailandês. Se você só testa um tamanho de tela, perde isso.
Fique de olho em culpados frequentes: assumir ordem de palavras em inglês ao inserir variáveis (nomes, contagens, datas), montar mensagens concatenando pedaços em vez de usar uma única mensagem, esquecer de testar valores longos (nomes de produto, endereços, detalhes de erro), enviar com fallback silencioso habilitado de modo que chaves faltantes “pareçam” ok em inglês, e copiar/colar chaves enquanto edita somente o valor em inglês.
Se você quer um fluxo i18n Vue 3 que se mantenha calmo com 500+ chaves, trate chaves como parte da sua API: estáveis, específicas e testadas como todo o resto.
Passos de QA que pegam traduções faltantes cedo
Traduções faltantes são fáceis de não perceber porque o app ainda “funciona”. Ele apenas volta para a chave, o idioma errado ou uma string vazia. Trate cobertura de tradução como testes: você quer feedback rápido antes de qualquer coisa chegar à produção.
Checagens automatizadas (rodar em todo PR)
Comece com checagens que façam o build falhar, não avisos que ninguém lê.
- Escaneie o código por
$t('...')et('...'), então verifique se cada chave usada existe no locale base. - Compare conjuntos de chaves entre localidades e falhe se algum locale estiver faltando chaves (a menos que a chave esteja em uma lista de exceções curta e revisada como “apenas en para notas legais”).
- Marque chaves órfãs que existem em arquivos de localidade mas nunca são usadas.
- Valide a sintaxe das mensagens (placeholders, blocos ICU/plural). Uma única mensagem quebrada pode travar uma página em runtime.
- Trate chaves duplicadas ou caixa inconsistente como erros.
Mantenha a lista de exceções curta e de responsabilidade do time, não “o que passar no CI”.
Checagens em runtime e visuais (staging)
Mesmo com CI, você ainda quer uma rede de segurança em staging porque caminhos reais do usuário disparam strings que você esqueceu.
Habilite logging de tradução faltante em staging e inclua contexto suficiente para corrigir rápido: locale, rota, nome do componente (se disponível) e a chave ausente. Torne isso barulhento. Se for fácil ignorar, será ignorado.
Adicione uma pseudo-localidade e use-a para uma checagem visual rápida. Uma abordagem simples é transformar cada string (torná-la mais longa e adicionar marcadores) para que problemas de layout saltem aos olhos, por exemplo: [!!! 𝗧𝗲𝗫𝗧𝗢 𝗘𝗫𝗣𝗔𝗡𝗗𝗜𝗗𝗢 !!!]. Isso pega botões cortados, cabeçalhos de tabela quebrados e espaçamentos faltantes antes do envio.
Por fim, faça uma checagem pré-release curta dos fluxos de maior valor em 2-3 localidades: login, checkout/pagamento, configurações principais e a nova feature que você está liberando. É aqui que você pega “foi traduzido mas o placeholder está errado”.
Lidando com novos idiomas e mudanças contínuas de texto
Adicionar um novo idioma vira bagunça quando você trata isso como “trabalho de copy” em vez de um pequeno release de produto. A forma mais fácil de manter seu fluxo i18n no Vue 3 estável é fazer o app buildar mesmo quando um locale está incompleto, enquanto torna lacunas óbvias antes que usuários as vejam.
Quando adicionar uma nova localidade, comece gerando a mesma estrutura de arquivos do seu locale fonte (geralmente en). Não traduza primeiro, estruture primeiro.
- Crie a nova pasta/arquivo de locale com o conjunto completo de chaves copiado da fonte.
- Marque valores como placeholders TODO para que strings faltantes fiquem visíveis no QA.
- Adicione o idioma ao seletor apenas depois que o básico estiver coberto.
- Rode uma passagem tela a tela para pegar problemas de layout (palavras mais longas, quebra de linha).
Traduções frequentemente chegam atrasadas, então decida antecipadamente o que significa “parcial” para seu produto. Se uma feature é voltada ao cliente, considere feature flags para que a feature e suas strings sejam lançadas juntas. Se você tiver que liberar sem traduções completas, prefira um fallback claro (como inglês) a rótulos vazios, mas torne isso barulhento em staging.
Atualizações de copy são onde times quebram chaves. Se você muda a redação, mantenha a chave estável. Chaves devem descrever intenção, não a sentença exata. Guarde renomear a chave para quando o significado mudar, e mesmo assim faça uma migração controlada.
Para evitar “strings zumbi”, deprecie chaves com propósito: marque como deprecado com data e substituição, mantenha por um ciclo de release e remova somente depois de confirmar que não há referências.
Mantenha notas de tradução próximas à chave. Se seu formato JSON não aceita comentários, armazene notas em um pequeno documento acompanhante ou em um arquivo de metadata adjacente (por exemplo, “usado na tela de sucesso do checkout”). Isso é especialmente útil quando seu app web Vue 3 é gerado por uma ferramenta como AppMaster e várias pessoas mexem em copy e UI.
Exemplo: entregar uma feature com 60 novas strings
Em uma sprint, seu time entrega três coisas ao mesmo tempo: uma nova página de Configurações, uma tela de Billing e três templates de email (recibo, pagamento falhou, fim do trial). São cerca de 60 novas strings, e é aí que i18n costuma ficar bagunçado.
O time concorda em agrupar chaves por feature e depois por superfície. É criado um novo arquivo para cada feature, e as chaves seguem o mesmo padrão em todo lugar: feature.area.element.
// settings
"settings.profile.title": "Profile",
"settings.security.mfa.enable": "Enable two-factor authentication",
// billing
"billing.plan.current": "Current plan",
"billing.invoice.count": "{count} invoice | {count} invoices",
// email
"email.receipt.subject": "Your receipt",
"email.payment_failed.cta": "Update payment method"
Antes de começar a tradução, strings plurais são testadas com valores reais, não suposições. Para billing.invoice.count, o QA verifica 0, 1, 2 e 5 usando dados seedados (ou um simples toggle dev). Isso pega casos estranhos cedo, como "0 invoice".
O QA então roda um fluxo focado que tende a revelar chaves faltantes: abrir Settings e Billing e clicar em cada aba uma vez, acionar cada template de email em staging com contas de teste, rodar o app com uma localidade não padrão ativa e falhar o build se houver qualquer aviso de tradução faltante nos logs.
Nesta sprint, o QA encontra duas chaves faltantes: um rótulo na tela de Billing e um assunto de email. O time corrige antes do release.
Na decisão de bloquear o release ou permitir fallback, eles usam uma regra simples: telas voltadas ao usuário e emails transacionais bloqueiam o release; texto de baixo risco só para admins pode temporariamente cair para o idioma padrão, mas somente com um ticket e um prazo claro.
Próximos passos e um checklist simples de release
Um fluxo i18n no Vue 3 se mantém estável quando você trata traduções como código: adicione do mesmo jeito sempre, teste e mantenha métricas.
Checklist de release (5 minutos antes do merge)
- Chaves: seguem seu padrão de nomenclatura e escopo claro (página, feature, componente).
- Plurais: confirme que formas plurais renderizam corretamente em pelo menos um idioma com regras plurais múltiplas.
- Placeholders: verifique que variáveis estão presentes, com os mesmos nomes em todos os lugares e ficam corretas com dados reais.
- Fallbacks: confirme que o comportamento para chave ausente corresponde à sua política atual.
- Telas: verifique rapidamente as poucas telas mais propensas a quebrar (tabelas, toasts, modais, estados vazios).
Decida o que medir (para que problemas apareçam cedo)
Escolha alguns números simples e reveja regularmente: taxa de chaves faltantes no seu teste, contagem de strings não traduzidas em localidades não padrão e contagem de chaves não usadas (strings que não aparecem mais em lugar nenhum). Acompanhe por release se possível, para ver tendências em vez de falhas pontuais.
Escreva os passos exatos para adicionar uma string, atualizar traduções e verificar o resultado. Mantenha curto e inclua exemplos de nomes de chaves e uso de plurais. Novos colaboradores devem conseguir seguir sem perguntar.
Se você constrói ferramentas internas, AppMaster (appmaster.io) pode ser uma maneira prática de manter copy da UI e chaves de tradução consistentes entre um app web Vue3 e apps móveis acompanhantes, já que tudo é gerenciado em um só lugar.
Agende uma pequena tarefa de saúde i18n a cada sprint: delete chaves mortas, corrija placeholders inconsistentes e reveja falhas recentes. Limpezas pequenas vencem buscas emergenciais de tradução em produção.


