Как привязать текстовый домен к локальной папке для gettext под GTK3
С gettext
Вы можете использовать стандартный системный языковой каталог по умолчанию или указать его самостоятельно, используя bindtextdomain
, Это полезно при запуске программы непосредственно из источника, когда скомпилированные файлы перевода.mo недоступны в расположении системы по умолчанию.
В Python вы бы сделали это:
import gettext
from gettext import gettext as _
gettext.bindtextdomain('nautilus-image-manipulator', '/path/to/mo/folder')
gettext.textdomain('nautilus-image-manipulator')
где /path/to/mo/folder
содержит знакомое fr/LC_MESSAGES/nautilus-image-manipulator.mo
состав. Звонит вот так:
print _("Delete this profile")
верните правильно переведенную строку из локальных файлов.mo, большое спасибо.
В GTK+2/pygtk существовал gtk.glade.bindtextdomain
, но мне интересно, есть ли какой-нибудь эквивалент в GTK+3/PyGObject.
Чтобы дать вам конкретный пример, вот как Nautilus Image Manipulator, пользовательский интерфейс которого создается из его файла Glade:
from gi.repository import Gtk
builder = Gtk.Builder()
builder.set_translation_domain('nautilus-image-manipulator')
builder.add_from_file(ui_filename)
return builder
Части пользовательского интерфейса, которые не построены из файла Glade (т.е. установлены из кода), отображаются правильно переведенными, но строки из файла Glade по-прежнему отображаются на английском языке.
Мне кажется, что я пропускаю звонок в какой-то builder.bind_text_domain('nautilus-image-manipulator', '/path/to/mo/folder')
до звонка builder.set_translation_domain
... Есть идеи, как это сделать?
3 ответа
В PyGtk вы также можете использовать Gtk.Builder. В соответствии с документацией PyGtk Gtk.Builder:
http://developer.gnome.org/pygtk/stable/class-gtkbuilder.html
Домен перевода, используемый при переводе значений свойств, которые были помечены как переводимые в описаниях интерфейса. Если доменом перевода является None, GtkBuilder использует gettext(), в противном случае dgettext(). Значение по умолчанию: Нет
То есть Gtk.Builder использует dgettext () из "библиотеки C". Проблема в том, что модуль gettext Python, функция bindtextdomain (), по какой-то неизвестной мне причине не устанавливает "библиотеку C". Опция заключается в использовании модуля языкового стандарта, который также предоставляет этот интерфейс. Из документации модуля языка Python:
http://docs.python.org/library/locale
Модуль locale предоставляет интерфейс gettext библиотеки C в системах, которые предоставляют этот интерфейс. Он состоит из функций gettext(), dgettext(), dcgettext(), textdomain(), bindtextdomain() и bind_textdomain_codeset(). Они аналогичны тем же функциям в модуле gettext, но используют двоичный формат библиотеки C для каталогов сообщений и алгоритмы поиска библиотеки C для поиска каталогов сообщений.
Приложения Python обычно не должны вызывать эти функции и должны использовать вместо них gettext. Известным исключением из этого правила являются приложения, которые связываются с дополнительными библиотеками C, которые внутренне вызывают gettext () или dcgettext(). Для этих приложений может потребоваться привязка текстового домена, чтобы библиотеки могли правильно найти свои каталоги сообщений.
Что, это текущий случай. Что за хак:S
Это будет сделано, файл test.py:
from gi.repository import Gtk
from os.path import abspath, dirname, join
import gettext
import locale
APP = 'myapp'
WHERE_AM_I = abspath(dirname(__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()
Мой файл Glade 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>
Не забудьте создать mo в mo/LANG/LC_MESSAGES/myapp.mo на основе.po, извлеченного с помощью:
xgettext --keyword=translatable --sort-output -o en.po test.glade
На что это похоже:
С уважением
Ну а после того, как щедрость так с треском провалилась, чтобы получить ответ от Mac OS X, мне пришлось провести собственное исследование. Вот фрагмент, который я использую:
import locale, ctypes, sys, os
import gettext
# setup textdomain and install _() for strings from python
gettext.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('')
Позже, когда у вас есть Gtk.Builder, установите домен:
builder.set_translation_domain('domain')
Это будет работать только если библиотека gettext libintl
находится в пути к библиотеке, в противном случае завершится неудачно. Для работы трансляций вам нужно будет установить gettext в качестве зависимости.
Решение для активации перевода gettext в Gtk / python под Windows - elib_intl.py. Файл легко найти в Google. Это позволяет переводить текст в коде и текст в интерфейсе поляны.
Вот код, используемый для следующей среды:
Windows 7 Python 2.7 Gtk 3+, загруженный: pygi-aio-3.10.2-win32_rev18-setup.exe
Он должен работать в любых окнах, а также для Python 3. elib_intl.py можно использовать с pyGtk (Gtk 2).
from gi.repository import Gtk, Gdk
import cairo
import locale #for multilanguage support
import gettext
import elib_intl
elib_intl.install("pdfbooklet", "share/locale")
Если вы используете Gtk 3, вы, вероятно, получите сообщение об ошибке: для строки 447:
libintl = cdll.intl
Эта ошибка указывает: модуль не найден. Причина в том, что в Gtk3 имя dll было изменено. Это больше не intl.dll. В описанной установке Pygi имя: libintl-8. Вы должны заменить строку, которая вызывает ошибку:
libintl = cdll.LoadLibrary("libintl-8.dll")
Вы можете найти полный рабочий пример здесь: pdfBooklet 2.4.0(Предупреждение: еще не в строке, когда я пишу)
спасибо Дитеру Верфайли, написавшему elib_intl