【发布时间】:2019-05-04 10:26:31
【问题描述】:
我正在开发一个 Python 程序,使用 PyGTK3 和 Glade 作为 UI。我想国际化 UI,不是基于系统中的语言环境,而是通过程序“安装”的语言,我希望能够“即时”更改 UI 语言,例如,通过选择菜单中的语言。我在 Windows 10 上,运行 Python 3.4。
我做了很多研究,尝试了各种各样的事情,并取得了一些进展。我能够安装一个 gettext for Windows 包(链接?),但它显然相当小。 xgettext 确实从我的 Python 源代码中提取 _("strings") 。但是,如果我尝试 xgettext -L Glade (根据https://askubuntu.com/questions/218432/how-extract-strings-from-a-ui-file-glade-with-gettext),则无法说明此版本是在没有外籍人士的情况下构建的。此外,似乎没有各种口味的 intltool 。没问题。根据本页 (http://www.learningpython.com/2006/12/03/translating-your-pythonpygtk-application) 上描述的 intltool-extract 的输出,我知道我可以手动从 .glade 文件中提取可翻译的字符串并将它们放入 C .h 格式的文件中:
char *s = N_("_File");
然后我可以在我的 xgettext 命令中添加该 .h 文件和 -kN_,以从 Python 源代码和 .glade UI 文件中获取带有字符串的 .pot 文件。我还可以编写一个 Python 脚本,从 .glade 源文件中提取各种字符串,并将它们与空字符串成对添加到 .pot 文件中。据我了解,这些只是将适当的字符串放入 .pot 文件的技术,因此可以翻译它们,但似乎我也可以手动创建 .pot 文件……
有了要翻译的字符串的 .pot 文件后,我就可以使用 msginit 命令创建 .po 文件了:
msginit --input=test.pot --locale=fr_FR (this creates a file fr.po)
然后我手动翻译(或让某人翻译)每个 .po 文本文件中的所有字符串,完成后,我创建 .mo 文件并将它们放入适当的目录结构中(都是子目录\po):
msgfmt --output-file=fr_FR\LC_MESSAGES\test.mo fr.po
到目前为止一切顺利。
在我的 Python 代码中,为了启用翻译,我提出了以下最小代码:
import gettext
APP_NAME = "test"
locale_path = os.path.realpath('.\po')
langs = ['fr_FR', 'en_US']
lang = gettext.translation(APP_NAME, locale_path, languages=langs, fallback = True)
_ = lang.gettext
builder = Gtk.Builder()
builder.set_translation_domain(APP_NAME)
builder.add_from_file("test.glade")
builder.connect_signals(Handler())
这非常适合翻译 Python 代码中的字符串,但 Glade 接口没有被翻译。这是我的基本问题。
在 Glade XML 中手动设置文本 我找到了这个页面:Translating python gtk builder files (http://martens.me/programming/translating-python-gtk-builder-files.html),它解释了如何创建 Gtk.Builder 的派生类,它扫描 .glade 文件的 XML 并手动调用 set_{}(在我的上下文中,它将是 set_label、set_text 或 set_title),每个参数为 _(child.text),以便可以进行翻译。我对他的代码做了一些更改,因为在扫描 XML 之前对象没有加载到 Builder 中,所以我在解析树之前加载了 .glade 文件,如下所示:
class GtkBuilder(Gtk.Builder):
def __init__(self, glade_file, APP_NAME):
super().__init__()
self.set_translation_domain(APP_NAME)
self.add_from_file(glade_file)
tree = ET.parse(glade_file)
root = tree.getroot()
self.recursive_xml_translate(root)
并且翻译发生在更下方(使用 _(child.text) 触发翻译):
# 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)
func(_(child.text))
在我的代码中,我使用的是:
builder = GtkBuilder("PrimerPrep.glade", APP_NAME)
builder.connect_signals(Handler())
这似乎可行,但似乎是一种非常复杂的方式来到达我想去的地方。
其他翻译 Glade 界面的尝试 我还读到问题是 Glade 接口是使用 C 代码呈现的,因此 _() 的覆盖不会翻译 Glade 字符串。所以我尝试了这段代码的变体:
try:
import ctypes
libintl = ctypes.cdll.LoadLibrary('libintl-8.dll')
libintl.bindtextdomain(APP_NAME, locale_path)
libintl.bind_textdomain_codeset(APP_NAME, 'UTF-8')
except:
print('Error loading translations into Glade file.')
我也试过设置环境变量:
os.environ['LANG'] = 'fr_FR'
我玩过不同的语言环境选项,包括这里描述的内容:How to bind a text domain to a local folder for gettext under GTK3) 但由于我的语言环境模块没有 bindtextdomain 对象,因此没有任何结果。而且我不想实际设置计算机区域设置。例如。我的计算机上没有法语语言环境,但我希望能够将程序 UI 更改为法语。如果我尝试将语言环境设置为未安装的语言环境,则会出现错误。
这些选项似乎都不能翻译 Glade 界面。
gettext应该可以做得更好吧? 从 23.1.3.3 中的 gettext 文档 (https://docs.python.org/3.5/library/gettext.html) 看来,这应该不难:
lang1 = gettext.translation('myapplication', languages=['en'])
lang2 = gettext.translation('myapplication', languages=['fr'])
# start by using language1
lang1.install()
# ... time goes by, user selects language 2
lang2.install()
我尝试了这些东西的各种组合,但似乎都没有影响 Glade 界面(可能是上面提到的 C 语言问题)。
让用户界面更新 所以上面复杂的解决方案是唯一在某种程度上有效的解决方案。但即便如此,我也只能在程序启动时设置语言环境以使其生效。在程序运行时更改 UI 语言的过程是什么。手动将 _() 例程更改为新的翻译语言后,我尝试再次运行 builder.recursive_xml_translate() 例程,但这似乎并没有更新界面。我找不到像 Gtk.Builder.refresh() 方法这样的东西。关于如何更新 UI 语言的任何建议?
结论 所以我找到了一种复杂的方式来翻译 Glade 界面,所以看起来我可以付出足够的努力来完成这项工作(如果我能找到一种即时更新它的方法)。但一定有更简单的方法!请告诉我,我只是错过了一些能让我的生活更轻松的小东西……
【问题讨论】:
-
您是否尝试在 glade 属性中设置翻译域? this对话框
标签: python-3.x gtk3 glade