玩转 Qt 国际化:如何正确使用 QTranslator 加载 .qm 文件

2025-11-23

在 Qt 框架中,QtTranslation 类是处理应用程序国际化和本地化(简称 i18n 和 l10n)的核心机制的一部分。

它的主要作用是

加载翻译文件 它负责加载由 Qt Linguist 工具生成的翻译文件(通常是 .qm 格式)。

查找和提供翻译 当应用程序中的代码调用 QObject 的 tr() 函数时,QtTranslation 实例会在加载的翻译文件中查找对应的字符串翻译,并将其返回给 tr()。

一个典型的 Qt 国际化流程是

标记字符串 使用 QObject::tr() 宏或函数标记需要翻译的字符串。

提取字符串 使用 lupdate 工具从源代码中提取这些字符串,生成 .ts 文件。

翻译 翻译人员使用 QtLinguist 工具编辑 .ts 文件。

编译 使用 lrelease 工具将 .ts 文件编译成二进制的 .qm 文件。

加载 在应用程序启动时,使用 QTranslator 类的实例加载 .qm 文件。

在使用 QTranslator 进行翻译加载时,新手开发者经常会遇到一些问题。

这是最常见的问题。应用程序运行时,界面仍然显示英文(或源代码中的原始字符串),没有任何翻译。

可能原因排除步骤/解决方案文件路径错误检查 QTranslator::load() 函数中使用的路径是否正确。.qm 文件通常应放在应用程序可执行文件同级目录下的一个子文件夹(例如 i18n 或 translations)中。文件名错误确保文件名与调用 load() 时使用的名称完全匹配。例如,如果文件是 myapp_zh_CN.qm,就要用此名称加载。没有编译 .qm 文件确保你运行了 lrelease 工具,并且 .ts 文件成功编译成了 .qm 文件。加载时机错误QTranslator 必须在创建任何需要翻译的 QObject 之前被加载,并在 QApplication 实例创建之后。请务必检查 QTranslator::load() 的返回值,它会告诉你文件是否成功加载。

#include

#include

#include

#include

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

// 1. 加载 Qt 内置的翻译文件 (可选, 用于翻译标准对话框)

QTranslator qtBaseTranslator;

// 搜索 Qt 内置翻译文件的标准路径 (根据你的 Qt 版本和安装目录可能会不同)

QString translationsPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);

if (qtBaseTranslator.load("qt_zh_CN", translationsPath)) {

a.installTranslator(&qtBaseTranslator);

qDebug() << "Loaded Qt base translations.";

} else {

qDebug() << "Failed to load Qt base translations.";

}

// 2. 加载应用程序自己的翻译文件 (最重要!)

QTranslator appTranslator;

// 假设你的翻译文件放在可执行文件同目录的 "i18n" 文件夹下

// myapp_zh_CN.qm 是你的翻译文件名

QString appTranslationPath = QCoreApplication::applicationDirPath() + "/i18n";

if (appTranslator.load("myapp_zh_CN", appTranslationPath)) {

// 成功加载后,必须安装到 QApplication 实例

a.installTranslator(&appTranslator);

qDebug() << "Loaded application translations.";

} else {

qDebug() << "Failed to load application translations. Path attempted: " << appTranslationPath;

}

// ... 应用程序的主窗口代码 ...

return a.exec();

}

你确信已经加载了 .qm 文件,但某些自定义组件的文本仍然没有被翻译。

可能原因排除步骤/解决方案没有使用 tr() 宏只有被 tr() 标记的字符串才会被 lupdate 工具提取,才能被翻译。检查未翻译的字符串是否在 QObject 派生类的方法中,并使用 tr()。tr() 调用位置错误tr() 必须在一个继承自 QObject 的类中调用,否则 lupdate 无法正确关联上下文(Context)。上下文不匹配即使使用了 tr(),如果原始代码中字符串的 Context(上下文,即类名)在 lupdate 后被修改,翻译文件中的 Context 可能会失效。// good_widget.h

#include

#include

class GoodWidget : public QWidget

{

Q_OBJECT // QObject 派生类是使用 tr() 的前提

public:

explicit GoodWidget(QWidget *parent = nullptr) : QWidget(parent)

{

// 正确:在 QObject 派生类中使用 tr()

QPushButton *button = new QPushButton(tr("Click Me"), this);

}

void updateStatus()

{

// 即使在成员函数中,也使用 tr()

qDebug() << tr("Status updated successfully.");

}

};

// ---

// bad_example.cpp

void setupUi()

{

// 错误:在非 QObject 派生类或全局函数中使用 tr()

// lupdate 会把 Context 设为 "default",这在大型项目中容易混乱和冲突。

// 应在 QObject 派生类中调用。

// QPushButton *button = new QPushButton(tr("Click Me Again"));

}

QTranslator 的一个主要替代(或说高级)用法是如何在运行时动态切换应用程序的语言,而不是在程序启动时固定。

实现动态切换的关键是

卸载旧的 QTranslator。

加载新的 QTranslator。

重新翻译 UI 界面。

动态切换需要一个关键的步骤发送事件通知所有 UI 控件重新翻译自己。在 Qt 中,控件会在收到 QEvent::LanguageChange 事件时自动调用自己的 retranslateUi() 或重新设置文本。

#include

#include

#include

#include

// 保持 QTranslator 实例,以便随时卸载/安装

static QTranslator *s_appTranslator = nullptr;

// 切换语言的函数

void setLanguage(QApplication &app, const QString &localeName)

{

// 1. 卸载旧的翻译器(如果有的话)

if (s_appTranslator) {

app.removeTranslator(s_appTranslator);

delete s_appTranslator;

s_appTranslator = nullptr;

}

// 2. 加载新的翻译器

QTranslator *newTranslator = new QTranslator(&app);

// 文件名例如: myapp_en_US.qm, myapp_fr_FR.qm

QString fileName = QString("myapp_%1").arg(localeName);

QString appTranslationPath = QCoreApplication::applicationDirPath() + "/i18n";

if (newTranslator->load(fileName, appTranslationPath)) {

app.installTranslator(newTranslator);

s_appTranslator = newTranslator;

qDebug() << "Successfully switched to language:" << localeName;

} else {

delete newTranslator; // 加载失败,释放内存

qWarning() << "Failed to load translation file for:" << localeName;

}

// 3. 关键步骤:发送 QEvent::LanguageChange 事件

// 这将强制所有窗口部件重新加载它们的 tr() 字符串。

QEvent languageChangeEvent(QEvent::LanguageChange);

app.sendEvent(&app, &languageChangeEvent);

// 如果你有自定义的主窗口,可能需要调用它的 retranslateUi()

// 或重新设置标题/文本

// mainWindow->setWindowTitle(QObject::tr("My Application"));

}

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

s_appTranslator = new QTranslator(&a); // 初始化静态指针

// 初始加载系统默认语言

setLanguage(a, QLocale::system().name());

// ... QMainWindow mainWin; mainWin.show();

// 假设用户点击了 "切换到法语" 按钮

// setLanguage(a, "fr_FR"); // 在某个槽函数中调用

return a.exec();

}