Zurück zum Blog

So automatisieren Sie Ihren Django-Übersetzungs-Workflow

2026-07-11 9 Min. Lesezeit

Wer schon länger mit Djangos Übersetzungssytem gearbeitet hat, kennt den Ablauf. Sie markieren Strings mit _(), führen makemessages aus, öffnen eine .po-Datei und starren auf hunderte leere msgstr-Felder. Dann wiederholen Sie das Ganze für jede Sprache, die Ihre App unterstützt.

Der Prozess funktioniert. Er frisst aber auch Stunden, die in die Entwicklung neuer Features fließen könnten. Ein Projekt mit 200 übersetzbaren Strings in fünf Sprachen bedeutet 1.000 Übersetzungen, die verwaltet werden müssen. Ändern Sie ein Button-Label, müssen alle fünf .po-Dateien vor dem nächsten Deploy aktualisiert werden, sonst liefern Sie teilweise unübersetzte Seiten aus.

Der manuelle Workflow stößt irgendwann an seine Grenzen. Es gibt praktische Wege, ihn zu automatisieren, ohne die Kontrolle über die Qualität zu verlieren.

Der manuelle Workflow

Djangos eingebaute Übersetzungs-Pipeline besteht aus vier Schritten:

  1. Strings mit gettext oder {% trans %} in Code und Templates markieren
  2. makemessages ausführen, um sie in .po-Dateien zu extrahieren
  3. Die msgstr-Einträge in jeder .po-Datei übersetzen
  4. compilemessages ausführen, um die binären .mo-Dateien zu erzeugen, die Django liest

Schritte 1 und 2 gehen schnell. Schritt 4 ist ein einziger Befehl. Schritt 3 ist der Punkt, an dem alles langsam wird.

Wie Schritt 3 in der Praxis aussieht

Öffnen Sie locale/de/LC_MESSAGES/django.po in Ihrem Editor. Sie sehen etwas wie:

#: 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 ""

Für jeden Eintrag brauchen Sie eine korrekte Übersetzung, die alle Platzhalter-Variablen wie %(username)s oder {count} beibehält. Ein kaputter Platzhalter führt zur Laufzeit zu einem Formatierungsfehler in Django.

Bei fünf Sprachen und hundert neuen Strings verbringen Sie einen ganzen Nachmittag damit, zwischen Übersetzungsdiensten hin und her zu kopieren, Platzhalterformate zu korrigieren und zu hoffen, dass Sie nichts übersehen haben. Und im nächsten Sprint geht das Ganze von vorne los.

Wo der manuele Ansatz an seine Grenzen stößt

Kleine Projekte kommen mit manueller Übersetzung zurecht. Sobald ein Projekt bestimmte Schwellenwerte überschreitet, wird der Workflow zum Problem.

Wachsende Anzahl von Strings

Eine Django-App mit einem Dutzend Templates, ein paar Formularen und einigen E-Mail-Benachrichtigungen erreicht schnell 300 übersetzbare Strings. Multipliziert mit der Anzahl unterstützter Sprachen steigt die Gesamtzahl rasant. Ab einem bestimmten Punkt will niemand mehr die Person sein, die diese .po-Datei öffnet.

Veraltete Übersetzungen

Wenn Entwickler bestehende Strings ändern, markiert makemessages die alten Übersetzungen als fuzzy. Diese Fuzzy-Einträge müssen manuell überprüft werden, und sie häufen sich, weil sie niemandem auffallen, bis ein Benutzer meldet, dass auf einer deutschen Seite englischer Text erscheint. Der Fuzzy-Rückstau wächst still zwischen den Releases.

Platzhalter-Fehler

Djangos .po-Format verwendet verscheidene Platzhalter-Stile: %(name)s für Pythons %-Formatierung, {name} für .format() und f-Strings, und {{ name }} für Template-Variablen. Übersetzer (menschliche oder maschinelle) beschädigen diese manchmal, und die Fehler treten erst zur Laufzeit auf. Ein fehlerhafter %(username)s in einer deutschen Übersetzung kann eine View zum Absturz bringen, die auf Englisch einwandfrei funktioniert.

Blockierte Deployments

Wenn Übersetzungen ein manueller Schritt in Ihrer Deployment-Pipeline sind, werden sie zum Flaschenhals. Entweder warten Sie mit dem Deploy auf die Übersetzungen (langsam), oder Sie deployen mit fehlenden Übersetzungen (schlechte Benutzererfahrung). Keine der beiden Optionen ist gut, wenn Sie wöchentlich deployen.

Wie Automatisierung aussieht

Django-Übersetzungen zu automatisieren bedeutet, Schritt 3 (den manuellen Übersetzungsteil) durch einen programmatischen Prozess zu ersetzen, während alles andere gleich bleibt. Ihr makemessages- und compilemessages-Workflow ändert sich nicht. Sie hören einfach auf, .po-Dateien von Hand zu übersetzen.

Option 1: selbst skripten

Sie können ein Skript schreiben, das eine .po-Datei liest, unübersetzte Strings an eine Übersetzungs-API sendet und die Ergebnisse zurückschreibt. Die Basisversion ist überraschend kurz:

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()

Damit kommen Sie 80% ans Ziel. Die restlichen 20% werden kompliziert:

  • Pluralformen (msgid_plural und mehrere msgstr[n]-Einträge) brauchen Sonderbehandlung, weil verschiedene Sprachen unterschiedliche Pluralregeln haben
  • Kontext-Strings (msgctxt) sollten an die API übergeben werden, damit die Übersetzung zum Verwendungszweck passt
  • Sie müssen validieren, dass Platzhalter die Übersetzung unbeschadet überstanden haben
  • Rate-Limits und API-Fehler brauchen Retry-Logik
  • Das Skript muss die .po-Datei-Kodierung korrekt handhaben (UTF-8 mit bestimmten Header-Feldern)
  • Fuzzy-Einträge brauchen eine andere Behandlung als unübersetzte

All das selbst zu bauen ist machbar, kostet aber ein paar Tage Arbeit und laufende Wartung. Jedes Mal, wenn eine Übersetzungs-API ihr Verhalten oder ihre Preise ändert, müssen Sie Ihr Skript aktualiseren.

Option 2: eine Übersetzungsmanagement-Plattform nutzen

Dienste wie Crowdin, Transifex und Lokalise integrieren sich mit Versionskontrolle und bieten eine Web-Oberfläche für Übersetzer. Sie unterstützen .po-Dateien nativ, beherrschen Pluralformen und können automatisierte Workflows mit maschineller Übersetzung als ersten Durchgang einrichten.

Der Kompromiss ist Kosten und Komplexität. Diese Plattformen sind für Teams mit dedizierten Übersetzern gebaut, und die Preisgestaltung spiegelt das wider. Für einen Solo-Entwickler oder ein kleines Team, das einfach nur .po-Dateien übersetzt braucht, bringen sie mehr Infrastrucktur als nötig mit.

Option 3: spezialisierte Tools

Tools, die speziell für Djangos .po-Datei-Workflow gebaut sind, können die Übersetzung automatisieren und dabei die Eigenheiten des Formats berücksichtigen. Sie beherrschen Pluralformen, bewahren Platzhalter, verwalten Fuzzy-Einträge und integrieren sich in Ihre bestehende makemessages/compilemessages-Pipeline.

Der Vorteil ist, dass sie genau für diesen Anwendungsfall entwickelt wurden, sodass weniger Glue-Code geschrieben und gewartet werden muss. Der Nachteil ist, dass Sie Ihrem Übersetzungs-Workflow eine Abhängikeit hinzufügen.

Automatisierte Übersetzungen in CI/CD einrichten

Unabhängig davon, welches Tool Sie wählen, folgt die Integration in Ihre Deployment-Pipeline demselben Muster:

# .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

Der Workflow extrahiert neue Strings, übersetzt sie, kompiliert die Ergebnisse und committet die aktualisierten Dateien. Der git diff --staged --quiet-Check verhindert leere Commits, wenn sich nichts geändert hat.

Sie können das auch als Pre-Commit-Hook oder als geplanten Job laufen lassen. Die Kernidee bleibt gleich: Übersetzung passiert automtisch als Teil Ihres normalen Entwicklungsprozesses, nicht als separater manueller Schritt.

Übersetzungen validieren

Automatisierte Übersetzungen brauchen Valideirung. Selbst die besten KI-Modelle beschädigen gelegentlich Platzhalterformate oder erzeugen Übersetzungen, die nicht zum UI-Kontext passen.

Platzhalter-Validierung

Schreiben Sie einen Check, der Platzhalter zwischen msgid und msgstr vergleicht:

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

Führen Sie das in CI aus und lassen Sie den Build fehlschlagen, wenn Platzhalter defekt sind. Es dauert Sekunden und fängt die gefährlichste Klasse von Übersetzungsfehlern ab, bevor sie die Produktion erreichen.

Längenprüfungen

Manche Übersetzungen sind deutlich länger als der Quellstring. Deutscher Text ist typischerweise 20-30% länger als englischer, und das kann bei UI-Elementen mit fester Breite zu Problemen führen. Eine einfache Längenverhältnis-Prüfung kann Übersetzungen markieren, die möglicherweise Layout-Probleme verursachen.

Fuzzy-Einträge prüfen

Stellen Sie nach der automatisierten Übersetzung sicher, dass keine Einträge als fuzzy markiert bleiben. Fuzzy-Einträge bedeuten, dass Django die Übersetzung nicht verwenden wird und stattdessen auf Englisch zurückfällt. Ihre CI-Pipeline sollte Fuzzy-Einträge genauso als Fehlerbedingung behandeln wie einen fehlgeschlagnen Test.

Übersetzungen synchron halten

Der schwierigste Teil der Übersetzungswartung ist nicht die initiale Übersetzung. Es ist das Aktualisieren der Übersetzungen, während sich die Codebasis weiterentwickelt.

String-Änderungen

Wenn Sie einen bestehenden übersetzbaren String ändern, macht makemessages etwas Subtiles: Es sucht nach einem ähnlichen String in der .po-Datei und erstellt einen Fuzzy-Match. Die alte Übersetzung bleibt erhalten, wird aber als überprüfungsbedürftig markiert. Das ist nützlich, wenn ein menschlicher Übersetzer Änderungen durchsieht, bedeutet aber, dass automatisierte Workflows Fuzzy-Einträge gezielt behandeln müssen.

Ein praktischer Ansatz: Entfernen Sie das Fuzzy-Flag und übersetzen Sie den Eintrag komplett neu. Fuzzy-Matching spart menschlichen Übersetzern Arbeit, aber ein automatsiertes Tool kann den neuen String einfach direkt übersetzen. Das Ergebnis ist in der Regel besser, als zu versuchen, eine alte Übersetzung an einen neuen Quellstring anzupassen.

Neue Strings

Neue Strings erscheinen als unübersetzte Einträge nach dem Ausführen von makemessages. Ihr automatisierter Workflow sollte diese übersetzen und die Ergebnisse committen. Wenn Sie makemessages in CI ausführen, werden neue Strings beim Mergen automatisch übersetzt.

Entfernte Strings

makemessages --no-obsolete entfernt Einträge für Strings, die in Ihrem Code nicht mehr existieren. Das hält .po-Dateien sauber und verhindert, dass sich tote Übersetzungen über die Zeit ansammeln.

Was Sie vor der Automatisierung prüfen sollten

Bevor Sie automatisierte Übersetzung einrichten, überprüfen Sie ein paar Dinge:

  • Alle übersetzbaren Strings sind korrekt mit _() oder {% trans %} markiert. Führen Sie makemessages aus und prüfen Sie, ob Sie Strings übersehen haben.
  • Ihre LOCALE_PATHS-Einstellung ist korrekt und Ihre locale/-Verzeichnisstruktur ist vorhanden.
  • compilemessages läuft fehlerfrei auf Ihren bestehenden .po-Dateien.
  • Sie haben eine Möglichkeit, automatisierte Übersetzungen vor dem Go-Live zu prüfen, auch wenn es nur eine Staging-Umgebung ist, in der jemand die App in jeder Sprache durchklicken kann.

Übersetzungsautomatisierung funktioniert am besten, wenn der Rest Ihres i18n-Setups solide ist. Schritt 3 zu automatisieren hilft nicht, wenn Schritt 1 und 2 fehlerhaft sind.

Praktische Tipps

Einige Dinge, die ich bei der Arbeit mit automatisierten Django-Übersetzungen gelernt habe:

  • Führen Sie makemessages mit --no-obsolete aus, um .po-Dateien sauber zu halten. Tote Einträge verwirren sowohl menschliche Reviewer als auch automatisierte Tools.
  • Verwenden Sie msgctxt, wenn derselbe englische String in unterschiedlichen Kontexten verschiedene Übersetzungen braucht. "Post" kann entweder einen Blog-Beitrag oder die Aktion des Postens bedeuten, und ohne Kontext muss der Übersetzer (menschlich oder automatisiert) raten.
  • Testen Sie mit Sprachen, die sich strukturell vom Englischen unterscheiden. Die längeren Wörter des Deutschen und die Zeichensätze des Japanischen decken Layout-Fehler auf, die europäische Sprachen übersehen.
  • Pflegen Sie eine TRANSLATING.md-Datei mit projektspezifischer Terminologie und Tonalitätsrichtlinien. Wenn Ihr Projekt einen "Workspace" im UI als "Projekt" bezeichnet, dokumentieren Sie das. Einige automatisierte Übersetzungstools können diese Datei lesen und Ihre Präferenzen konsistent anwenden.
  • Committen Sie .po- und .mo-Dateien zusammen. Wenn Sie Messages in CI kompilieren, stellen Sie sicher, dass die .mo-Dateien in Ihrem Deploy-Artefakt enthalten sind. Django liest .mo-Dateien, nicht .po-Dateien.

Ansätze im Vergleich

Für einen Solo-Entwickler oder ein kleines Team mit einem Django-Projekt, das 3-5 Sprachen unterstützt:

Ein eigenes Skript funktioniert, wenn Sie es gerne warten und Ihre String-Anzahl unter 200 liegt. Darüber hinaus fangen die Sonderfälle bei Pluralformen, Platzhaltern und Fuzzy-Einträgen an, die eingesparte Zeit wieder aufzufressen.

Übersetzungsmanagement-Plattformen sind sinnvoll, wenn Sie ein Team von Übersetzern haben, das an mehreren Projekten arbeitet. Für eine einzelne Django-App sind sie in der Regel überdimensioniert.

Spezialisierte Tools treffen die goldene Mitte: Sie beherrschen die Eigenheiten von .po-Dateien, ohne dass Sie die Integration selbst bauen und warten müssen. Die monatlichen Kosten sind in der Regel geringer als die Entwicklungszeit für eine eigene Lösung.

Wählen Sie den Ansatz, der zu Ihrer Teamgröße und Ihrer Bereitschaft passt, Übersetzungsinfrastruktur zu pflegen. Wichtig ist, dass Übersetzungen kein manueller Flaschenhals mehr sind, sondern als Teil Ihres normalen Entwicklungszyklus stattfinden.

Schluss mit der manuellen Bearbeitung von .po-Dateien

TranslateBot automatisiert Django-Übersetzungen mit KI. Ein Befehl, alle Sprachen, Cent pro Übersetzung.