前言
在桌面软件开发中,国际化(Internationalization,简称 i18n)是一个非常常见的需求。
例如:
-
MES系统
-
ERP系统
-
工业相机软件
-
设备上位机
-
数据管理平台
通常需要实现:
- 中文界面
- 英文界面
- 菜单切换语言
- 不重启软件即可切换
- Qt Designer设计界面支持翻译
- 纯代码界面支持翻译
- 多窗口同步切换语言
Qt官方已经提供了完整的国际化解决方案:
- Qt Designer
- Qt Linguist
- pyside6-lupdate
- pyside6-lrelease
- QTranslator
本文将从零开始讲解完整开发流程,以及开发过程中最容易踩到的坑。
一、Qt国际化原理
Qt翻译机制如下:
text
源代码
↓
tr()
↓
ts文件
↓
Qt Linguist翻译
↓
qm文件
↓
QTranslator加载
↓
界面显示目标语言
例如:
python
self.setWindowTitle(self.tr("登录"))
中文环境显示:
text
登录
英文环境显示:
text
Login
Qt会自动根据当前加载的翻译文件进行替换。
二、纯代码开发如何支持翻译
错误写法
很多项目直接这样写:
python
self.setWindowTitle("登录")
button.setText("确定")
menu.addMenu("文件")
这种写法Qt无法提取翻译内容。
正确写法
必须使用:
python
self.setWindowTitle(self.tr("登录"))
button.setText(self.tr("确定"))
menu.addMenu(self.tr("文件"))
Label:
python
label.setText(self.tr("用户名"))
ComboBox:
python
combo.addItem(self.tr("自动模式"))
只有被 tr() 包裹的文本才会被Qt Linguist扫描到。
三、使用Qt Designer怎么办
很多项目都是:
text
Qt Designer
↓
.ui
↓
pyside6-uic
↓
ui_xxx.py
Designer中直接填写中文
例如:
按钮:
text
登录
标签:
text
用户名
菜单:
text
文件
保存:
text
login.ui
转换Python代码
执行:
bash
pyside6-uic login.ui -o ui_login.py
生成:
python
self.pushButton.setText(QCoreApplication.translate("MainWindow", "登录", None))
Qt已经自动帮我们做好翻译支持。
因此:
使用Qt Designer时不需要自己手工加tr()
Designer会自动生成translate代码。
四、Qt Designer项目如何生成翻译文件
假设项目结构:
text
project
│
├─ ui
│ ├─ login.ui
│ ├─ main.ui
│
├─ translations
│
├─ main.py
└─ ui_login.py
方法1:扫描UI文件
bash
pyside6-lupdate ui/*.ui -ts translations/zh_CN.ts
生成:
text
zh_CN.ts
方法2:扫描整个项目(推荐)
bash
pyside6-lupdate . -ts translations/zh_CN.ts
自动扫描:
text
.py
.ui
所有文件。
大型项目推荐这种方式。
五、Qt Linguist完整使用流程
第一步:打开Qt Linguist
命令:
bash
pyside6-linguist
或者:
bash
linguist
第二步:打开ts文件
菜单:
text
File
↓
Open
选择:
text
translations/zh_CN.ts
第三步:开始翻译
左侧:
text
Source Text
显示原始文本。
例如:
text
文件
右侧:
text
Translation
填写:
text
File
例如:
text
打开
翻译:
text
Open
例如:
text
退出
翻译:
text
Exit
例如:
text
用户管理
翻译:
text
User Management

第四步:标记完成
翻译后:
text
Ctrl + Enter
或者点击:
text
Done
第五步:全部翻译完成
查看左侧:
text
Finished
确认全部完成。
第六步:发布翻译
菜单:
text
File
↓
Release
或者执行:
bash
pyside6-lrelease translations/zh_CN.ts
生成:
text
translations/zh_CN.qm
六、ts和qm区别
很多新手容易搞混。
ts
text
翻译源文件
可以编辑。
qm
text
编译后的翻译文件
程序运行时加载。
例如:
text
translations
├─ zh_CN.ts
└─ zh_CN.qm
程序加载的是:
text
zh_CN.qm
不是:
text
zh_CN.ts
七、加载翻译文件
主程序:
python
translator = QTranslator()
加载:
python
translator.load("translations/en_US.qm")
安装:
python
app.installTranslator(translator)
八、实现中英文切换
菜单:
python
setting.addAction(self.tr("切换中英文"))
响应:
python
elif q.text() == self.tr("切换中英文"):
self.switch_language()
实现:
python
def switch_language(self):
global translator,current_language
app = QApplication.instance()
if current_language == "zh_CN":
app.removeTranslator(translator)
translator.load("translations/en_US.qm")
app.installTranslator(translator)
current_language = "en_US"
else:
app.removeTranslator(translator)
current_language = "zh_CN"
self.refresh_ui()
九、为什么切换语言没效果
最常见原因:
代码写死。
例如:
python
menu.addMenu("文件")
切换语言后仍然显示:
text
文件
正确写法:
python
menu.addMenu(self.tr("文件"))
十、为什么ts文件是空的
例如:
python
button.setText("登录")
执行:
bash
pyside6-lupdate .
生成:
xml
<TS version="2.1">
</TS>
空文件。
原因:
没有使用:
python
self.tr()
正确:
python
button.setText(self.tr("登录"))
重新执行:
bash
pyside6-lupdate .
即可提取。
十一、Designer界面翻译无效
很多人遇到:
python
app.installTranslator(translator)
执行成功。
但是界面不变。
原因:
Designer生成界面后没有重新翻译。
解决方法:
python
def changeEvent(self,event):
if event.type() == QEvent.LanguageChange:
self.retranslateUi(self)
super().changeEvent(event)
这样收到:
python
QEvent.LanguageChange
后会自动刷新界面。


十二、多窗口项目如何处理
例如:
text
MainWindow
LoginWindow
SettingWindow
UserWindow
每个窗口都需要:
python
def changeEvent(self,event):
if event.type() == QEvent.LanguageChange:
self.retranslateUi(self)
super().changeEvent(event)
这样所有窗口都会同步刷新。
十三、为什么切换后闪退
很多项目这样实现:
python
def refresh_ui(self):
self.close()
self.main = MainWindow()
self.main.show()
切换语言:
text
关闭窗口
↓
重新创建窗口
↓
重新初始化资源
如果程序包含:
python
self.camera = Camera()
或者:
python
self.serial = Serial()
或者:
python
self.plc = PLC()
重新创建窗口时会再次初始化。
可能出现:
text
open device fail
text
serial open fail
text
PLC connect fail
十四、工业项目为什么更容易出问题
因为存在:
text
工业相机
PLC
串口
TCP连接
数据库连接
算法线程
消息队列
这些资源通常只能初始化一次。
错误流程:
text
切换语言
↓
重新创建MainWindow
↓
重新初始化所有资源
容易出现:
text
设备占用
线程异常
相机打开失败
PLC断开
串口冲突
十五、正确做法
推荐使用Qt官方方案:
text
QTranslator
↓
LanguageChange
↓
retranslateUi
只刷新界面文本。
不重建窗口。
优势:
text
相机不断流
PLC不断线
线程不停
数据库不断开
无闪屏
十六、推荐项目结构
text
project
│
├─ ui
│ ├─ login.ui
│ ├─ main.ui
│ ├─ setting.ui
│
├─ translations
│ ├─ zh_CN.ts
│ ├─ zh_CN.qm
│ ├─ en_US.ts
│ └─ en_US.qm
│
├─ main.py
├─ login.py
├─ setting.py
└─ resource.py
十七、推荐开发规范
所有显示文字:
python
self.tr("文件")
self.tr("登录")
self.tr("用户管理")
self.tr("系统设置")
不要直接写:
python
"文件"
"登录"
"用户管理"
统一管理:
python
translator
current_language
Designer界面:
python
retranslateUi()
动态刷新:
python
changeEvent()
十八、完整开发流程总结
text
Qt Designer设计界面
↓
保存.ui文件
↓
pyside6-uic生成Python代码
↓
所有文本使用tr()/translate
↓
pyside6-lupdate扫描项目
↓
生成ts文件
↓
Qt Linguist翻译
↓
生成qm文件
↓
QTranslator加载
↓
installTranslator
↓
LanguageChange
↓
retranslateUi
↓
界面实时切换语言
十九、常见问题汇总
| 问题 | 原因 | 解决方法 |
|---|---|---|
| ts文件为空 | 没有使用tr() | 使用self.tr() |
| qm加载失败 | 路径错误 | 检查translations目录 |
| 菜单不翻译 | 文本写死 | 使用self.tr() |
| Designer界面不翻译 | 未调用retranslateUi | 重写changeEvent |
| 多窗口不同步 | 子窗口未处理LanguageChange | 每个窗口实现changeEvent |
| 切换后闪退 | 重建窗口导致资源异常 | 使用LanguageChange机制 |
| 相机打开失败 | 设备重复初始化 | 不重建设备对象 |
| PLC断线 | 窗口重建 | 通信对象单例化 |
| 新增文本不翻译 | 未重新执行lupdate | 重新生成ts |
| 修改翻译无效 | 未执行lrelease | 重新生成qm |
二十、结语
Qt官方国际化方案已经非常成熟。对于小型项目,可以采用"切换语言后重建窗口"的方式快速实现;对于大型项目、工业软件、视觉检测软件、MES系统、设备上位机等,建议采用Qt官方推荐的 LanguageChange + retranslateUi() 机制,只刷新界面文本,不重新创建窗口和设备资源。
这样既能实现实时切换语言,又能避免设备断开、线程异常、界面闪烁等问题,能够满足绝大多数商业项目的国际化需求。