国际化,英文为 internationalization,因英文单词太长不方便记忆,故采取 i18n 进行简写,其中18的意思为 internationalization 共20个字符,首尾字符分别为i和n,中间还有18个字符,故简称为 i18n。国际化即软件产品支持多个国家的语言、文化、使用习惯等环境,一般我们多指语言国际化,因为语言是使用者最大的障碍。
本地化,英文为 Localization,同样简称为 l10n。本地化即软件产品使用当地的环境,如语言、文化、使用习惯等.
python 自带的 gettext 模块就是为了支持国际化语言的,兼容 GUN gettext,GUN gettext 是最出名的国际化语言开源解决方案,这里对 GUN gettext 只做简介。GUN gettext 包含三种文件 .pot、.po、.mo:
.pot 为 Portable Object Template 可移植对象模板,即语言模板文件,可以使用 GettextTools 或 Poedit 软件获得,推荐使用Poedit软件,有免费社区版,Poedit Pro 为收费版。
.po 为 Portable Object 可移植对象,即可阅读语言翻译文件,此文件为 txt 格式,可以使用文本编辑器打开进行,文件结构这里不祥解,建议使用Poedit软件翻译
.mo 为 Machine Object 机器对象,即机器语言文件,为二进制文件,不可使用文本编辑器编辑。
pot 文件可以被 Poedit 打开并转化为 po 文件,Poedit 翻译后保存自动生成 mo 文件,也可以通过 GettextTools 的 xgettext 获得 pot 文件(可以直接改扩展名为 po 文件)、msgfmt 编译 po 文件为 mo 文件,msgunfmt 反编译 mo 文件为 po 文件。 (注意:Poedit 也是利用 GettextTools 进行编译的 )
这里以 wxFormBuilder 创建 GUI 窗口框架,并开启国际化支持,即字符串 "xxxxxx" 使用 _("xxxxxx") 进行翻译,文件名 GUI_Frame.py 代码如下:
# -*- coding: utf-8 -*-
###########################################################################
## Python code generated with wxFormBuilder (version Mar 23 2018)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
###########################################################################
import wx
import wx.xrc
## 下面两行为 wxFormBuilder 开启国际化支持自动使用 gettext 模块,对于文件中是否需要这两句,文章内有详细解释
import gettext
_ = gettext.gettext
###########################################################################
## Class MyFrame
###########################################################################
class MyFrame ( wx.Frame ):
def __init__(self, parent):
wx.Frame.__init__ (self, parent, id = wx.ID_ANY, title = _(u"i18n_example"),
pos = wx.DefaultPosition, size = wx.Size( 800,460 ),
style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
self.SetBackgroundColour(wx.Colour( 239, 235, 235 ))
self.m_menubar1 = wx.MenuBar(0)
self.file = wx.Menu()
self.m_menubar1.Append(self.file, _(u"File"))
self.about = wx.Menu()
self.m_menubar1.Append(self.about, _(u"About"))
self.SetMenuBar(self.m_menubar1)
self.Centre(wx.BOTH)
def __del__( self ):
pass
项目名称为 wx_i18n , 主文件为 wx_i18n.py 代码如下:
"""主文件,启用国际化支持."""
import wx
import os
## python gettext 来实现 i18n, gettext 提供两种方法:
# 实现国际化语言方法选择:1 类似 GUN gettext API,2 Python gettext 类
method = 1
"""
语言文件一般的路径一般为: localedir/language/LC_MESSAGES/domain.mo
其中:
语言主目录: localedir - 通常设为 locale, 可自定义
语言子目录: language 指具体语言的目录,可以有多种语言,
语言和语言子目录有一个默认对应表,如 简体中文 为 zh_CN, 英文 为 en,见相关说明文档
语言文件所在目录: LC_MESSAGES 无法修改,这是默认的
语言文件: domain.mo,用户可自定义文件名,若定义了文件名,则所有的语言文件名均为此名称
"""
# ToDo: 1.类似 GUN gettext API 的一套方法
"""
此方法适用于下,程序会根据用户指定的语言或者是查询系统环境变量 LANGUAGE, LC_ALL,
LC_MESSAGES, LANG 指定的语言进行程序语言初始化.
注意:使用这种方法必须在项目的所有 .py 文件内添加 _ = gettext.gettext
"""
if method == 1:
import gettext # 导入模块 gettext
lang_domain = "wx_i18n" # 语言域, 即所有语言的语言文件均含有 wx_i18n.mo
lang_localedir = os.path.abspath("locale") # 指定语言主目录为 ".\\locale"
# 将语言域 lang_domain 与 lang_localedir 语言主目录绑定
# 这样 gettext 函数会在 lang_localedir 目录下搜索对应语言的二进制 wx_i18n.mo 文件
gettext.bindtextdomain(lang_domain, lang_localedir)
# 声明使用的语言域, 可以有多个语言域
gettext.textdomain(lang_domain)
# 使用 os.environ 设置环境变量 LANGUAGE, 也可以设置系统环境变量 LANGUAGE
# 这里表示语言子目录, 只要语言子目录匹配到 "zh_CN" 即找到语言, 若存在多个以 zh_CN
# 为开头的语言子目录, 则选择第一个匹配的语言。
os.environ['LANGUAGE'] = "zh_CN"
# 以上即指定了 语言文件为: locale/zh_CN/LC_MESSAGES/wx_i18n.mo
# 把 _() 变成系统方法, 且关联为 gettext.gettext() 以支持多语言
import builtins
__builtins__.__dict__['_'] = gettext.gettext # 翻译方法绑定, 即 _('xxxx') 的内容均会被翻译
# 若不使用 builtins 模块把 _() 变为系统方法,则需要在每个项目文件内添加
# import gettext
# _ = gettext.gettext
# ToDo: 2.Python gettext 类的一套方法
"""
此方法适的每一种语言均要通过 gettext.translation() 进行设置,
使用 install() 进行安装,翻译方法 _() 函数会自动添加到 python 的内置命名空间中,
项目中其他 .py 文件不需要添加 _ = gettext.gettext,否则存在 _ = gettext.gettext 的文件
将不会被翻译为选定语言。并且最后一次安装的语言为当前生效语言。
"""
if method == 2:
import gettext # 导入模块 gettext
lang_domain = "wx_i18n" # 语言域, 即所有语言的语言文件均含有 wx_i18n.mo
lang_localedir = os.path.abspath("locale") # 指定语言主目录为 ".\\locale"
# 设置 zh_CN 语言,指定语言主目录(lang_localedir)、指定使用哪种语言(zh_CN)、指定语言域(lang_domain)
zh_CN = gettext.translation(domain=lang_domain, localedir=lang_localedir, languages=['zh_CN'])
# 安装语言 install() 将 _() 函数添加到 python 的内置命名空间中
zh_CN.install(True)
# 安装 en_US 语言,指定语言主目录(lang_localedir)、指定使用哪种语言(en_US)、指定语言域(lang_domain)
en_US = gettext.translation(lang_domain, lang_localedir, languages=['en_US'])
en_US.install(True)
# ToDo: 无论使用哪种方法,语言的设置必须在主程序初始化之前
## GUI 窗口框架
import GUI_Frame
## 主函数
if __name__ == '__main__':
if '_' in GUI_Frame.__dict__:
GUI_Frame.__dict__.pop('_') # 删除其他翻译函数, 以防冲突
if 'app' in dir():
del app # 防止出现以下错误: PyNoAppError: The wx.App object must be created first!
app = wx.App() # 实例化 wx.App, 这是 wxPython 必要步骤
frame = GUI_Frame.MyFrame(None) # GUI 主框架实例
frame.Show() # 显示窗口
app.MainLoop() # wxPython 的启动函数
代码有了,就介绍一下语言文件所在位置:
语言文件一般的路径一般为: localedir/language/LC_MESSAGES/domain.mo
其中:
语言主目录: localedir - 通常设为 locale, 可自定义,与源码同目录
语言子目录: language 指具体语言的目录,可以有多种语言,语言和语言子目录有一个默认对应表,如 简体中文 为 zh_CN,英文 为 en,见相关说明文档
语言文件所在目录: LC_MESSAGES 无法修改,这是默认的
语言文件: domain.mo,用户可自定义文件名,若定义了文件名,则所有的语言文件名均为此名称
本例子下语言文件路径为:
locale
+| zh_CN
. +| LC_MESSAGES
. +| wx_i18n.mo
. wx_i18n.po
+| en_US
. +| LC_MESSAGES
. +| wx_i18n.mo
. wx_i18n.po
这里分析一下 python gettext 的用法,gettext 提供两种方法:
第一种为类似 GUN gettext API 的一套方法
第二种为 python gettext 类成员的一套方法
GUN gettext API 方法, 程序会根据用户指定的语言或者是系统环境变量 LANGUAGE, LC_ALL, LC_MESSAGES, LANG 指定的语言进行程序语言初始化.
python gettext 提供了一套 API 和 GUN gettext 十分类似,主要常用的有如下:
gettext .bindtextdomain(domain, localedir=None) 此函数的作用是绑定指定的语言文件主目录和语言域。参数 domain 为语言域,一种语言可以存在多个语言域,一般设置一个语言域就够用了,就如本例中 zh_CN 和 en_US 均只有一个语言域 wx_i18n。localedir 默认为 None,指的是语言文件的主目录,本例中为 .\locale 目录。
gettext.textdomain(domain=None) 此函数的作用是选择使用哪个语言域(因为有可能存在多个语言域)。参数 domain 为语言域,本例只有一个语言域,因此只能指定 wx_i18n 这个语言域。本函数只指定了语言域但未指定具体使用那种语言
os.environ['LANGUAGE'] = "zh_CN" 使用 os.environ 设置环境变量 LANGUAGE, 也可以设置系统环境变量 LANGUAGE,这里表示语言子目录, 只要语言子目录匹配到 "zh_CN" 即找到语言, 若存在多个以 zh_CN为开头的语言子目录, 则选择第一个匹配的语言。
_ = gettext.gettext 翻译方法绑定, 即 _('xxxx') 的内容均会被翻译,gettext.gettext() 为默认翻译方法,但为每个字符串均加上这个方法太过于繁琐,因此简化为 _() 方法 。若要全局翻译,那么项目里所有的 .py 文件均要添加此翻译方法。
Python gettext 类的一套方法,此方法的每一种语言均要通过 gettext.translation() 进行设置,使用 install() 进行安装,翻译方法 _() 函数会自动添加到 python 的内置命名空间中,项目中其他 .py 文件不需要添加 _ = gettext.gettext,否则选定语言在此文件内不生效。最后一次安装的语言为当前生效语言。
注意:无论使用哪种方法,语言的设置必须在主程序初始化之前!!!
实例源码:https://download.csdn.net/download/qq_26227591/12312538
实例中,若删除 locale 文件夹,则为无语言情况,显示程序界面为:
实例中,选择多语言方式为 1(即:method = 1),语言设为中文(zh_CN),显示程序界面为:
实例中,选择多语言方式为 2(即:method = 2),语言设为美式英文(en_US),显示程序界面为:
扩展一下:
还有一种方法可以实现 wxPython 国际化多语言,即为 wxPython 自带的 wx.GetTranslation() 方法,其语言文件位置与 gettext 方式类似,以下为测试源码,需要上文实例的 语言文件和 GUI_Frame.py 文件。
# -*- coding: utf-8 -*-
import wx
# 把_()变成系统方法, 且关联为 wx.GetTranslation() 以支持多语言
import builtins
__builtins__.__dict__['_'] = wx.GetTranslation
## Implementing MyFrame
import GUI_Frame
class MyForm(GUI_Frame.MyFrame):
def __init__(self, parent):
GUI_Frame.MyFrame.__init__(self, parent)
## 主函数
if __name__ == '__main__':
if '_' in GUI_Frame.__dict__:
GUI_Frame.__dict__.pop('_') # 删除其他翻译函数, 以防冲突
if 'app' in dir():
del app # 防止出现以下错误: PyNoAppError: The wx.App object must be created first!
app = wx.App() # 实例化 wx.App, 这是 wxPython 必要步骤
"""" 语言文件通常为源码目录下的 localedir/language/LC_MESSAGES/domain.mo
其中:
语言主目录:localedir 语言所在主目录,一般设为 locale 可以自定义
语言子目录:language 指具体语言的目录,可以有多种语言,比如 简体中文 为 zh_CN,见说明文档
语言文件目录:LC_MESSAGES 无法修改,这是默认的
语言文件:domain.mo,用户可自定义文件名,若定义了文件名,则所有的语言文件名均为此名称
wx.GetTranslation() 方法必须在主程序初始化函数内切在控件初始化之前初始化语言
"""
lang = None
# 设置语言 wx.LANGUAGE_XXXX,同时也就指定了语言目录下选定语言的目录
# 具体参照说明文档,此处为 简体中文 目录为 zh_CN
lang = wx.Locale(wx.LANGUAGE_CHINESE_SIMPLIFIED)
if lang.IsOk():
# 设置语言主目录为源码目录下的 locale 目录,语言主目录名可以修改
lang.AddCatalogLookupPathPrefix('locale')
# 设置语言文件为 wx_i18n.mo,用户可自定义文件名, 返回值为 True 则语言加载成功
ibRet = lang.AddCatalog('wx_i18n')
frame = MyForm(None) # GUI 主框架实例
frame.Show() # 显示窗口
app.MainLoop() # wxPython 的启动函数