Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
216 views
in Technique[技术] by (71.8m points)

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

With gettext you can either use the default system-wide locale directory, or specify one yourself using bindtextdomain. This is useful when running a program directly from source when the compiled .mo translation files are not available in the system's default location.

In Python you would do this:

import gettext
from gettext import gettext as _
gettext.bindtextdomain('nautilus-image-manipulator', '/path/to/mo/folder')
gettext.textdomain('nautilus-image-manipulator')

where /path/to/mo/folder contains the familiar fr/LC_MESSAGES/nautilus-image-manipulator.mo structure. Calls like this:

print _("Delete this profile")

return the properly translated string from the local .mo files, thank you very much.

In GTK+2/pygtk, there existed gtk.glade.bindtextdomain, but I'm wondering if there is any equivalent in GTK+3/PyGObject.

To give you a specific example, this is how Nautilus Image Manipulator;s UI is created from its Glade file:

from gi.repository import Gtk
builder = Gtk.Builder()
builder.set_translation_domain('nautilus-image-manipulator')
builder.add_from_file(ui_filename)
return builder

Parts of the UI that are not built from the Glade file (i.e. set from code) show up properly translated, but the strings from the Glade file still show up in English.

It seems to me that I'm missing a call to some kind of builder.bind_text_domain('nautilus-image-manipulator', '/path/to/mo/folder') before the call to builder.set_translation_domain... Any idea how to perform this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 Gtk
from os.path import abspath, dirname, join, realpath
import gettext
import locale

APP = '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.gettext

print('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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...