Qt多语言核心是tr()标记→lupdate提取.ts→lrelease编译.qm→QTranslator查表的协作链路;关键在流程完整、路径正确、上下文不冲突,而非编写翻译逻辑。

Qt 多语言不是“写个翻译程序”,而是搭建一套 tr() 标记 + .ts 提取 + .qm 加载 + QTranslator 查表的协作链路。真正要写的代码极少,关键在流程不漏环节、路径不写错、上下文不冲突。
tr() 必须用对:不是所有字符串都能被翻译
只有继承自 QObject 的类里直接调用 tr("xxx") 才有效;非 QObject 类(比如纯数据结构、工具函数)必须显式写 QObject::tr("xxx"),否则 lupdate 扫不出来。
- ✅ 正确:
ui->label->setText(tr("Save"));(MainWindow是QObject派生类) - ❌ 无效:
QString s = "Save"; ui->label->setText(s);(没走tr(),完全不会进翻译流程) - ⚠️ 易错:UI 文件(
.ui)里的文字默认不进tr()—— 必须在 Qt Designer 中勾选「Translatable」属性,或手动在ui_*.h生成代码里补上tr()(推荐前者) - ⚠️ 消歧义必须显式传参:
tr("File", "menu item")和tr("File", "verb")在.ts里是两条独立条目,漏写disambiguation会导致翻译错位
lupdate 生成 .ts 文件失败的常见原因
lupdate 不是编译器,它只做静态文本扫描。它看不到运行时拼接的字符串,也认不出宏展开后的字面量。
- ❌ 不支持变量:
QString key = "Open"; tr(key.toUtf8());→lupdate完全忽略 - ❌ 不支持宏定义:
#define MSG "Exit" ... tr(MSG)→ 多数 Qt 版本(尤其 Qt 6.5+)默认不展开宏,需在.pro或CMakeLists.txt中加CONFIG += linguist_resource或等效配置 - ✅ 必须确保
.pro里声明了源文件:SOURCES += main.cpp mainwindow.cpp,否则lupdate不知道扫哪些文件 - ✅ 建议加注释提示翻译者:
tr("OK") // Button label, confirm action,lupdate会把注释提取进.ts的节点
QTranslator::load() 返回 true 却不生效?检查这三处
load() 成功只代表文件读取和解析无误,不代表翻译已生效。真正起作用的是安装顺序和对象生命周期。
- ❌ 局部创建:
{ QTranslator t; t.load("zh_CN.qm"); qApp->installTranslator(&t); }→t出作用域即析构,翻译器失效 - ❌ 安装太晚:
QApplication a(argc, argv); MainWindow w; w.show(); QTranslator t; t.load("zh_CN.qm"); a.installTranslator(&t);→ 窗口已构建完成,内部控件文本早已调用过tr()并缓存为原文,不会自动重刷 - ✅ 正确时机:在
main()中QApplication构造后、任何窗口创建前安装;切换语言时,先removeTranslator(),再load()+installTranslator(),最后调用w->retranslateUi(w)或触发changeEvent(QEvent::LanguageChange) - ✅ 路径别硬编码:
t.load("zh_CN.qm")默认找当前工作目录;生产环境建议用t.load("zh_CN.qm", ":/i18n")(资源路径)或t.load("zh_CN.qm", QApplication::applicationDirPath() + "/translations")
中文乱码、英文显示方块?编码与字体才是真瓶颈
.qm 文件本身是 UTF-8 编码,但最终渲染依赖系统字体是否支持对应字符集。Qt 不负责字体 fallback,只负责把翻译后的字符串交给控件绘制。
- ❌ Windows 上默认中文字体(如 SimSun)在英文界面下可能缺失,导致中文显示为方块;需显式设置字体:
qApp->setFont(QFont("Microsoft YaHei", 9)); - ❌ Linux 下未安装中文字体(如
fonts-wqy-zenhei),即使.qm正确加载,QLabel仍画不出汉字 - ✅ 验证是否真乱码:在
.ts文件里直接查看内容是否为合法 UTF-8 中文(用 VS Code 或 Notepad++ 以 UTF-8 无 BOM 打开);若 XML 里已是乱码,说明编辑时保存编码错了 - ✅ Qt 6 起默认禁用
QTextCodec::setCodecForLocale(),不要在代码里手动设 GBK/GB2312 —— 这只会让tr()解析源码字符串时出错
最常被忽略的点:翻译生效 ≠ 文本刷新。哪怕 QTranslator 加载成功、tr() 查表命中,控件也不会自动重绘自身文本。必须显式通知 UI 层“语言变了”,靠 retranslateUi() 或 changeEvent() 触发,否则你看到的永远是启动那一刻的语言快照。











