Ir para o conteúdo

Roadmap de internacionalização (i18n)

Diátaxis: explanation. Para o como traduzir, veja locale/README.md.

CLAUDE.md §1 e §5 fixam português brasileiro como idioma fonte do Anotae. i18n para outros idiomas é planejada de forma incremental.

Por que i18n vem depois

Anotae nasce focado no SUS brasileiro. Internationalizar antes de estabilizar a UX em PT-BR seria:

  • Caro: cada string que muda invalida traduções pendentes.
  • Distraído: tira foco do problema clínico real (atrito de digitação na APS/DF).
  • Prematuro: a primeira release internacional (v4.0, ~M36) espera demanda comprovada — uma UBS de Cabo Verde ou Moçambique pedindo o app, não suposição.

Fases planejadas

Fase Versão Idiomas Justificativa
Hoje v0.9.x – v3.x apenas PT-BR foco no piloto APS/DF
i18n base v0.9.0-beta4+ infra gettext pronta, _() em strings novas esta PR (#34)
Tradução parcial v3.x PT-PT (cobertura UI principal) dar conta de profissionais portugueses
i18n full v4.0 (M36+) PT-BR + PT-PT + ES + EN PALOPs + LATAM
Hub regional v5.0+ + FR, IT se houver demanda

Decisão técnica: Python gettext stdlib

Sem dependência nova. Suportado em todas as plataformas. Workflow padrão da comunidade Python (xgettext.po.mo).

Alternativas consideradas:

Opção Vantagem Desvantagem
gettext stdlib Zero deps; padrão API verbosa
Babel Pluralização melhor Dep extra
Fluent (Mozilla) Sintaxe rica Dep + curva
Crowdin/Weblate SaaS Workflow tradutor Vendor lock + custo

Convenção de msgid

Msgid = string PT-BR. Em outros projetos (Django, GNOME) o msgid é em inglês para máxima portabilidade. Anotae inverte porque:

  1. PT-BR é o idioma fonte, não destino.
  2. Sem .mo carregado, _("Salvar") devolve "Salvar" — UX fica intacta para a base de usuários atual.
  3. Tradutores de outros idiomas trabalham a partir de PT-BR (idioma que dominam, pelo menos no caso PALOP/LATAM).

A convenção pode mudar em v4.0+ se uma comunidade de tradutores não-lusófonos preferir msgid em inglês — então fazemos uma rodada de migração com tradução automatizada via msgmerge.

Workflow CI

.github/workflows/ci.yml deve (ainda não implementado neste PR) ganhar um step:

- name: Verifica que locale/anotae.pot está sincronizado
  run: scripts/i18n-extract.sh --check

Sem isso, strings novas com _() ficam "presas" — tradutor não vê até a próxima execução manual do script. Adicionar em PR de follow-up junto com a primeira tradução real.

Política sobre PII em strings traduzíveis

Strings de UI nunca devem conter PII de paciente em runtime. Quando uma string usa placeholder (_("Encounter %s salvo") % handle), o tradutor vê apenas "Encounter %s salvo" — sem dados reais.

Reforço:

  • O .pot é gerado por análise estática do código — só pega strings literais. Dados em runtime nunca entram no catálogo.
  • Tradutores recebem apenas o .pot — nunca o vault de qualquer usuário.
  • Inspecionar o .pot antes de mandar para tradução: grep -i 'cns\|cpf\|paciente' locale/anotae.pot deve retornar 0 linhas.

Quando reabrir esta decisão

  • Demanda comprovada de UBS lusófona não-brasileira → acelerar PT-PT para v1.x em vez de aguardar v3.x.
  • Patrocínio para tradução profissional → priorizar EN (alcance máximo) sobre PT-PT.
  • Comunidade tradutora aparece spontaneously e prefere msgid em EN → migrar via msgmerge.