Python-/PyGObject-Programme lokalisieren

Veröffentlicht am

Wie ich kürzlich bereits angekündigt habe, habe ich im Zuge meines Projektes “Humble Savegame Backup” wieder einiges gelernt, was ich gerne auch mit euch teilen möchte.

Als erstes soll dieser Artikel kurz erklären, wie in Python geschriebene Programme übersetzt bzw. übersetzbar gemacht werden können. Speziell soll es dabei um Programme gehen, die mit Hilfe von PyGObject (bzw. PyGTK) GTK-Oberflächen darstellen. Gerade beim Übersetzen der Texte, die in der von Glade erstellten Datei enthalten waren, hatte ich zunächst arge Probleme…

Benötigte Tools

Für die Lokalisierung wird das gettext-Paket benötigt:

sudo apt-get install gettext

Zudem braucht man für die die Lokalisierung der Glade-Files noch ein weiteres Tool:

sudo apt-get install intltool

Ein einfaches Python-Beispiel

Zunächst ein (sehr) einfaches Python Beispiel namens hello.py – ohne GTK-Oberfläche:

#!/usr/bin/python
print '------------'
print 'Hello World!'
print '------------'

Ein solches Programm übersetzbar zu machen, ist wirklich sehr einfach. Viele werden die Vorgehensweise kennen und im Netz findet man ja auch wirklich reichlich Informations-Material dazu. Der Vollständigkeit halber möchte ich die notwendigen Schritte aber erklären.

Schritt 1 – gettext einbinden und anwenden

Zunächst muss gettext importiert und die Lokalisierungs-Funktion “installiert” werden. Dazu wird das Skript folgendermaßen erweitert:

#!/usr/bin/python
import os
import gettext
lang = os.environ.get('LANGUAGE', 'en')
trans = gettext.translation('hello', 'locale', [lang])
trans.install()
print '------------'
print 'Hello World!'
print '------------'

Schritt 2 – Kennzeichnung der Texte

Nun müssen alle Texte, die lokalisiert werden sollen, “gekennzeichnet” werden. Ich habe das Wort “gekennzeichnet” in Anführungszeichen gesetzt, weil es tatsächlich mehr als eine reine Kennzeichnung ist (Näheres dazu folgt gleich…).

Da nur die “Hello World!”-Ausgabe übersetzt werden soll, ist auch nur diese zu ändern:

print _('Hello World!')

Wie ihr seht ist nun der Text in Klammern eingeschlossen und der öffnenden Klammer ein Unterstrich vorangestellt. Das hat zur folge, dass der Text als Parameter an eine Funktion namens _ gegeben wird. Und der übersetzte Text wird dann zurückgegeben. Dafür ist aber erst noch etwas zu tun…

Schritt 3 – Texte extrahieren

Mit dem Tool xgettext können nun die Texte extrahiert werden:

xgettext --from-code=UTF-8 --language=Python --keyword=_ --output=hello.pot hello.py

Dieser Aufruf erzeugt eine Datei namens hello.pot, in der der “Hello World!”-Text wie folgt auftaucht:

#: hello.py:8
msgid "Hello World!"
msgstr ""

Die Datei enthält außerdem einige Angaben im Kopf, die ihr entsprechend anpassen könnt/solltet.

Schritt 4 – Übersetzung erzeugen

Nun erzeugen wir eine Quelldatei für die Übersetzung – hier beispielsweise für die deutsche:

msginit --input=hello.pot --locale=de

Durch diesen Aufruf (bei dem ihr nach eurer Mailadresse gefragt werdet) wird eine Datei de.po erstellt, die der hello.pot recht ähnlich sieht. In dieser Datei nimmt man nun die Übersetzung vor. Dazu füllt man den msgstr mit dem Text in der Zielsprache. Das Ergebnis sieht so aus:

#: hello.py:8
msgid "Hello World!"
msgstr "Hallo Welt!"

Wenn der Text nicht übersetzt werden soll (also in msgid der richtige Text für die Sprache enthalten ist), dann kann man msgstr auch einfach leer lassen. Ist man mit der Übersetzung fertig, muss die Quelldatei kompiliert werden:

msgfmt --output hello.mo de.po

So erhält man eine Datei namens hello.mo, die nun noch an die richtige Stelle verschoben werden muss, und zwar in das Unterverzeichnis locale/de/LC_MESSAGES. Den Namen locale haben wir in unserem Programm beim Aufruf von gettext.translation vorgegeben. Der Name des Unterverzeichnisses de steht dann für die Locale ist (je nach Sprache). Außerdem muss die Datei hello.mo heißen, weil wir auch das beim Aufruf von gettext.translation so angegeben haben (ohne die Endung .mo).

Schritt 5 – Testen

Nun kann die Übersetzung getestet werden. Dazu muss vor dem Aufruf des Programms einfach die Umgebungsvariable LANGUAGE umgesetzt werden, z.B. so:

LANGUAGE=es ./hello.py

Das Programm wird mit einem Fehler beendet, falls keine Übersetzung für die angegebene Sprache existiert. Für dieses Beispiel müsstet ihr also erst einmal noch eine Übersetzung für es (spanisch) erzeugen (siehe Schritt 4).

Ein Beispiel mit GTK-Builder

Das zweite Beispiel hat nun eine kleine GTK-Oberfläche. Dazu haben wir neben dem Python-Programm (der Name sei wieder hello.py) noch eine (z.B. mit Glade) erstellte XML-Datei, die die GTK-Oberfläche beschreibt (nennen wir sie hello.glade). Hier der Inhalt von hello.py, der im Gegensatz zum einfachen Beispiel oben nun um ein paar Zeilen für die Anzeige des GTK-Fensters erweitert wurde:

#!/usr/bin/python
import os
import gettext
from gi.repository import Gtk
lang = os.environ.get('LANGUAGE', 'en')
trans = gettext.translation('hello', 'locale', [lang])
trans.install()
print '------------'
print _('Hello World!')
print '------------'
b = Gtk.Builder()
b.add_from_file('hello.glade')
w = b.get_object('window1')
w.show()
Gtk.main()

Schritt 1 und 2

… überspringe ich hier. Wie ihr seht, sind diese Punkte schon im Code umgesetzt.

Schritt 3

Um die Texte aus der Glade-Datei nun auch wie oben beschrieben übersetzen zu können, muss man einen kleinen Umweg gehen und erst einmal die Texte in ein Zwischenformat extrahieren:

intltool-extract --type=gettext/glade hello.glade

Daraus entsteht eine Datei namens hello.glade.h, die die Texte enthält. Diese Datei benötigen wird eigentlich nur temporär. Sie kann also nach dem kommenden Schritt wieder gelöscht werden.

Nun kann man die Texte in eine .pot-Datei übernehmen. Dazu wird der Aufruf aus dem “einfachen Schritt 3″ (s.o.) etwas erweitert, damit sowohl die Texte aus der Python-Datei, als auch die Texte aus der hello.glade.h gezogen werden:

xgettext --from-code=UTF-8 --language=Python --keyword=_ --keyword=N_ --output=hello.pot hello.py hello.glade.h

Mit der .pot-Datei kann nun wie oben schon erklärt fortgesetzt werden (ab Schritt 4).

Schritt 4 und 5

Siehe einfaches Beispiel…

Schritt 6

Damit die Übersetzungen nun auch vom GTK-Builder gezogen werden, ist noch eine kleine Anpassung des Quellcodes notwendig. Hier der vervollständigte Code:

#!/usr/bin/python
import os
import gettext
import locale
from gi.repository import Gtk
lang = os.environ.get('LANGUAGE', 'en')
locale.bindtextdomain('hello', 'locale')
trans = gettext.translation('hello', 'locale', [lang])
trans.install()
print '------------'
print _('Hello World!')
print '------------'
b = Gtk.Builder()
b.set_translation_domain('hello')
b.add_from_file('hello.glade')
w = b.get_object('window1')
w.show()
Gtk.main()

Hinzugekommen ist das import locale, das local.bindtextdomain(...) und das b.set_translation_domain(...). Bei den beiden Aufrufen ist hello wieder die Kennung des Programms und locale das Verzeichnis mit den Übersetzungen – wie bei gettext.translation(...).

Weiterführendes

Wer sich intensiver mit diesem Thema beschäftigen will sollte die Online-Dokumentation zu gettext lesen. Besonders interessant dürfte das Kapitel 7 sein, das sich mit der Aktualisierung bestehender Sprachdateien beschäftigt – denn auf dieses “Problem” wird man zwangsläufig stoßen…


Dieser Artikel wurde in der/den Kategorie(n) Planet-U, Programmierung und Skripting veröffentlicht und mit den Tags , , versehen.

4 Kommentare zu Python-/PyGObject-Programme lokalisieren

  1. Kommentar von Andi
    4. März 2012, 15:20 Uhr.

    Wie funktioniert das kennzeichnen bei Python 3? Da sind die Klammern bei print() sowieso erforderlich.

    • Kommentar von Gerald
      4. März 2012, 16:26 Uhr.

      Ich würde vermuten, dass das da gleichermaßen läuft. Aber ich kann dir das nicht verlässlich sagen, sorry.

      EDIT: mit dem print hat das ja letztendlich nichts zu tun. Man “registriert” ja praktisch eine Funktion mit dem Namen _ (Unterstrich). Also denke ich schon, dass das weiterhin so läuft…

  2. Kommentar von dAnjou
    4. März 2012, 16:09 Uhr.

    Herzlichen Dank! Ich wollte mich damit auch schon beschäftigen, schreckte aber immer wieder vor der Doku zurück.

    • Kommentar von Gerald
      4. März 2012, 16:25 Uhr.

      … und dir vielen Dank für dein nettes Feedback!

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>