【问题标题】:Internationalize Python project, using PyGTK3 and Glade国际化 Python 项目,使用 PyGTK3 和 Glade
【发布时间】: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


【解决方案1】:

gettext 模块无法与 Glade 一起正常工作。改用提供 locale 模块的 gettext 函数:locale.gettext:

# At the beginning of the script ...
from locale import gettext as _
DOM = script_name[:-3]  # script_name = 'myscript.py' 
locale.bindtextdomain(DOM, PATH_SCRIPT + 'locale/')
locale.textdomain(DOM)
print(f"{DOM}")  # --> DOM = 'myscript'
....

接下来,定义 Gtk.Builder:

...
builder = Gtk.Builder()
builder.add_from_file(PATH_GLADE + "win.glade")
builder.set_translation_domain(DOM)  #  <--- !!!!!!
self.window = builder.get_object("window_app")
builder.connect_signals(Handler())
...

在示例中,我们假设在脚本所在的目录中有一个类似以下的“语言环境”目录:

     locale/
      ├── es_AR
      │   └── LC_MESSAGES
      │       └── myscript.mo
      └── fr_FR
          └── LC_MESSAGES
              └── myscript.mo

然后是通常的程序:

创建 .h 文件

$ intltool-extract --type="gettext/glade" ./ui/app.glade

创建 .pot 文件

$ xgettext -k_ -kN_ --from-code utf-8  -o myscript.pot myscript.py ./ui/app.glade.h

创建 .po 文件

$ msginit -i myscript.pot -o myscript.po

现在将翻译合并到 myscript.po 文件中。

创建 .mo 文件

$ msgfmt myscript.po -o myscript.mo

移动 myscript.mo 到目录 最后,将文件移动到它对应的语言目录 示例:

     locale/
       └─ es_AR
          └── LC_MESSAGES
              └── myscript.mo

对于另一种语言,创建一个新的 .po 文件,合并翻译,创建 .mo 文件并将其移动到相应的文件夹。

【讨论】:

    【解决方案2】:

    尝试检查:

    Using locale to bind glade i18n

    实际的标题有所不同,但可以解决问题。我仍然有股票按钮的问题,但我的应用程序的其余部分开始被 i18ned

    【讨论】:

      猜你喜欢
      • 2017-12-12
      • 2011-10-07
      • 1970-01-01
      • 2016-11-13
      • 2021-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多