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¶
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:
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:
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:
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:
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:
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)!
- Die Standardbibliothek lädt die kompilierte
.mo, undTranslatorbindet 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 wietr, gebunden an einen Katalog. - 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.
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.