PyQt中的国际化问题

Python

This article was last updated on <span id="expire-date"></span> days ago, the information described in the article may be outdated.

最近自己搞的海雾识别可视化界面已经基本完善可用了,唯一的不足就是没有弄国际化。因为网上有关 PyQt 国际化的示例实在是太不全了,方法五花八门,甚至连 Stack Overflow 上都没有很好的解决方法。经过自己的不断搜索,以及阅读 PyQt 上的手册,终于搞明白了 PyQt5 和 PyQt6 两个版本 PyQt 国际化的方法。

image-20231105205151967

PyQt5

PyQt5 中搞国际化稍微简单一点。首先需要将所有需要翻译的文本传入QCoreApplication.translate函数,该函数将会根据安装的语言包将文本翻译为对应语言的文本并返回。该函数接受两个参数,第一个参数 context 传入文本所在类的类名即可,第二个参数是需要翻译的文本。示例代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import QMainWindow


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 为了减少代码量,将 self._translate 设为 QCoreApplication.translate
# 需要注意的是,pylupdate5 转换脚本是通过检测"translate"和"_translate"关键字来抓取代码中的翻译文本的,
# 因此如果不将 QCoreApplication.translate 重命名为以上两个名字的话,最后生成的TS文件中是不会包含对应的文本的。
# 有兴趣可以自己尝试一下
self._translate = QCoreApplication.translate

def slot_function(self):
print(self._translate("MainWindow", "Who's your daddy"))

然后还需要准备一个.pro文件,类似于C++ Qt。SOURCES后面写上所有需要抓取翻译文本的Python文件。实测.ui文件是不可以的。TRANSLATIONS后面写上生成哪些翻译文件,也可以写多个。

1
2
3
4
5
SOURCES += /path/to/Python/scripts \
/other/scripts

TRANSLATIONS += /path/to/ts/file \
/other/path/to/ts/file

然后在命令行中运行pylupdate5脚本即可生成TS翻译文件。例如上面的.pro文件我们保存为test.pro,则运行的命令为

1
pylupdate5 test.pro

然后在对应的路径下即可看到生成的TS文件。当代码中的文本发生变化时,只需要再次运行上面的命令重新生成TS文件即可,已存在的翻译不会被覆盖掉。

PyQt6

PyQt6 中对应的pylupdate6更改了作用方式,不能再读取.pro文件了,但是可以抓取.ui文件中的文本了。并且在Python代码中抓取文本时检测的关键字也只有"translate"了。所以我们需要将self._translate改为self.translate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PyQt6.QtCore import QCoreApplication
from PyQt6.QtWidgets import QMainWindow


class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 为了减少代码量,将 self._translate 设为 QCoreApplication.translate
# 需要注意的是,pylupdate5 转换脚本是通过检测"translate"和"_translate"关键字来抓取代码中的翻译文本的,
# 因此如果不将 QCoreApplication.translate 重命名为以上两个名字的话,最后生成的TS文件中是不会包含对应的文本的。
# 有兴趣可以自己尝试一下
self.translate = QCoreApplication.translate

def slot_function(self):
print(self.translate("MainWindow", "Who's your daddy"))

然后运行以下命令生成对应的TS文件。例如上面的代码保存到mainwindow.py,我们要生成zh_hans.ts文件,则命令为

1
pylupdate6 --ts /path/to/zh_hans.ts /path/to/mainwindow.py /path/to/other/Python/scripts /path/to/other/ui/file

你可以将其他的Python文件、.ui文件跟在后面。后面每次更改文本时,都需要重新运行上面的命令,并且后面传入的Python、.ui文件不能缺少,否则在更新TS文件时如果pylupdate6没有找到文本的来源,会将文本标记为废弃状态。这样的话在 PyQt6 中生成多种语言的TS文件时稍微有些麻烦,因为需要手动运行多次命令,命令的长度也比较长。

动态更改语言

PyQt 中似乎没有与切换语言相关的事件,因此更改语言的逻辑都需要自己编写。整体的思路就是在用户选择一个新的语言后,读取并安装一个新的语言包,并向其他所有UI界面发送信号让它们强制刷新一次UI界面(例如调用self.ui.retranslateUi(self))。这里我以 PyQt5 作为例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from PyQt5.QtCore import pyqtSignal, QTranslator
from PyQt5.QtWidgets import QMainWindow, QApplication


class Setting(QMainWindow):

signal_change_language = pyqtSignal()

def __init__(self):
super().__init__()
# 初始化 Translator
self.translator = QTranslator()

def slot_on_language_change(self):
# 翻译器读取新的语言包,不需要带.qm后缀
# 第二个参数是放置语言包的目录路径
self.translator.load("zh_hans", "/path/to/qm/folder")
# 获取当前的app实例
app = QApplication.instance()
# 安装新的翻译器
app.installTranslator(self.translator)
# 发送信号让其他界面刷新UI
self.signal_change_language.emit()

至于如果你想让UI刷新后保存已有的更改(例如参数设置等),你需要在接受到更改语言的信号后保存好参数的设置,然后在界面刷新后重新设置参数。

Author: Syize

Permalink: https://blog.syize.cn/2023/11/05/pyqt-translation/

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Syizeのblog

Comments