1. 程式人生 > >使用 PySide2 開發 Maya 外掛系列三:qt語言國際化(internationalization)

使用 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:\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 外掛系列 總覽