Qt实现多语言原理和实践详解

目录

1.简介

2.QTranslator说明

3.语言文件制作

3.1.前置条件

3.2.完整制作流程

4.多语言示例

5.关键注意事项

5.1.tr()的正确使用

[5.2.将 .qm 嵌入资源文件(避免外置)](#5.2.将 .qm 嵌入资源文件(避免外置))

[5.3.翻译 Qt 内置控件文本(如 QMessageBox)](#5.3.翻译 Qt 内置控件文本(如 QMessageBox))

5.4.批量处理多语言文件(脚本化)

6.总结


1.简介

在 Qt 中,QTranslator是实现多语言切换的核心类,它通过加载预编译的翻译文件(.qm),将程序中标记的字符串替换为目标语言。

实现原理:

1.关键类与工具

  • QTranslator:加载.qm翻译文件,提供字符串翻译映射。
  • QCoreApplication::installTranslator():为应用安装翻译器,使tr()标记的字符串被翻译。
  • lupdate:从代码中提取待翻译字符串,生成.ts(XML 格式)源文件。
  • Qt Linguist:可视化翻译工具,编辑.ts文件并保存。
  • lrelease:将翻译完成的.ts编译为二进制.qm文件(程序运行时加载)。

2.核心逻辑

  • tr()包裹所有需要翻译的字符串(tr()会关联当前类的 "上下文",确保翻译准确)。
  • 通过工具链生成并编译翻译文件。
  • 程序启动 / 切换语言时,加载对应语言的.qm文件,安装到应用中,并刷新界面文本。

2.QTranslator说明

1.load()

load()QTranslator 最核心的接口,用于加载 .qm 文件,返回 booltrue 表示加载成功)。所有重载均支持本地路径、资源路径(:/xxx.qm)。

重载签名 功能说明 参数解析 典型场景
bool load(const QString &fileName, const QString &directory = QString(), const QString &searchDelimiters = QString(), const QString &suffix = QString()) 加载指定路径的 .qm 文件 - fileName:文件名(可含后缀,如 zh_CN.qm);- directory:文件所在目录(可选,为空则使用当前工作目录);- searchDelimiters:搜索分隔符(极少用,默认空);- suffix:文件后缀(默认 .qm 加载本地 / 资源文件系统中的自定义 .qm(最常用)
bool load(const QLocale &locale, const QString &baseName, const QString &prefix = QString(), const QString &directory = QString(), const QString &suffix = QString()) 按区域设置自动匹配翻译文件 - locale:目标区域(如 QLocale::Chinese/QLocale("en_US"));- baseName:文件名前缀(如 app);- 其他参数同上 自动匹配系统 / 指定区域的翻译文件(如 baseName=app + locale=zh_CN → 加载 app_zh_CN.qm
bool load(const QByteArray &data, const QString &fileName = QString()) 从内存字节数组加载翻译数据 - data.qm 文件的二进制数据;- fileName:标识名(仅用于日志,无实际加载作用) 加载网络下载 / 内存缓存的 .qm 数据
bool load(QLibraryInfo::LibraryLocation location, const QString &fileName, const QString &prefix = QString(), const QString &suffix = QString()) 加载 Qt 内置翻译文件(Qt6 新增) - location:Qt 库路径(如 QLibraryInfo::TranslationsPath,指向 Qt 内置翻译文件目录);- 其他参数同上 加载 Qt 自带控件的翻译文件(如 qt_zh_CN.qm

关键说明

  • 加载失败原因:文件不存在、路径错误、.qm 损坏、Qt 版本不兼容(如 Qt5 编译的 .qm 无法在 Qt6 加载);
  • 资源文件加载:路径以 :/ 开头(如 translator.load(":/translations/zh_CN.qm"))。

示例:

cpp 复制代码
QTranslator trans;
// 方式1:加载本地文件
trans.load("translations/zh_CN.qm");
// 方式2:加载资源文件
trans.load(":/translations/en_US.qm");
// 方式3:按QLocale加载(自动匹配zh_CN)
trans.load(QLocale::Chinese, "app", "_", "translations"); // 加载 translations/app_zh_CN.qm
// 方式4:加载Qt内置翻译文件(Qt6)
QTranslator qtTrans;
qtTrans.load(QLibraryInfo::TranslationsPath, "qt", "_", "zh_CN"); // 加载 qt_zh_CN.qm

2.翻译字符串(核心:translate() 系列)

translate() 是翻译的核心接口,QObject::tr() 底层会调用当前安装的翻译器的 translate() 方法。返回翻译后的字符串,无匹配时返回源文本。

重载签名 功能说明 参数解析
QString translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1) const 核心翻译接口(支持普通 / 消歧 / 复数翻译) - context:上下文(tr() 默认为当前类名,如 MainWindow);- sourceText:待翻译的源文本;- disambiguation:消歧符(区分相同源文本的不同含义,如 "Close" 可指 "关闭窗口"/"关闭文件");- n:复数计数(-1 表示非复数,≥0 时处理复数形式)
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n, const QString &locale) const(Qt6) 指定区域的翻译(极少用) 新增 locale:目标区域编码(如 "zh_CN"

关键说明

  • 上下文一致性:context 必须与 lupdate 提取的上下文(.ts 中的上下文)一致,否则翻译失效;
  • 复数处理:n 为计数时,需配合 .ts 中复数规则(如 %n file(s) 翻译为 "1 个文件"/"5 个文件");
  • 消歧符:同一源文本在不同场景有不同翻译时使用(如 tr("Close", "Window") vs tr("Close", "File"))。

示例:

cpp 复制代码
QTranslator trans;
trans.load("translations/zh_CN.qm");

// 普通翻译(上下文Global,源文本"OK")
QString okText = trans.translate("Global", "OK"); // 输出"确定"

// 带消歧符的翻译
QString closeWin = trans.translate("Global", "Close", "Window"); // "关闭窗口"
QString closeFile = trans.translate("Global", "Close", "File"); // "关闭文件"

// 复数翻译
QString file1 = trans.translate("Global", "%n file(s)", nullptr, 1); // "1个文件"
QString file5 = trans.translate("Global", "%n file(s)", nullptr, 5); // "5个文件"

3.翻译器管理接口(父翻译器)

支持设置 "父翻译器",当前翻译器无匹配的翻译时,自动回退到父翻译器查找,实现翻译兜底。

接口签名 功能说明 使用场景
void setParentTranslator(QTranslator *parent) 设置父翻译器 主翻译器 + 兜底翻译器(如 Qt 内置翻译器作为父翻译器)
QTranslator *parentTranslator() const 获取当前父翻译器 检查 / 修改父翻译器配置

示例:

cpp 复制代码
// 自定义应用翻译器(业务文本)
QTranslator appTrans;
appTrans.load("app_zh_CN.qm");

// Qt内置翻译器(Qt控件文本,如QMessageBox的"Cancel")
QTranslator qtTrans;
qtTrans.load("qt_zh_CN.qm", QLibraryInfo::path(QLibraryInfo::TranslationsPath));

// 设置父翻译器:appTrans查不到时,自动用qtTrans翻译
appTrans.setParentTranslator(&qtTrans);

// 仅安装appTrans即可,自动兜底到qtTrans
qApp->installTranslator(&appTrans);

4.辅助功能接口

接口签名 功能说明 适用版本 使用场景
bool isEmpty() const 判断翻译器是否加载了有效翻译数据 Qt5+ 检查 .qm 是否加载成功(补充 load() 返回值)
void clear() 清空翻译器中所有已加载的翻译数据 Qt5+ 切换语言前清空旧翻译数据
QString language() const 返回翻译文件的目标语言编码(如 "zh_CN"/"en_US" Qt6.2+ 识别当前翻译器的语言(Qt5 需自行解析 .qm 文件名)
QStringList translations() const 返回所有已加载的翻译条目(源文本列表) Qt6+ 调试翻译数据,确认是否包含目标字符串

示例:

cpp 复制代码
QTranslator trans;
trans.load("zh_CN.qm");

if (trans.isEmpty()) {
    qDebug() << "翻译文件加载为空!";
} else {
    qDebug() << "当前翻译语言:" << trans.language(); // Qt6+输出"zh_CN"
    qDebug() << "翻译条目数:" << trans.translations().size(); // Qt6+
}

// 清空翻译数据
trans.clear();

3.语言文件制作

Qt 语言文件制作是实现多语言的核心环节,核心产物是 .ts(翻译源文件,XML 格式).qm(编译后的二进制文件,程序运行加载)

3.1.前置条件

  • 安装 Qt 开发环境(含 lupdatelrelease 工具和 Qt Linguist 可视化翻译工具);
  • 代码中已用 tr()/QCoreApplication::translate() 标记所有待翻译字符串(需确保类继承 QObject 并添加 Q_OBJECT 宏)。

3.2.完整制作流程

1.项目配置(.pro 文件)

在项目的 .pro 文件中声明 TRANSLATIONS 变量,指定要生成的 .ts 文件路径(关键:lupdate 会根据此列表生成 / 更新 .ts)。

cpp 复制代码
QT += core gui widgets

# 源码/头文件(示例)
SOURCES += main.cpp mainwindow.cpp
HEADERS += mainwindow.h

# 声明翻译文件(建议放在translations子目录,需手动创建)
TRANSLATIONS += translations/zh_CN.ts \
                translations/en_US.ts \
                translations/ja_JP.ts

# 可选配置(Qt5.11+)
CONFIG += lrelease  # 构建项目时自动编译.ts为.qm
CONFIG += embed_translations  # 将.qm嵌入程序(无需外置文件)

注意:若未加 CONFIG += lrelease,需手动执行 lrelease 编译 .qm

2.提取字符串生成 .ts 文件

lupdate 工具会扫描代码中 tr() 标记的字符串,生成 / 更新 .ts 文件(XML 格式,可直接用文本编辑器打开,但推荐用 Qt Linguist 编辑)。

1)Qt 语言家 → 更新翻译 (lupdate) 界面进行操作。

2)命令行操作(推荐批量 / 自动化)

需先配置 Qt 环境变量(如 Qt6.5.0\mingw_64\bin 加入系统 PATH),然后执行:

cpp 复制代码
# 进入项目根目录
cd /path/to/your/project

# 基础用法:根据.pro文件生成/更新.ts
lupdate your_project.pro

# 进阶用法:指定编码、忽略文件
lupdate your_project.pro -encoding utf-8 -exclude "third_party/*"

lupdate 常用参数

参数 说明
-encoding <编码> 指定源码编码(如 utf-8,默认自动识别)
-exclude <路径> 忽略指定目录 / 文件(如第三方库代码)
-ts <文件列表> 手动指定要生成的.ts 文件(覆盖.pro 中的 TRANSLATIONS)
-no-obsolete 移除.ts 中已不存在的字符串(清理无效翻译)

3.使用 Qt Linguist 翻译 .ts 文件

Qt Linguist 是 Qt 官方可视化翻译工具,支持普通字符串、复数、消歧符翻译,是处理 .ts 的核心工具。操作比较简单,就不在这里赘述了。

4.编译 .ts 为 .qm 文件

1)界面执行发布翻译 (lrelease) ,执行后 translations 目录下会生成对应的 .qm 文件。

2)命令行操作

cpp 复制代码
# 基础用法:编译单个.ts为.qm
lrelease translations/zh_CN.ts -qm translations/zh_CN.qm

# 进阶用法:批量编译所有.ts
lrelease your_project.pro

# 可选参数:压缩qm、移除未翻译条目
lrelease translations/zh_CN.ts -qm translations/zh_CN.qm -compress -remove-untranslated

lrelease 常用参数

参数 说明
-compress 压缩 .qm 文件(减小体积)
-remove-untranslated 移除未翻译的字符串(减小 qm 体积)
-threshold <百分比> 仅保留翻译完成率≥指定百分比的条目

4.多语言示例

main.cpp中加载指定语言的.qm文件,并安装到应用中。

cpp 复制代码
#include <QApplication>
#include <QTranslator>
#include <QLocale>
#include <QDir>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 1. 创建翻译器对象
    QTranslator translator;

    // 2. 加载qm文件(优先加载系统语言,或指定语言)
    QLocale locale = QLocale::system(); // 获取系统语言(如zh_CN、en_US)
    // 拼接qm文件路径(需确保路径正确)
    QString qmPath = QString("translations/%1.qm").arg(locale.name());
    
    // 加载指定语言(测试用,如强制加载英文)
    // QString qmPath = "translations/en_US.qm";

    if (translator.load(qmPath)) {
        // 3. 安装翻译器到应用(核心步骤)
        a.installTranslator(&translator);
        qDebug() << "加载翻译文件成功:" << qmPath;
    } else {
        qDebug() << "加载翻译文件失败:" << qmPath;
        // 加载失败时,加载默认英文(可选)
        translator.load("translations/en_US.qm");
        a.installTranslator(&translator);
    }

    MainWindow w;
    w.show();

    return a.exec();
}

实际项目中需支持运行时切换语言(如按钮切换中英),核心逻辑:

  1. 卸载旧翻译器 → 加载新.qm → 重新安装翻译器。
  2. 刷新所有界面控件的文本(tr()需重新触发)。

实现示例:

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTranslator>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    // 切换语言的公共接口
    void switchLanguage(const QString &languageCode); // 如"zh_CN"、"en_US"

private slots:
    // 按钮点击槽函数(切换中文/英文)
    void on_btnZhCn_clicked();
    void on_btnEnUs_clicked();

private:
    Ui::MainWindow *ui;
    QTranslator *m_translator; // 翻译器对象(需全局,避免析构)

    // 刷新界面文本(核心:重新设置所有控件的tr()文本)
    void refreshUI();
};

#endif // MAINWINDOW_H

mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_translator(new QTranslator(this)) // 创建翻译器(父对象管理内存)
{
    ui->setupUi(this);

    // 初始化界面文本(用tr()包裹)
    refreshUI();
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 切换语言核心逻辑
void MainWindow::switchLanguage(const QString &languageCode)
{
    // 1. 卸载旧翻译器
    qApp->removeTranslator(m_translator);

    // 2. 加载新语言的qm文件
    QString qmPath = QString("translations/%1.qm").arg(languageCode);
    bool loadOk = m_translator->load(qmPath);
    if (loadOk) {
        // 3. 安装新翻译器
        qApp->installTranslator(m_translator);
        qDebug() << "切换语言成功:" << languageCode;
    } else {
        qDebug() << "切换语言失败,加载默认英文:" << qmPath;
        m_translator->load("translations/en_US.qm");
        qApp->installTranslator(m_translator);
    }

    // 4. 刷新界面文本
    refreshUI();
}

// 刷新所有控件的文本(必须手动重新设置,因为tr()仅在初始化时生效)
void MainWindow::refreshUI()
{
    // 窗口标题
    this->setWindowTitle(tr("多语言示例"));
    // 按钮文本
    ui->btnZhCn->setText(tr("切换为中文"));
    ui->btnEnUs->setText(tr("切换为英文"));
    // 标签文本
    ui->label->setText(tr("欢迎使用Qt多语言功能!"));
}

// 切换中文按钮
void MainWindow::on_btnZhCn_clicked()
{
    switchLanguage("zh_CN");
}

// 切换英文按钮
void MainWindow::on_btnEnUs_clicked()
{
    switchLanguage("en_US");
}

5.关键注意事项

5.1.tr()的正确使用

必须继承 QObject + Q_OBJECT 宏tr()QObject的成员函数,自定义类需继承QObject并添加Q_OBJECT宏(否则lupdate无法提取字符串)。

cpp 复制代码
class MyWidget : public QWidget
{
    Q_OBJECT // 必须加
public:
    MyWidget() {
        setWindowTitle(tr("我的窗口")); // 正确
    }
};

上下文一致性tr()的上下文默认是当前类名,若需跨类共享翻译,可使用QCoreApplication::translate()指定上下文:

cpp 复制代码
// 上下文为"Global",所有地方用此上下文可共享翻译
QString text = QCoreApplication::translate("Global", "确定");

避免动态拼接字符串tr()无法识别拼接的字符串,需拆分后翻译:

cpp 复制代码
// 错误:tr无法提取"共" + num + "条"
ui->label->setText(tr("共" + QString::number(num) + "条"));

// 正确:用arg()占位符
ui->label->setText(tr("共%1条").arg(num));

5.2.将 .qm 嵌入资源文件(避免外置)

.qm 文件加入 qrc 资源文件,程序无需依赖外置文件:

1.创建 translations.qrc 文件:

cpp 复制代码
<RCC>
    <qresource prefix="/translations">
        <file>translations/zh_CN.qm</file>
        <file>translations/en_US.qm</file>
    </qresource>
</RCC>

2.在 .pro 文件中添加:

cpp 复制代码
RESOURCES += translations.qrc

3.代码中加载资源文件中的 .qm

cpp 复制代码
translator.load(":/translations/zh_CN.qm"); // 路径以:/开头

5.3.翻译 Qt 内置控件文本(如 QMessageBox)

Qt 自带控件(如 QMessageBoxQFileDialog)的默认文本("OK"、"取消")需加载 Qt 官方翻译文件:

  1. 找到 Qt 安装目录下的内置翻译文件(如 Qt6.5.0\translations\qt_zh_CN.qm);
  2. 复制到项目 translations 目录,或直接加载:
cpp 复制代码
QTranslator qtTrans;
// Qt6:通过QLibraryInfo获取内置翻译路径
qtTrans.load("qt_zh_CN.qm", QLibraryInfo::path(QLibraryInfo::TranslationsPath));
qApp->installTranslator(&qtTrans);

// Qt5:手动拼接路径
// qtTrans.load("qt_zh_CN.qm", QCoreApplication::applicationDirPath() + "/translations");

5.4.批量处理多语言文件(脚本化)

若项目有大量语言文件,可编写批处理脚本(.bat/.sh)自动化:

cpp 复制代码
:: batch.bat(Windows)
@echo off
cd /d %~dp0  # 进入脚本所在目录
:: 更新ts
lupdate your_project.pro
:: 编译所有ts为qm
lrelease your_project.pro
echo 语言文件编译完成!
pause

6.总结

Qt 语言文件制作的核心流程是:

项目配置(.pro)lupdate提取.tsQt Linguist翻译.tslrelease编译.qm

Qt 多语言实现的核心是:

  1. tr()标记待翻译字符串。
  2. 通过lupdate/Qt Linguist/lrelease生成.qm文件。
  3. 代码中加载.qm并安装翻译器,切换语言时刷新界面。

掌握这些后,可灵活实现静态加载系统语言运行时动态切换语言翻译兜底等多语言场景需求。

相关推荐
2501_930707783 小时前
使用C#代码更改 PowerPoint 幻灯片大小
开发语言·c#·powerpoint
Pafey3 小时前
C++的左值引用、右值引用以及转发和完美转发
c++
CoderCodingNo3 小时前
【GESP】C++三级真题 luogu-B4414 [GESP202509 三级] 日历制作
开发语言·c++·算法
bug总结3 小时前
前端开发中为什么要使用 URL().origin 提取接口根地址
开发语言·前端·javascript·vue.js·html
晨曦夜月4 小时前
笔试强训day7
开发语言·c++·算法
Kurbaneli4 小时前
先啃C语言还是直奔目标?
开发语言
木心爱编程4 小时前
【Qt 5.14.2 新手实战】QTC++入门筑基——按钮与标签联动:QPushButton + QLabel 实现图片切换器
java·c++·qt
weixin_307779134 小时前
Jenkins Pipeline 完全指南:核心概念、使用详解与最佳实践
开发语言·ci/cd·自动化·jenkins·etl
kk”4 小时前
c++红黑树
开发语言·c++
Gomiko4 小时前
JavaScript DOM 原生部分(二):元素内容修改
开发语言·javascript·ecmascript