GTK3下如何将文本域绑定到本地文件夹以获取文本
Posted
技术标签:
【中文标题】GTK3下如何将文本域绑定到本地文件夹以获取文本【英文标题】:How to bind a text domain to a local folder for gettext under GTK3 【发布时间】:2012-04-23 01:45:16 【问题描述】:使用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;s UI 是如何从其 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 文件构建(即从代码设置)的部分 UI 显示正确翻译,但 Glade 文件中的字符串仍以英文显示。
在我看来,在调用builder.set_translation_domain
之前,我错过了对某种builder.bind_text_domain('nautilus-image-manipulator', '/path/to/mo/folder')
的调用...知道如何执行此操作吗?
【问题讨论】:
您是否尝试过通常的gettext.bindtextdomain()
?
【参考方案1】:
在 PyGtk 中你也可以使用 Gtk.Builder。根据 PyGtk Gtk.Builder 文档:
http://developer.gnome.org/pygtk/stable/class-gtkbuilder.html#properties-gtkbuilder
翻译属性值时使用的翻译域 在界面描述中被标记为可翻译。如果 翻译域为None,GtkBuilder使用gettext(),否则 dgettext()。默认值:无
也就是说,Gtk.Builder 使用“C 库”中的 dgettext()。问题是 Python 的 gettext 模块,函数 bindtextdomain(),出于某种我不知道的原因,没有设置“C 库”。选项是使用也公开该接口的 locale 模块。来自 Python 语言环境模块文档:
http://docs.python.org/library/locale#access-to-message-catalogs
语言环境模块在系统上公开 C 库的 gettext 接口 提供这个接口。它由函数 gettext() 组成, dgettext()、dcgettext()、textdomain()、bindtextdomain() 和 绑定文本域代码集()。这些与中的相同功能相似 gettext 模块,但使用 C 库的二进制格式的消息 目录,以及用于定位消息的 C 库的搜索算法 目录。
Python 应用程序通常不需要调用这些 函数,应该使用 gettext 代替。一个已知的例外 规则是与其他 C 库链接的应用程序 内部调用 gettext() 或 dcgettext()。对于这些应用程序,它 可能需要绑定文本域,以便库可以 正确定位他们的消息目录。
这是当前的情况。真是个黑客:S
这样就可以了,文件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()
我的 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/LANG/LC_MESSAGES/myapp.mo 中根据提取的 .po 创建 mo:
xgettext --keyword=translatable --sort-output -o en.po test.glade
它的样子:
亲切的问候
【讨论】:
谢谢,这很好用。但我想知道“locale.setlocale(locale.LC_ALL, '')” 行实际上是做什么的 - 我的应用程序即使在我删除它时也会被翻译......这个调用真的有必要吗? 我按照这里的建议添加了它:docs.python.org/2/library/locale.html#locale.setlocale“这会将所有类别的区域设置为用户的默认设置(通常在 LANG 环境变量中指定)。”这可能是在你晚上由于某种原因 LC_* 变量不同于我想的 LC_ALL 的情况下,或者在没有语言环境变量的情况下,但我不太确定。 我知道它已经过时了,但我现在正在面对它......这种方法似乎只适用于 Linux,因为 Windows 没有带有 gettext 的 C 库 @Zvika 如果我记得你在 Windows 中必须这样:github.com/carlos-jenkins/nested/blob/1.x/nested/… ...也许这可以将环境变量设置为 gettext 工作:github.com/carlos-jenkins/nested/blob/1.x/nested/… 它是否适用于 OS X?上次我检查时,locale.bindtextdomain
在这个平台上不存在...(见github.com/multani/sonata/issues/67)【参考方案2】:
Windows下在Gtk/python中激活gettext翻译的解决方案是elib_intl.py 用谷歌很容易找到文件。 这允许翻译代码中的文本和 glade UI 中的文本。
这是用于以下环境的代码:
Windows 7 蟒蛇 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 的节食者 Verfaillie
【讨论】:
【参考方案3】:在赏金如此悲惨地未能吸引 mac os x 答案之后,我不得不自己进行研究。这是我使用的 sn-p:
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 作为依赖项。
【讨论】:
以上是关于GTK3下如何将文本域绑定到本地文件夹以获取文本的主要内容,如果未能解决你的问题,请参考以下文章