Romani ite domum
| Anke (encarsia) | Auch verfügbar in: English
Inhalt
Lokalisation mit gettext und locale
Glade
Strings von Labels oder Menüs sind standardmäßig als übersetzbar konfiguriert (Checkbox unter "Beschriftung"), insofern muss hier nichts weiter beachtet werden. Glade-Projektdateien werden direkt von GetText verarbeitet.
Python
Übersetzbare Strings
Zur Übersetzung freigegebene Strings werden durch eine Einklammerung mit vorausgehendem Unterstrich markiert und beim Aufruf von xgettext
erkannt:
_ = gettext.gettext translatable_string = _("translate me")
(bind)textdomain einrichten
Nun muss man Python noch zeigen, unter welchem Namen und Pfad die MO-Dateien (siehe unten) zu finden sind:
locale.bindtextdomain(appname, locales_dir) locale.textdomain(locales_dir) gettext.bindtextdomain(appname, locales_dir) gettext.textdomain(appname) builder.set_translation_domain(appname)
set_translation_domain
muss vor dem Laden der Glade-Datei(en) aufgerufen werden.
GetText
POT
POT steht für Portable Object Template und ist dem Namen zufolge die Vorlage für Übersetzungen. Diese Datei enthält alle übersetzbaren Strings. Nachdem eine leere POT-Datei erstellt wurde, ruft man nun xgettext
nach folgendem Muster für alle Quelldateien auf:
$ xgettext --options -o output.pot sourcefile.ext
Die erkannten Strings werden nach dem Schema
#: sourcefile.ext:line number msgid "translatable string" msgstr ""
der angegebenen POT-Datei hinzugefügt. Die Markierung der Fundstelle(n) des Strings kann mit der Option --no-location
verhindert werden.
Für das Beispiel wird also je ein Aufruf für die Glade- und Python-Datei benötgt:
$ xgettext --sort-output --keyword=translatable --language=Glade -j -o 10_localization/TUT.pot 10_lokalisation.glade $ xgettext --language=Python -j -o 10_localization/TUT.pot 10_lokalisation.py
Mit der Option -j
(--join-existing
) wird eine bestehende Datei um zusätzliche Strings ergänzt und funktioniert deshalb sowohl bei der Initiierung (vorher einfach mit touch template.pot
die leere Datei erstellen) als auch bei erneutem Aufruf zum Aktualisieren neuer Strings.
PO
Die übersetzten Strings werden in jeweils einer PO-Datei gespeichert. Eine neue Übersetzung legt man mit
$ msginit --input=source.pot --locale=xx # xx=language code
an, das eine PO-Datei mit dem Namen xx.po (z.B. de.po) anlegt. Diese kann direkt im Texteditor oder mittels Tools wie PoEdit bearbeitet werden. Die deutschsprachige Lokalisation wird also angelegt mit
$ msginit --input=TUT.pot --locale=de
Wird die POT-Datei verändert, kann man die PO-Dateien mit msgmerge
abgleichen und anschließend die neuen Strings übesetzen:
$ msgmerge lang.po template.pot > new_lang.po
MO
MO-Dateien sind auf Maschinenlesbarkeit optimierte PO-Dateien und letztlich die, die vom Programm benutzt werden. Unterhalb der angegebenen bindtextdomain liegen die Lokalisationsdateien nach der Verzeichnisstruktur (path/to/bindtextdomain)/locale/language code/LC_MESSAGES/appname.po
Im Beispiel wird die bindtextdomain einfach im lokalen Verzeichnis angelegt, die erzeugte de.po wird mit msgfmt
in die MO-Datei überführt:
$ msgfmt --output locale/de/LC_MESSAGES/TUT.mo de.po
Tipps
xgettext-Optionen
--no-location
-
Ausgabe der Zeilennummer(n) und Datei (als Kommentar) des Strings verhindern
--omit-header
-
Überschreiben der Header-Informationen verhindern
--sort-output
-
Alphabetische Sortierung der Strings
Obsolete Strings entfernen
Strings, die aus der POT entfernt werden, bleiben in den Übersetzungen erhalten. Dies lässt sich durch den Aufruf von
$ msgattrib --set-obsolete --ignore-file=PRJ.pot -o xx.po xx.po
beheben.
Listings
Python
#!/usr/bin/python # -*- coding: utf-8 -*- import gettext import locale import os import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk _ = gettext.gettext class Handler: def on_window_destroy(self, *args): Gtk.main_quit() class Example: def __init__(self): #setting up localization locales_dir = os.path.join(os.getcwd(), "10_localization", "locale", ) appname = "TUT" #required for showing Glade file translations locale.bindtextdomain(appname, locales_dir) locale.textdomain(locales_dir) #required for code translations gettext.bindtextdomain(appname, locales_dir) gettext.textdomain(appname) self.builder = Gtk.Builder() self.builder.set_translation_domain(appname) self.builder.add_from_file("10_lokalisation.glade") self.builder.connect_signals(Handler()) #translatable strings print(_("It's a trap!")) print(_("""These aren't the droids you're looking for.\n""")) #not translatable nonono = """\"Jar Jar is the key to all of this.\"""" george = "...ruined it." print(nonono, george) window = self.builder.get_object("window") window.show_all() def main(self): Gtk.main() x = Example() x.main()
Glade
10_lokalisation.glade (Source)
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkApplicationWindow" id="window"> <property name="can_focus">False</property> <property name="title" translatable="yes">Localization example (English)</property> <property name="default_width">400</property> <property name="default_height">400</property> <signal name="destroy" handler="on_window_destroy" swapped="no"/> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkMenuBar"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_File</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-new</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-open</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-save</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-save-as</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkSeparatorMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-quit</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_Edit</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-cut</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-copy</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-paste</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-delete</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_View</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_Help</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-about</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkScrolledWindow"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <object class="GtkViewport"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Good morning. In less than an hour, aircraft from here will join others from around the world. And you will be launching the largest aerial battle in this history of mankind. Mankind -- that word should have new meaning for all of us today. We can't be consumed by our petty differences anymore. We will be united in our common interests. Perhaps its fate that today is the 4th of July, and you will once again be fighting for our freedom, not from tyranny, oppression, or persecution -- but from annihilation. We're fighting for our right to live, to exist. And should we win the day, the 4th of July will no longer be known as an American holiday, but as the day when the world declared in one voice: "We will not go quietly into the night! We will not vanish without a fight! We're going to live on! We're going to survive!" Today, we celebrate our Independence Day!</property> <property name="wrap">True</property> </object> </child> </object> </child> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> <child> <placeholder/> </child> </object> </interface>
POT
10_localization/TUT.pot (Source)
# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-11-28 13:06+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "Good morning. In less than an hour, aircraft from here will join others from " "around the world. And you will be launching the largest aerial battle in " "this history of mankind.\n" "\n" "Mankind -- that word should have new meaning for all of us today.\n" "\n" "We can't be consumed by our petty differences anymore.\n" "\n" "We will be united in our common interests.\n" "\n" "Perhaps its fate that today is the 4th of July, and you will once again be " "fighting for our freedom, not from tyranny, oppression, or persecution -- " "but from annihilation.\n" "\n" "We're fighting for our right to live, to exist.\n" "\n" "And should we win the day, the 4th of July will no longer be known as an " "American holiday, but as the day when the world declared in one voice:\n" "\n" "\"We will not go quietly into the night!\n" "We will not vanish without a fight!\n" "We're going to live on!\n" "We're going to survive!\"\n" "\n" "Today, we celebrate our Independence Day!" msgstr "" msgid "It's a trap!" msgstr "" msgid "Localization example (English)" msgstr "" msgid "These aren't the droids you're looking for.\n" msgstr "" msgid "_Edit" msgstr "" msgid "_File" msgstr "" msgid "_Help" msgstr "" msgid "_View" msgstr ""
Kommentare
Comments powered by Disqus