Romani ite domum
| Anke (encarsia) | Also available in: Deutsch
Contents
Localization with gettext and locale
Glade
Strings in widgets are by default configurated as translatable so there are no preparations required. GetText directly provercesses Glade project files.
Python
Translatable strings
Approved translatable strings are recognized by xgettext
by brackets with a leading underscore:
_ = gettext.gettext translatable_string = _("translate me")
configure (bind)textdomain
Now name and location of the MO files have to be configured in the source code:
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
has to be called before loading Glade files.
GetText
POT
POT is the abbrevation for Portable Object Template. This file contains all original translatable strings. After generating an empty POT file, xgettext
is executed for all source files containing translatable strings:
$ xgettext --options -o output.pot sourcefile.ext
The identified strings are added to the POT file.
#: sourcefile.ext:line number msgid "translatable string" msgstr ""
The file number reference comment can be avoided by passting the option --no-location
.
In this article's example it is required to run xgettext once for the Glade file and once for the Python source code; the -j
(--join-existing
) option adds new found strings to an existing file:
$ 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
PO
Translated strings are stored in a PO file per language. A new translation ist invoked by
$ msginit --input=source.pot --locale=xx # xx=language code
that generates a file after the pattern xx.po (p.e. de.po). This file can be edited in any text editor or dedicated tools such like PoEdit. A German localization for example is created by the command
$ msginit --input=TUT.pot --locale=de
If the POT file is altered the PO files are updated with the new strings by executing msgmerge
:
$ msgmerge lang.po template.pot > new_lang.po
MO
MO files are (machine readable) binary files and mandatory for gettext to work. Localization files are located below the bindtextdomain following the file structure path/to/bindtextdomain)/locale/language code/LC_MESSAGES/appname.po
.
In the example the bindtextdomain is created in the local directory, the generated de.po translation text file then transformed into the corresponding MO file:
$ msgfmt --output locale/de/LC_MESSAGES/TUT.mo de.po
Tipps
xgettext options
--no-location
-
Oppress writing line number(s) and file name as comment
--omit-header
-
Avoid overwriting header information
Remove obsolete strings
Strings that are removed from the template remain in the translation files. You can get rid of these by executing this command:
$ msgattrib --set-obsolete --ignore-file=PRJ.pot -o xx.po xx.po
Listings
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>
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()
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 ""
Comments
Comments powered by Disqus