使用 PySide2 开发 Maya 插件系列三:qt语言国际化(internationalization)

前言:

这是 qt for python 的语言国际化,基于 UI 的,python 也有自身的语言国际化,两者是不同的。

先来看最终效果:

前期准备:

这次创建一个 main window 在 menu bar 加一个 language 的 menu:

我们还要对 action 进行一些设置,如下:

生成 .py 文件:

生成代码:

 # -*- coding: utf-8 -*-

 # Form implementation generated from reading ui file '.\internationalizationTest.ui'
#
# Created: Sun Nov 18 02:16:18 2018
# by: pyside-uic 0.2.15 running on PySide 1.2.4
#
# WARNING! All changes made in this file will be lost! from PySide import QtCore, QtGui class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(320, 248)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 320, 26))
self.menubar.setObjectName("menubar")
self.menuLanguage = QtGui.QMenu(self.menubar)
self.menuLanguage.setObjectName("menuLanguage")
MainWindow.setMenuBar(self.menubar)
self.actionEnglish = QtGui.QAction(MainWindow)
self.actionEnglish.setObjectName("actionEnglish")
self.actionChinese = QtGui.QAction(MainWindow)
self.actionChinese.setObjectName("actionChinese")
self.menuLanguage.addAction(self.actionEnglish)
self.menuLanguage.addAction(self.actionChinese)
self.menubar.addAction(self.menuLanguage.menuAction()) self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.menuLanguage.setTitle(QtGui.QApplication.translate("MainWindow", "Language", None, QtGui.QApplication.UnicodeUTF8))
self.actionEnglish.setText(QtGui.QApplication.translate("MainWindow", "English", None, QtGui.QApplication.UnicodeUTF8))
self.actionChinese.setText(QtGui.QApplication.translate("MainWindow", "Chinese", None, QtGui.QApplication.UnicodeUTF8))

internationalizationTest_ui_pyside.py

其实 pyside 有 uic 模块可以直接load .ui 文件获得 ui 类,但是没办法实现语言国际化,或许通过另外的方法可以。

1. 使用 lupdate 从 .py 生成 .ts

安装了 PySide 或者 PySide2 后,就会有 lupdate 工具,如果不知道在哪,就在 python 的安装目录下搜 lupdate ,PySide 和 PyQt 的前缀都不一样:

这里我们使用第一个 pyside-lupdate.exe,这个参数会简单,lupdate 的参数相对复杂,在 cmd 中查看 pyside-lupdate.exe 的帮助:

可以看到 Usage,有两种用法,这里我们使用第一种project-file,方便以后反复修改,我们新建一个文件 translation_en_to_zh_CN.pro, 内容语法如下:

SOURCES = internationalizationTest_ui_pyside.py

TRANSLATIONS = translation_en_to_zh_CN.ts

CODECFORTR = UTF-8

CODECFORSRC = UTF-8

SOURCES:从一个或者多个 .py 文件中提取需要翻译的文本,不同 .py 用空格隔开,例如:

SOURCES = internationalizationTest_ui_pyside.py otherUI.py     

TRANSLATIONS:指定生成的 ts 文件名,注意文件名,因为我们不单单会有一种语言的翻译,例如如果我们还需要中文繁体,那么就可以新建另外的一个 project 文件:translation_en_to_zh_TW.pro,关于各国语言的简写,请参考:https://www.cnblogs.com/ibingshan/p/9871211.html

CODECFORTR 和 CODECFORSRC:指定一些编码,可以有可以没有。

下面我们来生成 .ts 文件:

这样就生成了 translation_en_to_zh_CN.ts:

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS><TS version="1.1">
<context>
<name>MainWindow</name>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="37"/>
<source>MainWindow</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="38"/>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="39"/>
<source>English</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="40"/>
<source>Chinese</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

那么 lupdate 是根据什么来决定那些文本需要被翻译的呢,看 internationalizationTest_ui_pyside.py 中的

def retranslateUi(self, MainWindow):
  MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
  self.menuLanguage.setTitle(QtGui.QApplication.translate("MainWindow", "Language", None, QtGui.QApplication.UnicodeUTF8))
  self.actionEnglish.setText(QtGui.QApplication.translate("MainWindow", "English", None, QtGui.QApplication.UnicodeUTF8))
  self.actionChinese.setText(QtGui.QApplication.translate("MainWindow", "Chinese", None, QtGui.QApplication.UnicodeUTF8))

可以看到并不是直接的 setText('text') ,而是有 QtGui.QApplication.translate ,lupdate 就是根据这个来决定的,注意 PySide 和 PySide2 的 QtGui.QApplication.translate 后面的参数有所不一样。

注意:QtGui.QApplication.translate 的前面连个参数是 str 类型,如果需要用参数来传递,最好转换成 str 例如 str(myStr)。

2. 使用 qt linguist 打开 .ts 文件来翻译成各语言版本

打开 qt linguist 了

file -> open,找到 translation_en_to_zh_CN.ts 并且打开,这是会弹出一个指定源语言和目标语言的选择窗口,我们可以在这里设置,也可以以后发布的时候通过 Edit -> Translation File Setting 打开这个窗口:

Source language 我们选择英语,其实源语言决定你使用 qt designer 的时候 widgets 的语言:

打开后如下:

这个使用是非常容易上手的,而且不用担心 lupdate 重新生成 .ts 后会把之前的翻译覆盖掉,事实上 lupdate 会保留已经翻译好的信息,而且会增加你添加的文本,或者你的 UI 中删除了,lupdate都能识别。

点击前面的问号,标记一下你已经翻译好了:

保存后的 .ts 文件:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="zh_CN" sourcelanguage="en">
<context>
<name>MainWindow</name>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="37"/>
<source>MainWindow</source>
<translation type="unfinished">主窗口</translation>
</message>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="38"/>
<source>Language</source>
<translation>语言</translation>
</message>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="39"/>
<source>English</source>
<translation>英文</translation>
</message>
<message>
<location filename="internationalizationTest_ui_pyside.py" line="40"/>
<source>Chinese</source>
<translation>中文</translation>
</message>
</context>
</TS>

3. ts 发布 .pm

PySide 翻译的时候并不是用 .ts 文件的,需要把 .ts 文件发布为 .pm 文件。

我们可以使用 lrelease.exe 来发布:

在 linguist 中保存好 .ts 文件后:

也可以在 linguist 中直接发布:

这时候就会生成 translation_en_to_zh_CN.qm,如果我们用文本编辑器打开,里面都是乱码。

4.继承 internationalizationTest_ui_pyside.py 中的类

新建一个 internationalizationTest.py:

 # -*- coding: utf-8 -*-

 import os
import sys import internationalizationTest_ui_pyside as ui from PySide import QtGui
from PySide import QtGui as QtWidgets
from PySide import QtCore TRANSLATOR = QtCore.QTranslator() #TRANSLATION_DIR = os.path.join(os.path.dirname(__file__), 'translations') class MainWindow(QtWidgets.QMainWindow, ui.Ui_MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.setupUi(self) self.languageActionGroup = QtWidgets.QActionGroup(self.menuLanguage) #这里把语言actions放到一个组里面,使得每次只能选择一个
self.languageActionGroup.addAction(self.actionEnglish)
self.languageActionGroup.addAction(self.actionChinese)
self.languageActionGroup.triggered[QtWidgets.QAction].connect(self.on_language_changed) #连接 trigger 槽,on_language_changed(self, action)中的action是自动传递的别点击的action对象 def on_language_changed(self, action):
result = False #为了debug TRANSLATOR 加载 pm 文件是否成功
if action == self.actionChinese: #通过action来判断哪个语言action被点击来选择不同的 pm 加载
result = TRANSLATOR.load('translation_en_to_zh_CN') #注意,可以不需要 .pm 后缀
#TRANSLATOR.load('translation_en_to_zh_CN', directory = TRANSLATION_DIR)#这里是指定某个路径下的 pm
else:
TRANSLATOR.load('') #如果加载失败,则会重置会第一个语言 print(result) #打印加载结果
self.retranslateUi(self) #在TRANSLATOR加载后,记得一定要执行 retranslateUi 或者其他自己定义的重新设置文本的方法。 def main():
app = QtWidgets.QApplication(sys.argv) app.installTranslator(TRANSLATOR) #非常重要的一步,为 app 安装 TRANSLATOR,如果不安装,是没有效果的 win = MainWindow()
win.show()
sys.exit(app.exec_()) if __name__ == "__main__":
main()

下面来看看效果:

5.在 maya 中实现

这次是在 maya2015 中实现,如果是 maya2017 以上,请自己修改一下代码,使得 pyside 和 pyside2 兼容

新建一个 internationalizationTest_maya.py:

 # -*- coding: utf-8 -*-

 #from PySide import QtGui
from PySide import QtGui as QtWidgets #这样可以使得 pyside 和 pyside2 基本兼容,而且可以不用额外的补丁,也就是说是以 pyside2 为基础的
#import shiboken2 as shiboken #如果是 maya2017 以上,可以这样。
import shiboken import internationalizationTest as ui import maya.OpenMayaUI as omui
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow() #获得maya主窗口的指针,主要是为了让插件界面设置它为父窗口
return shiboken.wrapInstance(long(main_window_ptr), QtWidgets.QWidget) #把maya主窗口封装从QtGui对象 class MainWindow(ui.MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent) win = MainWindow(maya_main_window())
def main():
app = QtWidgets.QApplication.instance() #因为 maya 已经是启动的 app,所以这里是获得 app 的实例 app.installTranslator(ui.TRANSLATOR) #安装 translator global win
try:
win.close()
except:
pass
win.show()

因为是在maya中运行,所以 internationalizationTest.py 要改为如下,也就是 TRANSLATOR.load('translation_en_to_zh_CN', directory = TRANSLATION_DIR) ,要为 translation_en_to_zh_CN 指定一个路径,如果不指定,那么默认路径是 app 的路径下查找,但是maya的app路径并不在 internationalizationTest_maya.py 所在的路径:

 # -*- coding: utf-8 -*-

 import os
import sys import internationalizationTest_ui_pyside as ui from PySide import QtGui
from PySide import QtGui as QtWidgets
from PySide import QtCore TRANSLATOR = QtCore.QTranslator() TRANSLATION_DIR = os.path.dirname(__file__) class MainWindow(QtWidgets.QMainWindow, ui.Ui_MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.setupUi(self) self.languageActionGroup = QtWidgets.QActionGroup(self.menuLanguage) #这里把语言actions放到一个组里面,使得每次只能选择一个
self.languageActionGroup.addAction(self.actionEnglish)
self.languageActionGroup.addAction(self.actionChinese)
self.languageActionGroup.triggered[QtWidgets.QAction].connect(self.on_language_changed) #连接 trigger 槽,on_language_changed(self, action)中的action是自动传递的别点击的action对象 def on_language_changed(self, action):
result = False #为了debug TRANSLATOR 加载 qm 文件是否成功
if action == self.actionChinese: #通过action来判断哪个语言action被点击来选择不同的 qm 加载
#result = TRANSLATOR.load('translation_en_to_zh_CN') #注意,可以不需要 .qm 后缀
result = TRANSLATOR.load('translation_en_to_zh_CN', directory = TRANSLATION_DIR)#这里是指定某个路径下的 qm else:
TRANSLATOR.load('') #如果加载失败,则会重置会第一个语言 print(result) #打印加载结果
self.retranslateUi(self) #在TRANSLATOR加载后,记得一定要执行 retranslateUi 或者其他自己定义的重新设置文本的方法。 def main():
app = QtWidgets.QApplication(sys.argv)
print(app)
app.installTranslator(TRANSLATOR) #非常重要的一步,为 app 安装 TRANSLATOR,如果不安装,是没有效果的 win = MainWindow()
win.show()
sys.exit(app.exec_()) if __name__ == "__main__":
main()

启动 maya,打开 Script Editor,在 python 栏输入:

import sys
sys.path.append(r'E:\Works\Maya\Scripts\PySideTest') #把代码所在的路径添加到环境变量PATH中,这样可以import它们

import internationalizationTest_maya
reload(internationalizationTest_maya)
internationalizationTest_maya.main()

  注意:sys.path.append 的路径改为自己的路径

全选代码,ctrl+shift+enter 运行,效果如下:

总结:

qt 语言国际化实现基本思路:

  1. 创建一个 translator 对象:TRANSLATOR = QtCore.QTranslator()
  2. app对象安装 translator:app.installTranslator(TRANSLATOR)
  3. translator 加载 qm 文件:TRANSLATOR.load('translation_en_to_zh_CN', directory = TRANSLATION_DIR)
  4. UI 再次设置 widget 文本:self.retranslateUi(self)

至此,使用 PySide2 开发 Maya 插件系列已经完毕,希望对大家有所帮助。

回到总览使用 PySide2 开发 Maya 插件系列 总览

使用 PySide2 开发 Maya 插件系列三:qt语言国际化(internationalization)的更多相关文章

  1. 使用 PySide2 开发 Maya 插件系列 总览

    使用 PySide2 开发 Maya 插件系列 总览 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 ...

  2. 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件

    使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 前期准备: 安装 python:https://www ...

  3. 使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form

    使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form 开发环境: Wing IDE 6.1 步骤1: 打开 Wing IDE,创建一个新的 pr ...

  4. (三)Qt语言国际化

    Vs 2010+ Qt5 实现语言国际化 创建一个工程,cpp代码如下: 1.创建工程 #include "languageinternationalized.h" #includ ...

  5. 【开发者portal在线开发插件系列三】字符串 及 可变长度字符串

    基础篇 基础场景见上面两个帖子,这里单独说明字符串和可变长度字符串的用法. 话不多说,开始今天的演(表)示(演) Profile和插件开发 添加一个string类型的属性: 在插件里添加一条数据上报消 ...

  6. 手把手教你开发jquery插件(三)

    First, i want to add options to Tabs constructor like this: var tabs = $("div.tabs").tabs( ...

  7. 步步为营 SharePoint 开发学习笔记系列总结

    转:http://www.cnblogs.com/springyangwc/archive/2011/08/03/2126763.html 概要 为时20多天的sharepoint开发学习笔记系列终于 ...

  8. Web 开发人员和设计师必读文章推荐【系列三十】

    <Web 前端开发精华文章推荐>2014年第9期(总第30期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  9. SSM框架开发web项目系列(三) MyBatis之resultMap及关联映射

    前言 在上篇MyBatis基础篇中我们独立使用MyBatis构建了一个简单的数据库访问程序,可以实现单表的基本增删改查等操作,通过该实例我们可以初步了解MyBatis操作数据库需要的一些组成部分(配置 ...

随机推荐

  1. GDOI2018 涛涛摘苹果 [CDQ分治]

    传送门我会让你知道哪里有题面吗(逃 思路 显然不能模拟苹果下掉的过程,考虑计算每个苹果对询问的贡献. 显然一开始就有的苹果可以看做第0天变出来的,于是只需要考虑变出来的苹果了. 设当前询问节点\(x\ ...

  2. es6 super关键字

    rhttp://es6.ruanyifeng.com/#docs/class-extends super关键字,既可以当作函数使用,也可以当作对象使用.这俩种的使用是不一样的 第一种:函数使用 代表父 ...

  3. LuoGu P1006 传纸条

    题目传送门 这题嘛...方格取数和这题一样一样的 只不过这题是从左上到右下再回去罢了(来回一趟和来两趟有区别么?没有,那么这题和上题用一样的转移和状态就行了 没什么好说的,说一下我的错误好了: 人家图 ...

  4. Confluence 6 启用和禁用 Office 连接器

    如果你希望限制访问 Office 连接器的所有组件或者部分组件,你可以禁用整个插件也可以禁用插件中的某个模块. 希望启用或禁用 Office 连接器模块: 进入  > 基本配置(General ...

  5. 《剑指offer》 树的子结构

    本题来自<剑指offer> 树的子结构 题目: 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 思路: 分两步走: 第一步:判断根节点,两个根节 ...

  6. laravel 框架后台主菜单接口

    后台菜单调用接口:/admin/manages ManageRepository类: 每个路由中注册: 等等: 最后后台菜单返回:

  7. Laravel5使用QQ邮箱发送邮件配置

    在.env文件中设置如下MAIL_DRIVER=smtpMAIL_HOST=smtp.qq.comMAIL_PORT=465MAIL_USERNAME=00000000000@qq.comMAIL_P ...

  8. 【转】运维DBA的4大纪律9项注意

    朋友们调侃说,运维是个把脑袋别在裤腰带上的活,更有人说,运维是个把脑袋别在他人裤腰带上的活,苦劳没人认,有锅就有得背! 测试的同学说,“吃瓜群众很难感知运维背后的付出,倒是出了事情更能体现我们的专业性 ...

  9. Windows批处理命令用法

    阅读下面文字需要一定的dos基础概念,象:盘符.文件.目录(文件夹).子目录.根目录.当前目录 每个命令的完整说明请加 /? 参数参考微软的帮助文档可以看到,在 /? 帮助里,"命令扩展名& ...

  10. EXcel vba 获取批注信息

    Public Function pizhu(i As Range) pizhu = i.Cells.Comment.Text End Function EXcel VBA获取批注信息