QT利用tr实现翻译
1. 目的
代码中待翻译文本(如tr()/QCoreApplication::translate/宏内文本/动态库文本)更新到.ts翻译文件的操作流程,确保所有待翻译文本被lupdate工具识别并纳入翻译管理。
2. 适用场景
- 主程序代码(含QObject类/无QObject类)新增翻译文本;
- 动态库(DLL/so)新增翻译文本;
3. 前置工具
- Qt Linguist工具集(核心:
lupdate.exe生成.ts、lrelease.exe编译.qm);- Qt5.10(安装的QT开发程序)
- 文本编辑器/linguist.exe(用于编辑.ts文件)

一、前置准备
1. 代码规范(必遵守)
新增待翻译文本需按以下规则标记,否则lupdate无法识别:
| 场景 | 标记方式 |
|---|---|
| QObject子类 | 直接用tr("待翻译文本")(上下文默认是类名) |
| 无QObject类/全局函数 | QCoreApplication::translate("上下文", "待翻译文本") + 可选QT_TR_NOOP("待翻译文本") |
| 宏内文本(暂无法处理) | 拆分QT_TRANSLATE_NOOP("上下文", "待翻译文本")为独立宏,避免嵌套在translate参数中(5.10,5.13版本lupdate验证未生效) |
宏内部翻译文本处理方式

代码示例
//QtWidgetsApplication1.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication1.h"
#include <QObject> // 必须包含,QT_TRANSLATE_NOOP依赖此头文件
class CDefineTextTranslate :public QObject
{
Q_OBJECT
private:
CDefineTextTranslate();
public:
static CDefineTextTranslate* getCDefineTextTranslateInstance();
static CDefineTextTranslate* mInstance;
const QString m_MSG_CODE_ERROR_str;
};
class QtWidgetsApplication1 : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication1(QWidget* parent = nullptr);
~QtWidgetsApplication1();
private:
Ui::QtWidgetsApplication1Class ui;
};
// 带参数的宏定义
#define MSG_CODE_ERROR(code) \
CDefineTextTranslate::getCDefineTextTranslateInstance()->m_MSG_CODE_ERROR_str.arg(code)
//QtWidgetsApplication1.cpp
#include "QtWidgetsApplication1.h"
#include<qmutex.h>
CDefineTextTranslate::CDefineTextTranslate() :
m_MSG_CODE_ERROR_str(tr("1231231 %1 xdgdfg"))
{
}
CDefineTextTranslate* CDefineTextTranslate::getCDefineTextTranslateInstance()
{
static QMutex mutex;
if (!mInstance) {
QMutexLocker lock(&mutex);
if (!mInstance)
mInstance = new CDefineTextTranslate;
}
return mInstance;
}
CDefineTextTranslate* CDefineTextTranslate::mInstance = nullptr;
QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
: QMainWindow(parent)
{
//g_pCDefineTextTranslate = new CDefineTextTranslate;
ui.setupUi(this);
ui.label->setText(MSG_CODE_ERROR(502));
QString Text2 = tr("12314134");
ui.label_2->setText(Text2);
}
QtWidgetsApplication1::~QtWidgetsApplication1()
{
}
//main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include <QTranslator>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// load translat language
QTranslator translator;
QString qmPath = "D:/workdir/code/Test/QtWidgetsApplication1/QtWidgetsApplication1/en_US.qm";
if (translator.load(qmPath))
{
app.installTranslator(&translator);
}
QtWidgetsApplication1 window;
window.show();
return app.exec();
}
2. 环境检查
-
确保
lupdate.exe在系统环境变量中(或使用完整路径,如C:\Qt\5.10.0\msvc2015_64\bin\lupdate.exe); -
待翻译文件编码统一为UTF-8(避免中文乱码)。
二、核心操作流程
步骤1:标记新增翻译文本
同前置准备
步骤2:执行lupdate命令(显式指定扫描文件/目录)
.ts文件会记录翻译文本所在行数,需要每次编辑完代码后实时更新,直接通过命令行执行
C:\Qt\Qt5.10.0\5.10.0\msvc2015_64\bin\lupdate.exe "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\.." "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\..\include" -ts "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\en_US.ts",将所有包含新增翻译文本的文件/目录,生成.ts文件:

生成成功:

生成到源码目录下

lupdate命令说明
| 子场景 | 命令示例(Windows) | 说明 |
|---|---|---|
| 扫描单个/多个文件 | lupdate D:\MyApp\MainWindow.cpp D:\MyApp\MacroDefs.h -ts D:\MyApp\translations\all_lang.ts | 精准扫描指定文件 |
| 递归扫描目录 | C:\Qt\Qt5.10.0\5.10.0\msvc2015_64\bin\lupdate.exe "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\.." "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\..\include" -ts "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\en_US.ts" | 扫描目录下所有.h/.cpp |
| 路径含空格/中文 | lupdate "D:\我的项目\MainWindow.cpp" -ts "D:\我的项目\translations\all_lang.ts" | 路径用双引号包裹 |
| 指定编码 | lupdate D:\MyApp -recursive -codecfortr UTF-8 -ts D:\MyApp\translations\all_lang.ts | 强制UTF-8扫描,避免乱码 |
| 排除第三方文件(Qt5.15+) | lupdate D:\MyApp -recursive -exclude D:\MyApp\third_party -ts D:\MyApp\translations\all_lang.ts | 跳过无需翻译的目录 |
三、编辑翻译.ts文件
执行lupdate后,需验证新增文本是否被正确识别:
- 打开生成的
.ts文件(用Qt Linguist/文本编辑器); - 检查「上下文」列是否包含新增文件
- 上下文下方是否列出新增的源文本(如「新增按钮」「宏内新增文本」);

或者有条件直接使用python脚本增量生成新的翻译文件

python脚本
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
TS文件翻译脚本
使用百度翻译API自动翻译TS文件中的中文文本
"""
import xml.etree.ElementTree as ET
import http.client
import hashlib
import urllib.parse
import random
import json
import time
import os
class BaiduTranslator:
def __init__(self, appid, secret_key, domain='it'):
self.appid = appid
self.secret_key = secret_key
self.domain = domain
self.api_url = '/api/trans/vip/fieldtranslate'
def translate(self, text, from_lang='auto', to_lang='en'):
"""翻译单个文本"""
if not text.strip():
return text
salt = random.randint(32768, 65536)
sign = self.appid + text + str(salt) + self.domain + self.secret_key
sign = hashlib.md5(sign.encode()).hexdigest()
url = (f"{self.api_url}?appid={self.appid}&q={urllib.parse.quote(text)}"
f"&from={from_lang}&to={to_lang}&salt={str(salt)}"
f"&domain={self.domain}&sign={sign}")
try:
http_client = http.client.HTTPConnection('api.fanyi.baidu.com')
http_client.request('GET', url)
response = http_client.getresponse()
result_all = response.read().decode("utf-8")
result = json.loads(result_all)
if 'trans_result' in result:
return result['trans_result'][0]['dst']
else:
print(f"翻译失败: {result}")
return text
except Exception as e:
print(f"翻译请求出错: {e}")
return text
finally:
if 'http_client' in locals():
http_client.close()
class TSTranslator:
def __init__(self, translator):
self.translator = translator
self.translated_count = 0
def parse_ts_file(self, file_path):
"""解析TS文件"""
try:
tree = ET.parse(file_path)
root = tree.getroot()
return tree, root
except ET.ParseError as e:
print(f"解析XML文件失败: {e}")
return None, None
def needs_translation(self, message):
"""检查message是否需要翻译"""
source = message.find('source')
translation = message.find('translation')
if source is None or translation is None:
return False
source_text = source.text or ""
translation_text = translation.text or ""
translation_type = translation.get('type', '')
# 需要翻译的条件:source有中文内容,且translation为空或标记为unfinished
has_chinese = any('\u4e00' <= char <= '\u9fff' for char in source_text)
needs_trans = (not translation_text.strip() and
(translation_type == 'unfinished' or not translation_type))
return has_chinese and needs_trans
def translate_ts_file(self, input_file, output_file=None):
"""翻译TS文件"""
if output_file is None:
output_file = input_file.replace('.ts', '_translated.ts')
tree, root = self.parse_ts_file(input_file)
if not tree:
return False
total_to_translate = 0
translated_count = 0
# 统计需要翻译的数量
for context in root.findall('context'):
for message in context.findall('message'):
if self.needs_translation(message):
total_to_translate += 1
print(f"发现 {total_to_translate} 个需要翻译的文本")
# 开始翻译
for context in root.findall('context'):
for message in context.findall('message'):
if self.needs_translation(message):
source = message.find('source')
translation = message.find('translation')
source_text = source.text
print(f"翻译: '{source_text}'")
# 调用翻译API
translated_text = self.translator.translate(source_text)
# 更新translation标签
translation.text = translated_text
if 'type' in translation.attrib and translation.attrib['type'] == 'unfinished':
del translation.attrib['type']
translated_count += 1
print(f"进度: {translated_count}/{total_to_translate} - {source_text} -> {translated_text}")
# 添加延迟避免API限制
time.sleep(0.1)
# 保存翻译后的文件
tree.write(output_file, encoding='utf-8', xml_declaration=True)
print(f"翻译完成! 共翻译 {translated_count} 个文本")
print(f"输出文件: {output_file}")
return True
def main():
# 配置百度翻译API
appid = '1231' # 请替换为您的appid
secret_key = 'OqqwzEDtqk3NN5' # 请替换为您的secret key
if appid == 'your_appid_here' or secret_key == 'your_secret_key_here':
print("请先配置百度翻译API的appid和secret key")
return
# 创建翻译器实例
translator = BaiduTranslator(appid, secret_key, domain='it')
ts_translator = TSTranslator(translator)
# 输入文件路径
input_file = 'en_US.ts' # 请替换为您的TS文件路径
output_file = 'en_USout.ts' # 输出文件路径
if not os.path.exists(input_file):
print(f"输入文件不存在: {input_file}")
return
# 执行翻译
ts_translator.translate_ts_file(input_file, output_file)
if __name__ == '__main__':
main()
四、后续操作
-
编译.qm文件:将生成.qm的命令添加到工程中的后期生成事件,编译代码会自动编译.qm文件,生成到可执行文件目录下的language目录下保证运行时可以加载.qm文件,一定要有编译过程才会执行后期生成事件的命令行


-
加载.qm文件:主程序/动态库启动时加载.qm(动态库需独立
QTranslator,保证生命周期)。实时的切换语言过于麻烦,子窗口都需要重写相应界面刷新函数(所有控件都需要刷新,繁琐工程量大),切换语言后重启程序能够100%保证所有界面都加载翻译器
//main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include <QTranslator>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// load translat language
QTranslator translator;
QString qmPath = "D:/workdir/code/Test/QtWidgetsApplication1/QtWidgetsApplication1/en_US.qm";
if (translator.load(qmPath))
{
app.installTranslator(&translator);
}
QtWidgetsApplication1 window;
window.show();
return app.exec();
}
五、常见问题与避坑指南
1. lupdate未识别新增文本
| 问题原因 | 解决方法 |
|---|---|
| 未指定扫描文件/目录 | 命令行显式指定文件路径 |
| 路径含空格/中文未加引号 | 所有路径用双引号包裹(如"D:\我的项目\MainWindow.cpp") |
2. 中文乱码
-
执行
lupdate时添加-codecfortr UTF-8 -codecforsrc UTF-8参数; -
确保所有代码文件编码为UTF-8(无BOM)。
3. 动态库翻译文本未识别
- 确保动态库源码文件被
lupdate扫描(显式指定路径); - 修改动态库源码会改变翻译文本位置,导致与.ts中标记的翻译位置对不上需要动态库作者提供翻译.ts文件。

4. 翻译后文本不生效
-
检查
QCoreApplication::translate的上下文与.ts中一致(大小写/符号无差异); -
确保
QTranslator为全局/成员变量(非局部变量,避免销毁),或者在主函数中保证程序运行过程中不会释放对象内存; -
验证.qm文件路径正确(用
QCoreApplication::applicationDirPath()拼接绝对路径)。
六、总结
新增翻译文本更新到.ts文件的核心流程可归纳为:
-
规范标记:按场景选择
tr()/与宏的处理方式; -
扫描文件:命令行执行lupdate指定扫描路径;
-
验证结果:检查.ts文件是否包含新增文本及对应上下文;
-
编译加载:翻译.ts后编译为.qm,主程序/动态库加载.qm生效。



被折叠的 条评论
为什么被折叠?



