Como encontrar chaves ausentes nos arquivos ARB de um app Flutter

Atualizado em · LocalePilot

Uma chave adicionada em inglês e esquecida em alemão, um placeholder renomeado em um único idioma: esses erros compilam sem problema e chegam aos seus usuários. Veja como pegá-los antes do lançamento.

Com pressa? Verifique seus arquivos ARB direto no navegador: grátis, sem cadastro, nada é enviado.

Como os arquivos ARB são organizados

Com o flutter gen-l10n, cada idioma tem seu próprio arquivo (app_en.arb, app_fr.arb…). O arquivo template, definido por template-arb-file no l10n.yaml, é a referência: ele contém todas as chaves e seus metadados @key (descrição, placeholders).

{
  "cartCount": "{count, plural, =0{Empty cart} =1{1 item} other{{count} items}}",
  "@cartCount": {
    "placeholders": { "count": { "type": "int" } }
  }
}

1. Deixe o Flutter listar as mensagens não traduzidas

Adicione a opção untranslated-messages-file ao l10n.yaml:

arb-dir: lib/l10n
template-arb-file: app_en.arb
untranslated-messages-file: untranslated.json

A cada geração, o Flutter grava nesse arquivo as chaves do template que faltam em cada idioma. É a verificação mais simples de configurar; confira se o arquivo está vazio (ou contém apenas {}) antes de publicar.

2. Compare as chaves com um pequeno script Dart

Para uma verificação de CI que falhe de forma clara, um script basta:

import 'dart:convert';
import 'dart:io';

void main() {
  final dir = Directory('lib/l10n');
  final template = _keys(File('lib/l10n/app_en.arb'));
  var failed = false;
  for (final file in dir.listSync().whereType<File>()) {
    if (!file.path.endsWith('.arb')) continue;
    final missing = template.difference(_keys(file));
    if (missing.isNotEmpty) {
      failed = true;
      print('${file.path}: ${missing.join(', ')}');
    }
  }
  if (failed) exit(1);
}

Set<String> _keys(File f) => (jsonDecode(f.readAsStringSync()) as Map<String, dynamic>)
    .keys
    .where((k) => !k.startsWith('@'))
    .toSet();

As chaves que começam com @ são metadados, por isso ficam fora da comparação.

3. Verifique os placeholders

Uma chave presente em todos os idiomas ainda pode quebrar: se a tradução francesa usa {nombre} enquanto o template declara {count}, o gen-l10n adiciona nombre como parâmetro extra em todos os locales, e as chamadas existentes deixam de compilar. Por outro lado, uma tradução que simplesmente perde um placeholder passa sem nenhum aviso (detalhes no guia de plurais e placeholders ICU). Para cada chave, compare os nomes entre chaves com os declarados em @key.placeholders. Atenção às mensagens ICU (plural, select): palavras-chave como other não são placeholders.

4. Fique de olho também nos valores vazios

Alguns fluxos de tradução criam a chave com um valor vazio até ela ser traduzida. Ela não aparece como "ausente", então adicione uma verificação que aponte strings vazias em todos os idiomas, exceto no template.

Checklist antes do lançamento

  • O arquivo de mensagens não traduzidas está vazio.
  • Todos os idiomas têm as mesmas chaves que o template.
  • Os placeholders batem, chave por chave.
  • Nenhum valor vazio fora do template.
  • As mensagens longas foram conferidas na tela nos idiomas mais extensos (alemão, por exemplo).

Perguntas frequentes

O Flutter avisa sobre traduções ausentes?

Sim, se você adicionar untranslated-messages-file ao l10n.yaml: o flutter gen-l10n lista ali as chaves do template que faltam em cada idioma. Sem essa opção, você só recebe um aviso resumido.

Preciso copiar os metadados @key em todos os idiomas?

Não. Os metadados (descrição, placeholders) são lidos do arquivo template; os outros arquivos só precisam das traduções.

Como evitar placeholders com nome errado?

Para cada chave, compare os nomes entre chaves na tradução com os declarados no template e faça a CI falhar quando forem diferentes.