Translating python gtk builder files

Translating python gtk builder files

I was toying around with creating a desktop GUI interface. And because I use Gnome and like Python, I start prototyping with PyGobjects. Apart from the C style interface I like working with PyGobjects.

One of the issues I run into, was the translation of the GTK Builder XML files.

I wanted to use getttext for translations and this works very well with the standard gettext library for Python. Only I could get translation partially to work with the GTK builder files.

When you use GTK builder for generating te interface, the text in the builder XML file are translated with the C gettext library. You can make the C gettext library work with your translations, if you set the locale translations:

import locale
locale.bindtextdomain("Application domain name" , "Path to application locale" )
locale.textdomain("Application domain name")
locale.setlocale(locale.LC_ALL, 'nl_NL.utf8')

The only problem with the locale solution is that you need to have the locale you want to translate installed on your computer. For python gettext this is not required, you can for example translate to nl_NL with with your application locale without installing the nl_NL locale on your computer. So if someone now how to make GTK builder use your application locale without installing the locale on your computer, i would like to here this.

To set a Python gettext translation on the GTK builder object was a bit tidies. So I made a little extension on the GTK builder, that will also read the XML and try's to find all the translatable GTK objects and will automatically apply the Python gettext for it:

# Gtk Builder implementation.
import os
import logging
import xml.etree.ElementTree as ET

from gi.repository import Gtk

logger = logging.getLogger(__name__)


class GtkBuilder(Gtk.Builder):

    def __init__(self, filename):
        super().__init__()

        tree = ET.parse(glade_file)
        root = tree.getroot()
        self.recursive_xml_translate(root)

    def recursive_xml_translate(self, node, grand_parent=None):
        """
        Custom translation with Glade/Builder does not work when locale is not installed.
        Reset every label in Glade file using gettext
        """
        def func_not_found(value):
            logger.warning('could not translate: {}'.format(value))

        parent_id = node.attrib.get('id')

        for child in node:
            if len(child):
                self.recursive_xml_translate(child, node)

            if not child.attrib.get('translatable') == 'yes':
                continue

            # translate combo box/liststore
            if child.tag == 'item':
                obj = self.get_object(grand_parent.attrib.get('id'))
                liststore = obj.get_model()
                for row_index, row in enumerate(liststore):
                    for value_index, value in enumerate(row):
                        if value == child.text:
                            try:
                                liststore[row_index][value_index] = str(_(value))
                            except Exception as e:
                                logger.exception(e)

            # translate property value
            if child.tag == 'property' and parent_id and child.attrib.get('name'):
                name = child.attrib.get('name')
                obj = self.get_object(parent_id)
                func = getattr(obj, 'set_{}'.format(name), func_not_found)
                logger.debug('Translate Glade object ({}): set_{}({})'.format(
                    parent_id, 
                    name, 
                    child.text
                ))
                func(_(child.text))

For getting all your translations for you project (GTK and Builder XML files), you can use these tools (xgettext, msgcat) and commands:

find <app> -iname "*.py" | xargs xgettext --from-code=UTF-8 --output=locale/<app>-python.pot
find data/glade -iname "*.glade" | xargs xgettext --from-code=UTF-8 --output=locale/<app>-glade.pot -L Glade
msgcat --use-first locale/<app>-python.pot locale/<app>-glade.pot > locale/<app>.pot
rm locale/<app>-python.pot locale/<app>-glade.pot

This maybe not an elegant solution, but its the easiest solution without tediously setting all the translations or alter much in the rest of the application.

Previous Post Meet Magento 2017 Next Post PHPStan static code analyzer for Magento 2

There are no comments yet.

Leave a Comment

You may format you comment with Markdown.