Powrót do bloga

Django i18n: Kompletny przewodnik po automatyzacji tłumaczenia plików .po

2026-01-28 9 min czytania
Django i18n: Kompletny przewodnik po automatyzacji tłumaczenia plików .po

Jeśli kiedykolwiek wdrażałeś aplikację Django w więcej niż jednym języku, znasz tę procedurę. Opakowujesz swoje ciągi znaków w gettext(), uruchamiasz makemessages, otwierasz plik .po z setkami wpisów i zaczynasz tłumaczyć linia po linii. Dla dwóch języków i pięćdziesięciu ciągów jest to do zniesienia. Dla sześciu języków i pięciuset ciągów to cały dzień pracy, którego nigdy nie odzyskasz.

Ten przewodnik obejmuje pipeline internacjonalizacji (i18n) Django od początku do końca, wyjaśnia, gdzie się załamuje, i pokazuje, jak zautomatyzować bolesną część za pomocą tłumaczenia opartego na AI.

Standardowy workflow Django i18n

Wbudowany system i18n Django jest dobrze zaprojektowany. Główna pętla wygląda tak:

Krok 1: Oznacz ciągi do tłumaczenia w kodzie Python i szablonach:

from django.utils.translation import gettext as _

def dashboard(request):
    welcome = _("Welcome back, %(name)s!") % {"name": request.user.first_name}
    return render(request, "dashboard.html", {"welcome": welcome})
{% load i18n %}
<h1>{% trans "Account Settings" %}</h1>
<p>{% blocktrans %}You have {{ count }} unread messages.{% endblocktrans %}</p>

Krok 2: Wyodrębnij ciągi do plików .po:

python manage.py makemessages -l de -l fr -l nl

To skanuje cały kod źródłowy i generuje jeden plik .po na język, zawierający każdy tłumaczalny ciąg:

#: myapp/views.py:4
msgid "Welcome back, %(name)s!"
msgstr ""

#: templates/dashboard.html:2
msgid "Account Settings"
msgstr ""

Krok 3: Przetłumacz każdy pusty msgstr ręcznie.

Krok 4: Skompiluj gotowe pliki .po do binarnych plików .mo:

python manage.py compilemessages

Kroki 1, 2 i 4 są szybkie. Krok 3 to miejsce, gdzie proces się załamuje.

Dlaczego ręczne tłumaczenie się nie skaluje

Typowa aplikacja Django ma od 200 do 2000 tłumaczalnych ciągów. Pomnóż to przez liczbę języków docelowych, a zobaczysz poważne zaangażowanie czasowe.

To nie jest teoretyczna skarga. W znanym wątku Django Forum programista zgłosił, że spędza ponad 8 godzin na plik .po na ręcznych tłumaczeniach. Główny kontrybutor Django opisał ponad 10 godzin spędzonych na włączaniu tłumaczeń przesłanych przez społeczność do jednego wydania, głównie na przeglądzie, poprawkach formatowania i naprawianiu uszkodzonych placeholderów.

Problemy narastają z czasem:

Główna przyczyna polega na tym, że tłumaczenie jest traktowane jako jednorazowe zdarzenie, a nie jako przyrostowy, powtarzalny proces.

Automatyzacja tłumaczenia z AI

Idea jest prosta: zamiast człowieka otwierającego każdy plik .po i wypełniającego wartości msgstr, narzędzie czyta plik, wysyła nieprzetłumaczone ciągi do modelu AI lub API tłumaczeniowego, zapisuje wyniki z powrotem i zachowuje wszystko inne (komentarze, strukturę pliku, placeholdery, formy liczby mnogiej).

TranslateBot Django to pakiet open-source, który robi dokładnie to. Wpina się w system komend zarządzania Django, więc pasuje do workflow, który już masz.

Konfiguracja krok po kroku

1. Zainstaluj pakiet

pip install translatebot-django

Lub, jeśli używasz uv (zalecane):

uv add --dev translatebot-django

Instalacja jako zależność deweloperska jest celowa. TranslateBot jest potrzebny tylko podczas generowania tłumaczeń, nie w czasie wykonywania na produkcji.

2. Dodaj do INSTALLED_APPS

# settings.py
INSTALLED_APPS = [
    # ...
    "translatebot_django",
]

3. Skonfiguruj dostawcę AI

# settings.py
import os

TRANSLATEBOT_API_KEY = os.getenv("OPENAI_API_KEY")
TRANSLATEBOT_MODEL = "gpt-4o-mini"

TranslateBot używa LiteLLM pod spodem, co oznacza, że możesz podmienić dowolny z ponad 100 modeli, zmieniając jeden ciąg:

Dostawca Wartość TRANSLATEBOT_MODEL
OpenAI gpt-4o-mini, gpt-4o
Anthropic claude-sonnet-4-5-20250929
Google gemini/gemini-2.5-flash
Azure OpenAI azure/gpt-4o-mini
DeepL Użyj TRANSLATEBOT_PROVIDER = "deepl" zamiast tego

Dla DeepL zainstaluj dodatkowy pakiet: pip install translatebot-django[deepl]. Darmowy plan DeepL daje 500 000 znaków miesięcznie bez kosztów, co wystarcza dla większości małych i średnich projektów.

4. Zdefiniuj swoje języki

# settings.py
LANGUAGES = [
    ("en", "English"),
    ("de", "German"),
    ("fr", "French"),
    ("nl", "Dutch"),
    ("ja", "Japanese"),
]

5. Uruchom tłumaczenie

python manage.py translate

To wszystko. TranslateBot skanuje projekt w poszukiwaniu plików .po, identyfikuje nieprzetłumaczone wpisy, wysyła je do skonfigurowanego modelu AI w zoptymalizowanych partiach i zapisuje wyniki. Istniejące tłumaczenia pozostają nietknięte.

Aby przetłumaczyć jeden język:

python manage.py translate --target-lang nl

Wynik wygląda tak:

Translating to Dutch (nl)...
Found 42 strings to translate
Translating batch 1/2...
Translating batch 2/2...
Successfully translated 42 strings

6. Skompiluj jak zwykle

python manage.py compilemessages

Twój pełny workflow to teraz:

python manage.py makemessages -l de -l fr -l nl -l ja
python manage.py translate
python manage.py compilemessages

Trzy komendy. Każdy język. Każdy sprint.

Przyrostowy z założenia

Najważniejsza cecha dla powtarzalnego workflow to tłumaczenie przyrostowe. TranslateBot tłumaczy tylko wpisy, gdzie msgstr jest puste. Jeśli masz 500 ciągów i 15 jest nowych w tym sprincie, tylko te 15 zostanie wysłanych do API.

Ma to znaczenie z praktycznych powodów:

  1. Koszt. Płacisz tylko za nowe ciągi, nie za cały plik.
  2. Szybkość. Tłumaczenie 15 ciągów trwa sekundy, nie minuty.
  3. Stabilność. Tłumaczenia, które już przejrzałeś i zatwierdziłeś, nigdy nie zostaną nadpisane (chyba że jawnie użyjesz --overwrite).

Bezpieczeństwo placeholderów

Django używa kilku formatów placeholderów: %(name)s, %s, %d, {0}, {name} oraz inline'owe tagi HTML jak <strong> lub <a href="...">. Jeśli którykolwiek z nich zostanie uszkodzony w tłumaczeniu, otrzymasz błędy w czasie wykonywania lub uszkodzony markup.

TranslateBot instruuje model AI, aby zachował wszystkie formaty placeholderów i waliduje wynik. Ciąg taki jak:

Welcome to %(site_name)s! You have <strong>%(count)d</strong> new messages.

Jest tłumaczony na holenderski jako:

Welkom bij %(site_name)s! Je hebt <strong>%(count)d</strong> nieuwe berichten.

Każdy placeholder przetrwa nienaruszony.

Kontrola jakości z TRANSLATING.md

Modele AI tłumaczą lepiej, gdy rozumieją kontekst. TranslateBot szuka pliku TRANSLATING.md w katalogu głównym projektu i dołącza jego zawartość do każdego żądania tłumaczenia.

# Translation Context

## About This Project
A B2B project management tool for construction companies.

## Terminology
- "project" means a construction project, not a software project
- "plan" means a building plan/blueprint, not a subscription plan
- Keep "Gantt chart" as-is in all languages

## Tone
- German: use formal "Sie" form (business context)
- French: use formal "vous" form
- Dutch: use informal "je" form

## Do Not Translate
- Brand name: "BuildFlow"
- Feature names: "SmartSchedule", "CostTracker"

Ten plik jest wersjonowany razem z kodem, więc cały zespół dzieli ten sam kontekst tłumaczenia. Możesz również umieszczać pliki TRANSLATING.md dla poszczególnych aplikacji ze specjalistyczną terminologią. Moduł dokumentacji medycznej i moduł rozliczeniowy mogą mieć własne glosariusze.

Podgląd przed zatwierdzeniem

Flaga --dry-run pokazuje dokładnie, co zostałoby przetłumaczone, bez wykonywania jakichkolwiek wywołań API ani modyfikowania plików:

python manage.py translate --target-lang fr --dry-run
Found 15 untranslated entries
Dry run mode: skipping LLM translation

Would translate 'Welcome to our site'
Would translate 'Hello, %(name)s!'
...

Dry run complete: 15 entries would be translated

Jest to przydatne przed dużym przebiegiem tłumaczeń lub podczas wdrażania nowego członka zespołu, który chce zrozumieć, co komenda robi, zanim zobowiąże się do kosztów API.

Integracja CI/CD

Dezaktualizacja tłumaczeń jest nieunikniona bez egzekwowania. TranslateBot zawiera komendę zarządzania check_translations zaprojektowaną dla pipeline'ów CI:

# .github/workflows/ci.yml
jobs:
  translations:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - run: uv python install
      - run: uv sync --frozen
      - name: Install gettext
        run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gettext
      - name: Check translations
        run: uv run python manage.py check_translations --makemessages

Flaga --makemessages najpierw uruchamia makemessages -a --no-obsolete, upewniając się, że pliki .po odzwierciedlają aktualny kod źródłowy przed sprawdzeniem. Jeśli jakiekolwiek wpisy są nieprzetłumaczone lub rozmyte, komenda kończy działanie z kodem 1 i powoduje niepowodzenie buildu:

locale/de/LC_MESSAGES/django.po: 2 untranslated, 0 fuzzy
locale/nl/LC_MESSAGES/django.po: 0 untranslated, 1 fuzzy
CommandError: Translation check failed

Typowy workflow programisty staje się:

  1. Dodaj nowe tłumaczalne ciągi w branchu z nową funkcjonalnością.
  2. CI nie przechodzi, ponieważ te ciągi są nieprzetłumaczone.
  3. Uruchom python manage.py translate lokalnie.
  4. Zatwierdź zaktualizowane pliki .po.
  5. CI przechodzi.

Tłumaczenia nigdy nie rozjeżdżają się po cichu.

Tłumaczenie zawartości bazy danych

Jeśli twoja aplikacja przechowuje tłumaczalną zawartość w bazie danych (nazwy produktów, tytuły wpisów blogowych, etykiety kategorii), TranslateBot integruje się również z django-modeltranslation:

pip install translatebot-django[modeltranslation]
# Translate all registered model fields
python manage.py translate --target-lang de --models

# Translate specific models only
python manage.py translate --target-lang de --models Product Category

Ta sama logika przyrostowa obowiązuje: tłumaczone są tylko pola, w których wartość języka docelowego jest pusta.

Porównanie kosztów

Jednym z najczęstszych pytań jest to, czy tłumaczenie AI jest opłacalne w porównaniu z alternatywami. Oto przybliżone porównanie dla projektu z 500 tłumaczalnymi ciągami w 5 językach:

Podejście Szacunkowy koszt Nakład czasu
Ręczne (czas programisty) $0 z kieszeni, 20-40+ godzin Bardzo wysoki
Profesjonalna usługa tłumaczeniowa $500-2000+ Niski (ale wolny zwrot)
Platforma lokalizacyjna SaaS $50-200/miesiąc Średni
TranslateBot + GPT-4o-mini ~$0,05 (jednorazowo) Minuty
TranslateBot + DeepL Free $0 (do 500 tys. znaków/miesiąc) Minuty
TranslateBot + Claude/GPT-4o ~$0,30 (jednorazowo) Minuty

Liczby zmieniają się w zależności od liczby ciągów i języków docelowych, ale różnica rzędu wielkości jest stała. Dla bieżącej konserwacji (tłumaczenie 20-50 nowych ciągów dodawanych w każdym sprincie) koszt AI jest zasadniczo zerowy.

Najlepsze praktyki

Zacznij od --dry-run. Przed pierwszym prawdziwym uruchomieniem tłumaczenia podejrzyj, co się stanie. To buduje pewność i wyłapuje problemy konfiguracyjne na wczesnym etapie.

Zatwierdź pliki .po przed tłumaczeniem. Jeśli coś pójdzie nie tak, git checkout natychmiast przywraca czysty stan.

Napisz TRANSLATING.md od pierwszego dnia. Nawet krótki plik z opisem projektu i kilkoma regułami terminologicznymi mierzalnie poprawia jakość tłumaczenia.

Dodaj check_translations do CI. Ten pojedynczy krok zapobiega najczęstszemu trybowi awarii i18n: ciągom oznaczonym do tłumaczenia, ale nigdy faktycznie nieprzetłumaczonym.

Używaj gpt-4o-mini lub DeepL dla efektywności kosztowej. Zachowaj modele premium jak GPT-4o lub Claude dla projektów, gdzie precyzja ma znaczenie, takich jak teksty marketingowe, prawne lub specjalistyczna terminologia domenowa.

Przeglądaj krytyczne ciągi. Tłumaczenia AI są wystarczająco dobre dla większości tekstu UI, ale poproś native speakera o przegląd wszystkiego, co jest prawnie wiążące, krytyczne dla bezpieczeństwa lub skierowane do klienta w kontekście wysokiego ryzyka.

Od godzin do sekund

Framework i18n Django doskonale radzi sobie z wyodrębnianiem i kompilowaniem tłumaczeń. Luka zawsze była w samym kroku tłumaczenia, żmudnej i podatnej na błędy pracy polegającej na wypełnianiu setek wartości msgstr w wielu językach.

TranslateBot zamyka tę lukę. Zainstaluj go, skieruj na dostawcę AI i uruchom jedną komendę. Nowe ciągi zostają przetłumaczone. Istniejące ciągi pozostają nietknięte. Placeholdery pozostają nienaruszone. CI wyłapuje wszystko, co się wymknie.

Twoje pliki .po przestają być uciążliwym obowiązkiem i stają się po prostu kolejną częścią buildu.

pip install translatebot-django

Zacznij na translatebot.dev.

Przestań ręcznie edytować pliki .po

TranslateBot automatyzuje tłumaczenia Django za pomocą AI. Jedno polecenie, wszystkie języki, grosze za tłumaczenie.