How to bind a text domain to a local folder for gettext under GTK3 How to bind a text domain to a local folder for gettext under GTK3 python python

How to bind a text domain to a local folder for gettext under GTK3


In PyGtk you can use Gtk.Builder too. Accordingly to the PyGtk Gtk.Builder documentation:

http://developer.gnome.org/pygtk/stable/class-gtkbuilder.html#properties-gtkbuilder

The translation domain used when translating property values that have been marked as translatable in interface descriptions. If the translation domain is None, GtkBuilder uses gettext(), otherwise dgettext(). Default value: None

That is, Gtk.Builder uses dgettext() from "C library". The problem is that Python's gettext module, function bindtextdomain(), for some reason unknown to me, don't set the "C library". The option is to use the locale module that also exposes that interface. From the Python locale module documentation:

http://docs.python.org/library/locale#access-to-message-catalogs

The locale module exposes the C library’s gettext interface on systems that provide this interface. It consists of the functions gettext(), dgettext(), dcgettext(), textdomain(), bindtextdomain(), and bind_textdomain_codeset(). These are similar to the same functions in the gettext module, but use the C library’s binary format for message catalogs, and the C library’s search algorithms for locating message catalogs.

Python applications should normally find no need to invoke these functions, and should use gettext instead. A known exception to this rule are applications that link with additional C libraries which internally invoke gettext() or dcgettext(). For these applications, it may be necessary to bind the text domain, so that the libraries can properly locate their message catalogs.

Which, is the current case. What a hack :S

This will do it, file test.py:

from gi.repository import Gtkfrom os.path import abspath, dirname, join, realpathimport gettextimport localeAPP = 'myapp'WHERE_AM_I = abspath(dirname(realpath(__file__)))LOCALE_DIR = join(WHERE_AM_I, 'mo')locale.setlocale(locale.LC_ALL, '')locale.bindtextdomain(APP, LOCALE_DIR)gettext.bindtextdomain(APP, LOCALE_DIR)gettext.textdomain(APP)_ = gettext.gettextprint('Using locale directory: {}'.format(LOCALE_DIR))class MyApp(object):    def __init__(self):        # Build GUI        self.builder = Gtk.Builder()        self.glade_file = join(WHERE_AM_I, 'test.glade')        self.builder.set_translation_domain(APP)        self.builder.add_from_file(self.glade_file)        print(_('File'))        print(_('Edit'))        print(_('Find'))        print(_('View'))        print(_('Document'))        # Get objects        go = self.builder.get_object        self.window = go('window')        # Connect signals        self.builder.connect_signals(self)        # Everything is ready        self.window.show()    def main_quit(self, widget):        Gtk.main_quit()if __name__ == '__main__':    gui = MyApp()    Gtk.main()

My Glade file test.glade:

<?xml version="1.0" encoding="UTF-8"?><interface>  <!-- interface-requires gtk+ 3.0 -->  <object class="GtkWindow" id="window">    <property name="can_focus">False</property>    <property name="window_position">center-always</property>    <property name="default_width">400</property>    <signal name="destroy" handler="main_quit" swapped="no"/>    <child>      <object class="GtkBox" id="box1">        <property name="visible">True</property>        <property name="can_focus">False</property>        <property name="orientation">vertical</property>        <child>          <object class="GtkLabel" id="label1">            <property name="visible">True</property>            <property name="can_focus">False</property>            <property name="label" translatable="yes">File</property>          </object>          <packing>            <property name="expand">False</property>            <property name="fill">True</property>            <property name="position">0</property>          </packing>        </child>        <child>          <object class="GtkLabel" id="label2">            <property name="visible">True</property>            <property name="can_focus">False</property>            <property name="label" translatable="yes">Edit</property>          </object>          <packing>            <property name="expand">False</property>            <property name="fill">True</property>            <property name="position">1</property>          </packing>        </child>        <child>          <object class="GtkLabel" id="label3">            <property name="visible">True</property>            <property name="can_focus">False</property>            <property name="label" translatable="yes">Find</property>          </object>          <packing>            <property name="expand">False</property>            <property name="fill">True</property>            <property name="position">2</property>          </packing>        </child>        <child>          <object class="GtkLabel" id="label4">            <property name="visible">True</property>            <property name="can_focus">False</property>            <property name="label" translatable="yes">View</property>          </object>          <packing>            <property name="expand">False</property>            <property name="fill">True</property>            <property name="position">3</property>          </packing>        </child>        <child>          <object class="GtkLabel" id="label5">            <property name="visible">True</property>            <property name="can_focus">False</property>            <property name="label" translatable="yes">Document</property>          </object>          <packing>            <property name="expand">False</property>            <property name="fill">True</property>            <property name="position">4</property>          </packing>        </child>      </object>    </child>  </object></interface>

Remember to create the mo in mo/LANG/LC_MESSAGES/myapp.mo based on .po extracted with:

xgettext --keyword=translatable --sort-output -o en.po test.glade

What it looks like:

enter image description here

Kind regards


The solution to activate gettext translations in Gtk / python under Windows is elib_intl.pyIt is easy to find the file with Google. This allows translation of text in the code and text in a glade UI.

Here is the code used for the following environment :

Windows 7Python 2.7Gtk 3+ loaded by : pygi-aio-3.10.2-win32_rev18-setup.exe

It should work in any windows and also for Python 3. elib_intl.py can be used with pyGtk (Gtk 2).

from gi.repository import Gtk, Gdkimport cairoimport locale       #for multilanguage supportimport gettextimport elib_intlelib_intl.install("pdfbooklet", "share/locale")

If you are using Gtk 3, you will probably receive an error : for line 447 :

libintl = cdll.intl

This error indicates : module not found. The reason is that in Gtk3, the name of the dll has been changed. It is no longer intl.dll. In the described Pygi installation the name is : libintl-8. You must replace the line which provoques the error by :

libintl = cdll.LoadLibrary("libintl-8.dll")

You can find a full working example here : pdfBooklet 2.4.0(Warning : not yet in line when I write)

thanks to dieter Verfaillie who has written elib_intl


Well after the bounty failing so miserably to attract a mac os x answer, I had to do my own research. Here's the snippet I use:

import locale, ctypes, sys, osimport gettext# setup textdomain and install _() for strings from pythongettext.install('domain', '/path/to/locale/dir')try:    if hasattr(locale, 'bindtextdomain'):        libintl = locale    elif os.name == 'nt':        libintl = ctypes.cdll.LoadLibrary('libintl-8.dll')    elif sys.platform == 'darwin':        libintl = ctypes.cdll.LoadLibrary('libintl.dylib')    # setup the textdomain in gettext so Gtk3 can find it    libintl.bindtextdomain('domain', '/path/to/locale/dir')except (OSError, AttributeError):    # disable translations altogether for consistency    gettext.install('')

Later, when you have the Gtk.Builder, set the domain:

builder.set_translation_domain('domain')

This will only work if gettext's library libintl is in the library path, otherwise fail gracefully. For transaltions to work, you will need to install gettext as a dependency.