PyQt 翻译(国际化)极简讲解

目标:让软件可以切换中文、英文。

核心工具:

  1. tr():最常用
  2. QCoreApplication.translate()tr() 的底层真身

如果你软件不需要切换多语言,这整套东西你完全不用写。

1. 没有翻译是什么样子

普通代码,写死文字:

python 复制代码
from PyQt5.QtWidgets import *

class Win(QWidget):
    def __init__(self):
        super().__init__()
        btn = QPushButton("确定")  # 硬编码写死中文
        layout = QVBoxLayout(self)
        layout.addWidget(btn)

app = QApplication([])
w = Win()
w.show()
app.exec_()

问题:程序写死中文,想变成英文,必须改源码。

2. 第一步:给字符串打上「需要翻译标记」

Qt 的思路:不直接写死字符串,告诉 Qt:这个文字以后可以被替换成别的语言。

方式A:在QWidget/QObject类里面,用 self.tr("文字")

python 复制代码
class Win(QWidget):
    def __init__(self):
        super().__init__()
        btn = QPushButton(self.tr("确定"))   # ✅打上翻译标记
        layout = QVBoxLayout(self)
        layout.addWidget(btn)
  • self.tr("确定")
    • 如果没加载翻译文件:直接返回字符串 "确定",和原来一模一样。
    • 如果加载了英文翻译文件:返回 "OK"

tr() 只能在继承 QWidget / QObject 的类里面,有 self 才能调用。

方式B:不在类里面,没有 self,用底层函数 translate

比如全局函数、普通python类,没有self,不能用tr(),就要手动调用底层。

tr() 本质等价:

python 复制代码
# self.tr("确定")
QCoreApplication.translate("Win", "确定")

第一个参数:上下文名字(一般填类名),第二个:原始字符串。

示例全局位置使用:

python 复制代码
from PyQt5.QtCore import QCoreApplication

# 不在任何QWidget类里面
text = QCoreApplication.translate("Global", "确定")

一句话:

self.tr() = 简写,自动把当前类名当做第一个参数传给 translate()

translate() = 底层原始函数,没有self的时候用。

3. tr / translate 只是标记,本身不会自动翻译

非常关键:

只写 self.tr("确定"),程序不会自动变成英文!

tr 只是做标记,真正翻译效果,靠加载外部 .qm 文件

整个流程分 4 步:

  1. 代码中所有界面文字,用 tr() / translate() 包裹字面字符串。
  2. 工具扫描代码,提取所有被标记的文字,生成 .ts 文件(xml,翻译底稿)
  3. 人去编辑ts文件,写好对应的英文译文,编译输出 .qm(二进制翻译包)
  4. 程序运行时加载 qm 文件,此时 tr/translate 才输出翻译后的文字。

4. 演示加载翻译文件

有一个编译好的 en.qm(英文翻译包)

python 复制代码
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTranslator, QCoreApplication

app = QApplication([])

# 1. 创建翻译器对象
trans = QTranslator(app)
# 2. 加载翻译二进制文件
trans.load("en.qm")
# 3. 把翻译器安装到app,全局生效
app.installTranslator(trans)

# 现在 tr() 就会生效
class Win(QWidget):
    def __init__(self):
        super().__init__()
        btn = QPushButton(self.tr("确定"))
        layout = QVBoxLayout(self)
        layout.addWidget(btn)

w = Win()
w.show()
app.exec_()

加载 qm 之后:self.tr("确定") 返回 "OK"

不加载 qm:返回原始 "确定"

5. 重要硬性限制(踩坑最多)

tr / translate 只能接收写死的字面字符串,不能传变量!

❌错误,工具提取不到,翻译失效:

python 复制代码
s = "确定"
btn.setText(self.tr(s))

✅正确:

python 复制代码
btn.setText(self.tr("确定"))

原因:提取工具是静态扫描源码,看引号里面的字面内容;运行时的变量它看不到。

6. 命令行工具(生成ts、生成qm)

pyqt5 使用 pylupdate5

bash 复制代码
# 扫描py代码,生成翻译底稿 ts
pylupdate5 main.py -o my_en.ts

得到 my_en.ts,这是xml文本,交给 Qt Linguist 软件,一行行填译文。

填完译文后,生成二进制qm:

bash 复制代码
lrelease my_en.ts -o en.qm

把 en.qm 放到程序运行目录,代码中 load 它。

7. 什么时候用 translate,什么时候用 tr

场景 使用
在QWidget/QObject子类里面,有self self.tr("xxx")(优先)
普通函数、全局代码、普通Python类,没有self QCoreApplication.translate("上下文名","xxx")

8. 极简总结

  1. self.tr() 是给界面字符串加翻译标记;底层调用 QCoreApplication.translate(类名,文本)
  2. translate 是底层原始接口,无self的时候手动调用,第一个参数填上下文名称。
  3. 只写tr不会自动翻译,必须外部加载 .qm 翻译文件才会替换文字。
  4. 参数必须是写死字面字符串,不能传变量。
  5. 不需要多语言切换,完全不要碰这套API,直接写普通字符串。

各个 MainWindow 区分对照表

结合你的 .ui xml文件、pyuic5生成的Python代码

出现位置 写法 本质 含义说明
ui文件xml <class>MainWindow</class> <class>MainWindow</class> 字符串,翻译上下文context 给翻译工具pylupdate5用;生成代码_translate("MainWindow",...)第一个参数就取自这里;ts文件的<name>MainWindow</name>和它对应,和Python类无关
ui文件xml <widget class="QMainWindow" name="MainWindow"> name="MainWindow" 控件的objectName属性(字符串) Qt对象的名字,MainWindow.setObjectName("MainWindow")就是把这个值设置给窗口;用于findChild查找控件,信号槽auto连接
ui文件xml class="QMainWindow" class="QMainWindow" Qt内置C++类名 指明这个控件是Qt提供的主窗口类QMainWindow,不要和上面两个字符串混淆
Python函数形参 def setupUi(self, MainWindow): MainWindow Python变量,QMainWindow实例对象(QObject) 外部传进来真实窗口对象,是真正干活的Qt窗口实例,可以调用.resize().setCentralWidget()等Qt接口
Python函数形参 def retranslateUi(self, MainWindow): MainWindow Python变量,QMainWindow实例对象(QObject) 和上面是同一个对象,只是传到retranslateUi函数里用来设置标题等属性
Python代码 _translate("MainWindow", "MainWindow") 第一个参数 "MainWindow" 字面字符串,翻译context上下文 直接复制来自ui的<class>MainWindow</class>,用来在qm翻译库查表;固定写死,不受继承子类影响
Python代码 _translate("MainWindow", "MainWindow") 第二个参数 "MainWindow" 字面字符串,原始显示文本 窗口要显示的原始标题文本,对应ui里<property name="windowTitle"><string>MainWindow</string></string>
Python类名 class Ui_MainWindow(object): Ui_MainWindow Python普通类名 pyuic5自动生成的UI装配工具类,注意:是Ui_MainWindow,带Ui_前缀,和上面全部不是一回事!

重点摘录对应关系

  1. ui:<class>MainWindow</class> → 生成代码:_translate("MainWindow", ...)第一个参数字符串(翻译上下文)
  2. ui:name="MainWindow" → 生成代码:MainWindow.setObjectName("MainWindow")(设置Qt对象名字)
  3. ui:class="QMainWindow" → Qt系统类,Python中from PyQt5.QtWidgets import QMainWindow
  4. def setupUi(self, MainWindow): 里面的MainWindow:只是一个局部Python变量,接收外部传入的QMainWindow()实例。

举个改动例子帮你彻底分清

如果你在Qt Designer,把顶层窗口的 objectName 修改为MyWin

  • ui xml:<class>MyWin</class><widget class="QMainWindow" name="MyWin">
  • pyuic5重新生成后:
python 复制代码
def retranslateUi(self, MainWindow):
    _translate = QtCore.QCoreApplication.translate
    MainWindow.setObjectName("MyWin")
    MainWindow.setWindowTitle(_translate("MyWin", "MainWindow"))

注意:函数参数变量名依旧叫MainWindow(pyuic5生成的函数参数名字不会变),但是translate第一个参数字符串、setObjectName的值已经变成MyWin

极简记忆

  • 带引号 "MainWindow":大多是字符串,翻译上下文 / objectName名字;
  • 不带引号 MainWindow(函数参数):是Qt窗口对象实例;
  • QMainWindow:Qt库的类;
  • Ui_MainWindow:自动生成的UI装配工具类。

我这边没法直接生成带标注的图片文件,但我给你做文本可视化示意图 ,把 XML‑UI 和 Python 代码分段,用 【标注】直接贴在对应位置,复制就能看,效果等价图片标注。

① ui 文件(xml)可视化标注

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>   【标注1:翻译上下文context字符串,py代码 _translate("MainWindow",...)第一个参数来源】
 <widget class="QMainWindow" name="MainWindow">
<!--        ↑Qt系统类名        ↑【标注2:objectName对象名字符串;对应py MainWindow.setObjectName("MainWindow")】 -->
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>726</width>
    <height>592</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string> 【标注3:原始窗口标题文本,对应 _translate(..., "MainWindow")第二个参数】
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>490</x>
      <y>110</y>
      <width>93</width>
      <height>28</height>
     </rect>
    </property>
    <property name="text">
     <string>按钮</string> 【标注4:按钮原始文字,对应 _translate(..., "按钮")第二个参数】
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>726</width>
     <height>28</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

② pyuic5生成的python代码可视化标注

python 复制代码
class Ui_MainWindow(object):  #【标注A:UI装配工具类,普通Python object,不是QObject;前缀Ui_不要忽略】
    def setupUi(self, MainWindow): #【标注B:MainWindow 是函数局部变量!接收外部传进来真实QMainWindow窗口实例(QObject)】
        MainWindow.setObjectName("MainWindow") #【标注C:设置Qt对象objectName,来自ui name="MainWindow"】
        MainWindow.resize(726, 592)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(490, 110, 93, 28))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 726, 28))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow) #【标注D:把窗口实例继续传给retranslateUi】
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow): #【标注E:MainWindow仍然是那个QMainWindow窗口对象变量】
        _translate = QtCore.QCoreApplication.translate
        #                 ↓【标注F:第一个参数字符串context,取自ui <class>MainWindow</class>】
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        #                                              ↑【标注G:第二个参数原始文本,ui windowTitle字符串】
        #                 ↓【标注H:context上下文,固定字符串,不受子类继承影响】
        self.pushButton.setText(_translate("MainWindow", "按钮"))
        #                                              ↑【标注I:第二个参数原始文本,ui按钮text】

对应关系速查(把上面标注一一对应)

  1. ui【标注1】 → py【标注F】【标注H】:"MainWindow" 翻译上下文
  2. ui【标注2】 → py【标注C】:objectName
  3. ui【标注3】 → py【标注G】:窗口标题原始文字
  4. ui【标注4】 → py【标注I】:按钮原始文字
  5. py【标注B】【标注D】【标注E】:不带引号 MainWindow = Python变量,QMainWindow实例对象
  6. Ui_MainWindow【标注A】只是装配工具,不是Qt窗口

核心记忆:

  • 带双引号 "MainWindow":字符串(上下文/对象名/显示文字)
  • 不带引号 MainWindow:Python变量,Qt窗口实例对象
  • Ui_MainWindow:带Ui_前缀,普通object工具类
  • QMainWindow:Qt系统类
相关推荐
房开民5 天前
PyQt5 常用模块(对应Qt五大模块)
数据库·pyqt
懷淰メ9 天前
【AI赋能】基于PyQt+YOLO+DeepSeek水上漂浮物检测系统(详细介绍)
人工智能·yolo·目标检测·计算机视觉·pyqt·漂浮物·水上漂浮物
龙腾AI白云1 个月前
【多Agent系统的倒U型曲线与前瞻治理】
人工智能·plotly·pyqt·知识图谱
江畔柳前堤2 个月前
github实战指南01-账号配置与 SSH 密钥
运维·人工智能·深度学习·ssh·github·pyqt·信号处理
DrMaker2 个月前
【无标题】
软件测试·python·测试工具·pyqt
懷淰メ2 个月前
【AI赋能】基于PyQt+YOLO+DeepSeek的淋巴细胞检测系统(详细介绍)
yolo·计算机视觉·pyqt·课程设计·医疗·淋巴细胞·淋巴
懷淰メ2 个月前
【AI加持】基于PyQt+YOLO+DeepSeek的结直肠息肉检测系统(详细介绍)
yolo·目标检测·计算机视觉·pyqt·ai加持·直肠息肉·结直肠
懷淰メ2 个月前
【AI加持】基于PyQt+YOLO+DeepSeek的疟原虫检测系统(详细介绍)
人工智能·yolo·计算机视觉·pyqt·医疗·ai分析·疟原虫
石工记2 个月前
CTO如何落地AI?从0到1的实战路径
人工智能·python·django·flask·numpy·pandas·pyqt