我正在开发一个Python程序,将PyGTK3和Glade用于UI。我想国际化UI,而不是根据系统中的语言环境,而是通过程序中“已安装”的语言进行国际化,并且我希望能够“即时”更改UI语言,例如,通过选择一个菜单中的语言。我在运行Python 3.4的Windows 10上。
我做了很多研究,尝试了很多事情,并取得了一些进展。我能够为Windows程序包安装一个gettext程序(链接?),但是显然它很小。 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手动设置文本 我找到了以下页面:翻译python gtk构建器文件(http://martens.me/programming/translating-python-gtk-builder-files.html),它解释了如何创建Gtk.Builder的派生类,该类将扫描.glade文件的XML并手动调用set _ {}(在我的上下文中,则每个参数的设置都应为_(child.text),设置为set_label,set_text或set_title),以便进行翻译。我对他的代码做了一些更改,因为在扫描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))
在我的代码中,我使用以下代码代替上面显示的4条构建器行:
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界面的方法,因此,我似乎可以做出足够的努力(如果我能找到一种动态更新它的方法)。但是必须有一个更简单的方法!请告诉我,我只是想念一些小事情,这些事情会使我的生活更加轻松……
答案 0 :(得分: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”目录:
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 文件并将其移动到相应的文件夹。
答案 1 :(得分:0)