Voltar ao blog

Como automatizar o fluxo de trabalho de tradução no Django

2026-07-11 10 min de leitura

Se você já trabalhou com o sistema de tradução do Django por algum tempo, conhece o ritual. Você marca strings com _(), executa makemessages, abre um arquivo .po e se depara com centenas de campos msgstr vazios. Depois repete tudo para cada idioma que o seu app suporta.

O processo funciona. Mas tambem consome horas que poderiam ser dedicadas a construir funcionalidades. Um projeto com 200 strings traduzíveis em cinco idiomas significa 1.000 traduções para gerenciar. Mude o texto de um botão e você precisa atualizar os cinco arquivos .po antes do próximo deploy, ou acaba publicando páginas parcialmente traduzidas.

O fluxo de trabaho manual tem suas limitações, mas existem formas práticas de automatizá-lo sem perder o controle sobre a qualidade.

O fluxo de trabalho manual

O pipeline de tradução nativo do Django tem quatro passos:

  1. Marcar strings com gettext ou {% trans %} no seu código e templates
  2. Executar makemessages para extraí-las em arquivos .po
  3. Traduzir as entradas msgstr em cada arquivo .po
  4. Executar compilemessages para produzir os arquivos binários .mo que o Django lê

Os passos 1 e 2 são rápidos. O passo 4 é um único comando. O passo 3 é onde tudo desacelera.

Como o passo 3 funciona na prática

Abra o arquivo locale/de/LC_MESSAGES/django.po no seu editor. Você verá algo assim:

#: myapp/views.py:42
msgid "Your subscription has been renewed."
msgstr ""

#: myapp/templates/dashboard.html:18
msgid "Welcome back, %(username)s"
msgstr ""

#: myapp/forms.py:15
msgid "This field is required."
msgstr ""

Para cada entrada, você precisa de uma tradução correta que preserve quaisquer variáveis de placeholder como %(username)s ou {count}. Quebre um placeholder e o Django vai lançar um erro de formataçao em tempo de execução.

Com cinco idiomas e cem strings novas, você está olhando para uma tarde inteira de copiar e colar entre serviços de tradução, corrigir formatos de placeholder e torcer para não ter esquecido nada. E no próximo sprint, o ciclo se repete.

Onde a abordagem manual começa a falhar

Projetos pequenos conseguem se virar com tradução manual. Quando um projeto ultrapassa alguns limites, o fluxo de trabalho começa a incomodar.

Quantidade crescente de strings

Um app Django com uma dúzia de templates, alguns formulários e algumas notificações por email pode facilmente chegar a 300 strings traduzíveis. Multiplique pelo número de idiomas suportados e o total cresce rápido. A partir de certo ponto, ninguém quer ser a pessoa que abre aquele arquivo .po.

Traduções desatualizadas

Quando desenvolvedores alteram strings existentes, o makemessages marca as traduções antigas como fuzzy. Essas entradas fuzzy precisam de revisão manual, e elas tendem a se acumular porque ninguém percebe até um usuário reportar que está vendo inglês em uma página em alemão. O backlog de fuzzy mantem um crescimento silencioso entre releases.

Erros de placeholder

O formato .po do Django usa vários estilos de placeholder: %(name)s para formatação com % do Python, {name} para .format() e f-strings, e {{ name }} para variáveis de template. Tradutores (humanos ou máquinas) às vezes corrompem esses placeholders, e os erros só aparecem em tempo de execução. Um %(username)s incorreto em uma tradução para alemão pode derrubar uma view que funciona perfeitamente em inglês.

Bloqueando deploys

Se as traduções são um passo manual no seu pipeline de deploy, elas se tornam um gargalo. Ou você espera pelas traduçoes antes de fazer deploy (lento), ou faz deploy com traduções faltando (experiência ruim para o usuário). Nenhuma opção é boa quando você está fazendo releases semanais.

Como a automação funciona

Automatizar traduções do Django significa substituir o passo 3 (a parte de tradução manual) por um processo programático, mantendo todo o resto igual. Seu fluxo de makemessages e compilemessages não muda. Você apenas para de traduzir arquivos .po na mão.

Opção 1: criar seu próprio script

Você pode escrever um script que lê um arquivo .po, envia strings não traduzidas para uma API de tradução e grava os resultados de volta. A versão básica é surpreendentemente curta:

import polib
from openai import OpenAI

client = OpenAI()
po = polib.POFile("locale/de/LC_MESSAGES/django.po")

for entry in po.untranslated_entries():
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": "Translate to German. Preserve all "
             "placeholder variables like %(name)s exactly as they appear."},
            {"role": "user", "content": entry.msgid},
        ],
    )
    entry.msgstr = response.choices[0].message.content.strip()

po.save()

Isso resolve 80% do problema. Os 20% restantes são onde a coisa fica complicada:

  • Formas plurais (msgid_plural e múltiplas entradas msgstr[n]) precisam de tratamento especial, porque idiomas diferetes têm regras de plural diferentes
  • Strings de contexto (msgctxt) devem ser passadas para a API para que a tradução se adeque ao uso
  • É necesário validar que os placeholders sobreviveram à tradução intactos
  • Limites de taxa e erros de API precisam de lógica de retry
  • O script precisa lidar corretamente com a codificação de arquivos .po (UTF-8 com campos de cabeçalho específicos)
  • Entradas fuzzy precisam de tratamento diferente das não traduzidas

Construir tudo isso por conta própria é viável, mas leva alguns dias de trabalho e manuteção contínua. Toda vez que uma API de tradução muda seu comportamento ou preços, você precisa atualizar o script.

Opção 2: usar uma plataforma de gerenciamento de tradução

Serviços como Crowdin, Transifex e Lokalise se integram com controle de versão e oferecem uma interface web para tradutores. Eles lidam com arquivos .po nativamente, suportam formas plurais e permitem configurar fluxos automatizados com tradução automática como primeiro passo.

O trade-off é custo e complexidade. Essas plataformas são feitas para equipes com tradutores dedicados, e os preços refletem isso. Para um desenvolvedor solo ou uma equipe pequena que precisa apenas de arquivos .po traduzidos, elas adicionam mais infraestrutura do que o necessário.

Opção 3: ferramentas especializadas

Ferramentas construídas especificamente para o fluxo de trabalho de arquivos .po do Django conseguem automatizar a tradução respeitando as particularidades do formato. Elas lidam com formas plurais, preservam placeholders, gerenciam entradas fuzzy e se integram com o pipeline existente de makemessages/compilemessages.

A vantagem é que foram projetadas exatamente para esse caso de uso, então há menos código de integração para escrever e manter. A desvantagem é que você está adicionando uma dependecia ao seu fluxo de tradução.

Configurando traduções automáticas no CI/CD

Independente de qual ferramenta você escolher, a integração com o pipeline de deploy segue o mesmo padrão:

# .github/workflows/translate.yml
name: Update translations

on:
  push:
    branches: [main]

jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: pip install django

      - name: Extract new strings
        run: python manage.py makemessages -a --no-obsolete

      - name: Translate .po files
        run: python scripts/translate.py  # your translation script

      - name: Compile messages
        run: python manage.py compilemessages

      - name: Commit and push
        run: |
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git add locale/
          git diff --staged --quiet || git commit -m "chore: update translations"
          git push

O workflow extrai novas strings, traduz, compila os resultados e faz commit dos arquivos atualizados. O check git diff --staged --quiet evita criar commits vazios quando nada mudou.

Você pode rodar isso como um pre-commit hook ou como um job agendado. A ideia central é a mesma: a tradução acontece automaticamente como parte do seu processo normal de desenvolvimento, não como um passo manual separado.

Validando traduções

Traduções automáticas precisam de validação. Mesmo os melhores modelos de IA ocasionalmente quebram formatos de placeholder ou produzem traduções que não se encaixam no contexto da interface.

Validação de placeholders

Escreva uma verificação que compare placeholders entre msgid e msgstr:

import re
import polib

PLACEHOLDER_RE = re.compile(r"%\(\w+\)[sd]|\{\w+\}|\{\{.*?\}\}")

def validate_po(path):
    po = polib.POFile(path)
    errors = []
    for entry in po.translated_entries():
        src = set(PLACEHOLDER_RE.findall(entry.msgid))
        dst = set(PLACEHOLDER_RE.findall(entry.msgstr))
        if src != dst:
            errors.append(f"Mismatch: {entry.msgid!r}")
    return errors

Rode isso no CI e falhe o build se algum placeholder estiver quebrado. Leva segundos e captura a classe mais perigosa de erros de tradução antes que cheguem a produção.

Verificação de comprimento

Algumas traduções ficam significativamente mais longas que a string original. Texto em alemão é tipicamente 20-30% mais longo que em inglês, e isso pode quebrar elementos de UI com largura fixa. Uma verificação simples de proporção de comprimento pode sinalizar traduções que podem causar problemas de layout.

Auditoria de entradas fuzzy

Após a tradução automática, verifique que nenhuma entrada ficou como fuzzy. Entradas fuzzy significam que o Django não vai usar a tradução, caindo de volta para o inglês. Seu pipeline de CI deve tratar entradas fuzzy como uma condição de falha, da mesma forma que trata um teste falhando.

Mantendo traduções sincronizadas

A parte mais difícil da manutenção de traduções não é a tradução inicial. É manter as traduções atualizadas conforme a base de código evolui.

Alterações em strings

Quando você altera uma string traduzível existente, o makemessages faz algo sutil: ele procura uma string similar no arquivo .po e cria um match fuzzy. A tradução antiga é preservada mas marcada como precisando de revisão. Isso é útil quando um tradutor humano está revisando alterações, mas significa que fluxos automatizados precisam lidar com entradas fuzzy de forma específica.

Uma abordagem prática: limpe a flag de fuzzy e re-traduza a entrada do zero. O fuzzy matching economiza trabalho para tradutores humanos, mas uma ferramenta automatizada pode simplesmente traduzir a nova string diretamente. O resultado geralmente é melhor do que tentar adaptar uma tradução antiga para uma nova string de origem.

Strings novas

Strings novas aparecem como entradas não traduzidas após executar makemessages. Seu fluxo automatizado deve traduzi-las e fazer commit dos resultados. Se você executa makemessages no CI, strings novas são traduzidas automaticamente quando mescladas.

Strings removidas

Executar makemessages --no-obsolete remove entradas de strings que não existem mais no seu código. Isso mantém os arquivos .po limpos e evita acumular traduções mortas ao longo do tempo.

O que verificar antes de automatizar

Antes de configurar tradução automatizada, verifique algumas coisas:

  • Todas as strings traduzíveis estão devidamente marcadas com _() ou {% trans %}. Execute makemessages e procure por strings que você deixou passar.
  • Sua configuração de LOCALE_PATHS está correta e a estrutura de diretórios locale/ está no lugar certo.
  • compilemessages executa sem erros nos seus arquivos .po existentes.
  • Você tem uma forma de revisar as traduções automáticas antes de publicá-las, mesmo que seja apenas um ambiente de staging onde alguém possa navegar pelo app em cada idioma.

A automação de tradução funciona melhor quando o resto da sua configuração de i18n está sólida. Automatizar o passo 3 não vai ajudar se os passos 1 e 2 estiverem quebrados.

Dicas práticas

Algumas coisas que aprendi trabalhando com traduções automáticas no Django:

  • Execute makemessages com --no-obsolete para manter os arquivos .po limpos. Entradas mortas confundem tanto revisores humanos quanto ferramentas automatizadas.
  • Use msgctxt quando a mesma string em inglês precisa de traduções diferentes em contextos diferentes. "Post" pode significar uma postagem de blog ou o ato de postar, e sem contexto o tradutor (humano ou automatizado) precisa adivinhar.
  • Teste com idiomas que são estruturalmente diferentes do inglês. As palavras mais longas do alemão e o conjunto de caracteres do japonês revelam bugs de layout que idiomas europeus não pegam.
  • Mantenha um arquivo TRANSLATING.md com terminologia especifica do projeto e diretrizes de tom. Se o seu projeto chama um "workspace" de "projeto" na interface, documente isso. Algumas ferramentas de tradução automática conseguem ler esse arquivo e aplicar suas preferências de forma consistente.
  • Faça commit de arquivos .po e .mo juntos. Se você compila mensagens no CI, garanta que os arquivos .mo estejam incluídos no seu artefato de deploy. O Django lê arquivos .mo, não arquivos .po.

Comparando abordagens

Para um desenvolvedor solo ou uma equipe pequena com um projeto Django suportando 3-5 idiomas:

Um script personalizado funciona se você gosta de mantê-lo e sua contagem de strings está abaixo de 200. Além disso, os casos extremos envolvendo formas plurais, placeholders e entradas fuzzy começam a consumir o tempo que você economizou.

Plataformas de gerenciamento de tradução fazem sentido se você tem uma equipe de tradutores trabalhando em múltiplos projetos. Para um único app Django, elas geralmente são excessivas.

Ferramentas especializadas acertam o meio-termo: lidam com as particularidades de arquivos .po sem exigir que você construa e mantenha a integração por conta própria. O custo mensal geralmente é menor que o tempo de engenharia gasto em uma solução personalizada.

Escolha a abordagem que se encaixa no tamanho da sua equipe e na disposição de manter infraestrutura de tradução. O importante é que as traduções deixem de ser um gargalo manual e passem a acontecer como parte do seu ciclo normal de desenvolvimento.

Pare de editar arquivos .po manualmente

TranslateBot automatiza traduções Django com IA. Um comando, todos os seus idiomas, centavos por tradução.