zoukankan      html  css  js  c++  java
  • 使用 PySide2 开发 Maya 插件系列三:qt语言国际化(internationalization)

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

    前言:

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

    先来看最终效果:

    前期准备:

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

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

    生成 .py 文件:

    生成代码:

     1 # -*- coding: utf-8 -*-
     2 
     3 # Form implementation generated from reading ui file '.internationalizationTest.ui'
     4 #
     5 # Created: Sun Nov 18 02:16:18 2018
     6 #      by: pyside-uic 0.2.15 running on PySide 1.2.4
     7 #
     8 # WARNING! All changes made in this file will be lost!
     9 
    10 from PySide import QtCore, QtGui
    11 
    12 class Ui_MainWindow(object):
    13     def setupUi(self, MainWindow):
    14         MainWindow.setObjectName("MainWindow")
    15         MainWindow.resize(320, 248)
    16         self.centralwidget = QtGui.QWidget(MainWindow)
    17         self.centralwidget.setObjectName("centralwidget")
    18         MainWindow.setCentralWidget(self.centralwidget)
    19         self.menubar = QtGui.QMenuBar(MainWindow)
    20         self.menubar.setGeometry(QtCore.QRect(0, 0, 320, 26))
    21         self.menubar.setObjectName("menubar")
    22         self.menuLanguage = QtGui.QMenu(self.menubar)
    23         self.menuLanguage.setObjectName("menuLanguage")
    24         MainWindow.setMenuBar(self.menubar)
    25         self.actionEnglish = QtGui.QAction(MainWindow)
    26         self.actionEnglish.setObjectName("actionEnglish")
    27         self.actionChinese = QtGui.QAction(MainWindow)
    28         self.actionChinese.setObjectName("actionChinese")
    29         self.menuLanguage.addAction(self.actionEnglish)
    30         self.menuLanguage.addAction(self.actionChinese)
    31         self.menubar.addAction(self.menuLanguage.menuAction())
    32 
    33         self.retranslateUi(MainWindow)
    34         QtCore.QMetaObject.connectSlotsByName(MainWindow)
    35 
    36     def retranslateUi(self, MainWindow):
    37         MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
    38         self.menuLanguage.setTitle(QtGui.QApplication.translate("MainWindow", "Language", None, QtGui.QApplication.UnicodeUTF8))
    39         self.actionEnglish.setText(QtGui.QApplication.translate("MainWindow", "English", None, QtGui.QApplication.UnicodeUTF8))
    40         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:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!DOCTYPE TS><TS version="1.1">
     3 <context>
     4     <name>MainWindow</name>
     5     <message>
     6         <location filename="internationalizationTest_ui_pyside.py" line="37"/>
     7         <source>MainWindow</source>
     8         <translation type="unfinished"></translation>
     9     </message>
    10     <message>
    11         <location filename="internationalizationTest_ui_pyside.py" line="38"/>
    12         <source>Language</source>
    13         <translation type="unfinished"></translation>
    14     </message>
    15     <message>
    16         <location filename="internationalizationTest_ui_pyside.py" line="39"/>
    17         <source>English</source>
    18         <translation type="unfinished"></translation>
    19     </message>
    20     <message>
    21         <location filename="internationalizationTest_ui_pyside.py" line="40"/>
    22         <source>Chinese</source>
    23         <translation type="unfinished"></translation>
    24     </message>
    25 </context>
    26 </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:

     1 # -*- coding: utf-8 -*-
     2 
     3 import os
     4 import sys
     5 
     6 import internationalizationTest_ui_pyside as ui
     7 
     8 from PySide import QtGui
     9 from PySide import QtGui as QtWidgets
    10 from PySide import QtCore
    11 
    12 TRANSLATOR = QtCore.QTranslator()
    13 
    14 #TRANSLATION_DIR = os.path.join(os.path.dirname(__file__), 'translations')
    15 
    16 class MainWindow(QtWidgets.QMainWindow, ui.Ui_MainWindow):
    17     def __init__(self, parent = None):
    18         super(MainWindow, self).__init__(parent)
    19         self.setupUi(self)
    20         
    21         self.languageActionGroup = QtWidgets.QActionGroup(self.menuLanguage)                    #这里把语言actions放到一个组里面,使得每次只能选择一个
    22         self.languageActionGroup.addAction(self.actionEnglish)
    23         self.languageActionGroup.addAction(self.actionChinese)
    24         self.languageActionGroup.triggered[QtWidgets.QAction].connect(self.on_language_changed) #连接 trigger 槽,on_language_changed(self, action)中的action是自动传递的别点击的action对象
    25         
    26     def on_language_changed(self, action):
    27         result = False                                              #为了debug TRANSLATOR 加载 pm 文件是否成功
    28         if action == self.actionChinese:                            #通过action来判断哪个语言action被点击来选择不同的 pm 加载
    29             result = TRANSLATOR.load('translation_en_to_zh_CN')     #注意,可以不需要 .pm 后缀
    30             #TRANSLATOR.load('translation_en_to_zh_CN', directory = TRANSLATION_DIR)#这里是指定某个路径下的 pm
    31         else:
    32             TRANSLATOR.load('')                                     #如果加载失败,则会重置会第一个语言
    33             
    34         print(result)                                               #打印加载结果
    35         self.retranslateUi(self)                                    #在TRANSLATOR加载后,记得一定要执行 retranslateUi 或者其他自己定义的重新设置文本的方法。
    36             
    37 def main():
    38     app = QtWidgets.QApplication(sys.argv)
    39     
    40     app.installTranslator(TRANSLATOR)   #非常重要的一步,为 app 安装 TRANSLATOR,如果不安装,是没有效果的
    41     
    42     win = MainWindow()
    43     win.show()
    44     sys.exit(app.exec_())
    45     
    46 if __name__ == "__main__":
    47     main()

    下面来看看效果:

    5.在 maya 中实现

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

    新建一个 internationalizationTest_maya.py:

     1 # -*- coding: utf-8 -*-
     2 
     3 #from PySide import QtGui
     4 from PySide import QtGui as QtWidgets       #这样可以使得 pyside 和 pyside2 基本兼容,而且可以不用额外的补丁,也就是说是以 pyside2 为基础的
     5 #import shiboken2 as shiboken               #如果是 maya2017 以上,可以这样。
     6 import shiboken
     7 
     8 import internationalizationTest as ui
     9 
    10 import maya.OpenMayaUI as omui
    11 def maya_main_window():
    12     main_window_ptr = omui.MQtUtil.mainWindow()                             #获得maya主窗口的指针,主要是为了让插件界面设置它为父窗口
    13     return shiboken.wrapInstance(long(main_window_ptr), QtWidgets.QWidget)  #把maya主窗口封装从QtGui对象
    14 
    15 class MainWindow(ui.MainWindow):
    16     def __init__(self, parent = None):
    17         super(MainWindow, self).__init__(parent)
    18         
    19 win = MainWindow(maya_main_window())
    20 def main():
    21     app = QtWidgets.QApplication.instance() #因为 maya 已经是启动的 app,所以这里是获得 app 的实例
    22     
    23     app.installTranslator(ui.TRANSLATOR)    #安装 translator
    24     
    25     global win
    26     try:
    27         win.close()
    28     except:
    29         pass
    30     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 所在的路径:

     1 # -*- coding: utf-8 -*-
     2 
     3 import os
     4 import sys
     5 
     6 import internationalizationTest_ui_pyside as ui
     7 
     8 from PySide import QtGui
     9 from PySide import QtGui as QtWidgets   
    10 from PySide import QtCore
    11 
    12 TRANSLATOR = QtCore.QTranslator()
    13 
    14 TRANSLATION_DIR = os.path.dirname(__file__)
    15 
    16 class MainWindow(QtWidgets.QMainWindow, ui.Ui_MainWindow):
    17     def __init__(self, parent = None):
    18         super(MainWindow, self).__init__(parent)
    19         self.setupUi(self)
    20         
    21         self.languageActionGroup = QtWidgets.QActionGroup(self.menuLanguage)                    #这里把语言actions放到一个组里面,使得每次只能选择一个
    22         self.languageActionGroup.addAction(self.actionEnglish)
    23         self.languageActionGroup.addAction(self.actionChinese)
    24         self.languageActionGroup.triggered[QtWidgets.QAction].connect(self.on_language_changed) #连接 trigger 槽,on_language_changed(self, action)中的action是自动传递的别点击的action对象
    25         
    26     def on_language_changed(self, action):
    27         result = False                                              #为了debug TRANSLATOR 加载 qm 文件是否成功
    28         if action == self.actionChinese:                            #通过action来判断哪个语言action被点击来选择不同的 qm 加载
    29             #result = TRANSLATOR.load('translation_en_to_zh_CN')     #注意,可以不需要 .qm 后缀
    30             result = TRANSLATOR.load('translation_en_to_zh_CN', directory = TRANSLATION_DIR)#这里是指定某个路径下的 qm
    31             
    32         else:
    33             TRANSLATOR.load('')                                     #如果加载失败,则会重置会第一个语言
    34             
    35         print(result)                                               #打印加载结果
    36         self.retranslateUi(self)                                    #在TRANSLATOR加载后,记得一定要执行 retranslateUi 或者其他自己定义的重新设置文本的方法。
    37             
    38 def main():
    39     app = QtWidgets.QApplication(sys.argv)
    40     print(app)
    41     app.installTranslator(TRANSLATOR)   #非常重要的一步,为 app 安装 TRANSLATOR,如果不安装,是没有效果的
    42     
    43     win = MainWindow()
    44     win.show()
    45     sys.exit(app.exec_())
    46     
    47 if __name__ == "__main__":
    48     main()

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

    import sys
    sys.path.append(r'E:WorksMayaScriptsPySideTest') #把代码所在的路径添加到环境变量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 插件系列 总览 

     

     

  • 相关阅读:
    img标签为什么可以设置宽高
    高度和宽度的操作
    自增自减运算符
    读取标签内容:innerHTML和innerText的区别 text()和html()的区别
    js中的常用方法
    js中style,currentStyle和getComputedStyle的区别以及获取css操作方法(考虑兼容性和局限性)
    IE盒模型与W3C盒模型区别
    css四种定位方式及其区别
    css隐藏元素的方法何区别
    Hibernate之HQL
  • 原文地址:https://www.cnblogs.com/ibingshan/p/9965139.html
Copyright © 2011-2022 走看看