Zum Inhalt

Tutorial

Diese Seite führt vom leeren Verzeichnis zu einem Programm, das auf Japanisch grüßt. Fünf Schritte, keine gettext-Erfahrung vorausgesetzt, und jeder Befehl wird mit der Ausgabe gezeigt, die er tatsächlich erzeugt — sodass du bei jedem Schritt weißt, ob du auf Kurs bist.

Du brauchst Python 3.14 oder neuer, denn t-strings sind neue Syntax in 3.14. Japanisch ist die Beispielsprache dieser Seite, aber nichts hängt von dieser Wahl ab. Für eine andere Sprache ersetzt du in Schritt 4 einfach ja — dieser Locale-Code ist das Einzige, was die Sprache benennt.

1. Installieren

python -m pip install "gettext-tstrings[babel]"

Das Extra [babel] bringt Babel mit, das Werkzeug, das in Schritt 3 deine Nachrichten in Katalogdateien einsammelt. Es ist ein Entwicklungswerkzeug: Produktionscode rendert allein mit der Standardbibliothek.

2. Eine Nachricht im Code markieren

Erstelle app.py:

from gettext_tstrings import tr

name = "Ada"
print(tr(t"Hello {name}"))

t"Hello {name}" sieht aus wie ein f-string, aber das Präfix t hält Text und Wert getrennt, statt sie an Ort und Stelle zu verschmelzen. Diese Trennung erlaubt es tr(), eine Übersetzung für den ganzen Satz Hello {name} nachzuschlagen und den Wert danach einzusetzen.

Führe es gleich aus:

$ python app.py
Hello Ada

Noch sind keine Übersetzungen installiert, also wird der Quelltext unverändert gerendert. Ein Programm mit dieser Bibliothek benötigt nie einen Katalog, um zu laufen — Englisch (oder was auch immer deine Quellsprache ist) ist der eingebaute Fallback.

3. Die Nachrichten extrahieren

Übersetzende arbeiten meist mit Katalogen statt mit Quellcode, also reist zwischen euch eine kleine Datei, ein Katalog. Der erste Schritt dorthin ist, jede markierte Nachricht aus dem Code einzusammeln.

Sag Babel, wo deine Nachrichten zu finden sind, indem du babel.cfg anlegst:

[gettext_tstrings: **.py]
encoding = utf-8

Extrahiere dann in eine Vorlagendatei (.pot):

$ mkdir -p locales
$ pybabel extract -F babel.cfg -c "Translators:" -o locales/messages.pot .
extracting messages from app.py (encoding="utf-8")
writing PO template file to locales/messages.pot

locales/messages.pot enthält jetzt einen Eintrag pro Nachricht:

#. gettext-tstrings
#: app.py:4
#, python-brace-format
msgid "Hello {name}"
msgstr ""

msgid ist der Schlüssel, den dein Code nachschlägt. Das leere msgstr ist der Platz für eine Übersetzung — aber nicht in dieser Datei: Eine .pot ist eine Vorlage, und der nächste Schritt kopiert sie einmal pro Sprache.

4. Übersetzen und kompilieren

Erzeuge den japanischen Katalog aus der Vorlage:

$ pybabel init -i locales/messages.pot -d locales -l ja
creating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot

Öffne locales/ja/LC_MESSAGES/messages.po und fülle das msgstr aus:

msgid "Hello {name}"
msgstr "こんにちは {name}"

Lass {name} genau so, wie es ist — über den Platzhalter findet der Wert seinen Platz im übersetzten Satz, und die Übersetzung darf ihn dorthin verschieben, wo die Zielsprache ihn braucht. In einem echten Projekt ist diese .po-Datei das, was du Übersetzenden übergibst oder auf eine Übersetzungsplattform hochlädst; das Format ist in beiden Fällen dasselbe.

Kataloge werden als Text bearbeitet, aber in binärer Form (.mo) geladen, also kompiliere:

$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo

Dieser Befehl ist zugleich ein Sicherheitsnetz. Hätte die Übersetzung den Platzhalter beschädigt — etwa {nome} statt {name} —, würde er sie nicht durchlassen:

$ pybabel compile -d locales
error: locales/ja/LC_MESSAGES/messages.po:24: translation does not match the
source placeholders: {name} is missing; {nome} is not in the source message
1 errors encountered.

Ein Vorbehalt, den man schon jetzt kennen sollte: Der Befehl meldet den Fehler und endet mit einem Exit-Status ungleich null, schreibt die .mo aber trotzdem. In einem echten Projekt muss die CI auf diesem Exit-Status stoppen — Im Produktivbetrieb richtet das ein.

5. Ausführen

Die Schritte 2–4 nutzten tr(), das nach einem Katalog sucht und keinen findet. Jetzt existiert einer: Lade ihn und binde ihn ein einziges Mal. Translator hält einen Katalog, damit die Aufrufstellen ihn nicht benennen müssen, und _ ist der konventionelle gettext-Name für das Ergebnis.

Richte app.py auf den kompilierten Katalog. Klick die Marker an, um zu sehen, was jede Zeile tut:

import gettext

from gettext_tstrings import Translator

_ = Translator(gettext.translation("messages", localedir="locales", languages=["ja"]))  # (1)!

name = "Ada"
print(_(t"Hello {name}"))  # (2)!
  1. Die Standardbibliothek lädt die kompilierte .mo, und Translator bindet sie an ein aufrufbares Objekt. _ ist der konventionelle gettext-Name für „übersetze das“ — kurz, weil er an jedem für Nutzer sichtbaren String auftaucht. Er leistet dieselbe Übersetzung wie tr, gebunden an einen Katalog.
  2. Beim Aufruf: Der Text der t-string wird zum Suchschlüssel Hello {name}, der Katalog antwortet こんにちは {name}, die Antwort wird gegen die Quellplatzhalter geprüft, und erst dann wird der Wert eingesetzt.
$ python app.py
こんにちは Ada

Das ist die ganze Schleife, und es lohnt sich, sie als ein Bild zu sehen:

flowchart LR
  mark["1–2 markieren<br>t-strings im Code"] --> extract["3 extrahieren<br>messages.pot"]
  extract --> translate["4 übersetzen<br>ja/…/messages.po"]
  translate --> compile["4 kompilieren<br>ja/…/messages.mo"]
  compile --> run["5 ausführen<br>こんにちは Ada"]

Markieren → extrahieren → übersetzen → kompilieren → ausführen. Alles Weitere auf dieser Website verfeinert einen dieser fünf Schritte.

Wie es weitergeht

  • Warum t-strings — wovor dich dieses Design schützt, verglichen mit %(name)s, .format() und $-Strings.
  • Anleitung — Pluralformen, Sprache pro Anfrage, verzögerte Strings und was zur Laufzeit geschieht, wenn ein Katalog doch fehlerhaft ist.
  • Im Produktivbetrieb — dieselbe Schleife, wie ein Team sie Woche für Woche betreibt: Kataloge aktualisieren, CI-Schranken und Übersetzungsplattformen.
  • Extraktion — die vollständige pybabel-Referenz: eigene Funktionsnamen, strikter CI-Modus und die Prüfungen, die deine Kataloge absichern.
  • Migration — falls das Projekt, in dem du das eigentlich tun willst, schon gettext-Kataloge hat.
  • Für Übersetzende — die eine Seite für alle, die diese msgstr-Zeilen ausfüllen.