当前位置: 首页 > news >正文

Qt 项目国际化从零到一:用 Qt Linguist 实现多语言动态切换(含源码与踩坑指南)

目录

  1. 为什么需要国际化(i18n)

  2. 环境与目录结构

  3. 第一个带翻译标记的 Qt 界面

  4. 生成 .ts 翻译文件(lupdate)

  5. 用 Qt Linguist 翻译

  6. 生成 .qm 文件(lrelease)

  7. 程序运行时加载 .qm

  8. 通式多语言切换(LanguageManager)

  9. 自动记忆 & 系统语言优先

  10. 打包与部署(含 Qt 基础控件翻译)

  11. 常见问题与踩坑总结

  12. 源码清单(可直接复制运行)


1. 为什么需要国际化(i18n)

  • 走向全球:桌面应用需要满足不同地区用户。

  • 体验一致:菜单、对话框、提示信息一致切换。

  • Qt 自带完整方案tr() 标记 → .ts 翻译(XML) → .qm 运行时资源。


2. 环境与目录结构

本文以最小工程示例:

MyI18nApp/
├─ main.cpp
├─ mainwindow.h / mainwindow.cpp / mainwindow.ui
├─ languagemanager.h / languagemanager.cpp
├─ translations/
│   ├─ app_en_US.ts / app_zh_CN.ts / app_ja_JP.ts   ← lupdate 生成
│   ├─ app_en_US.qm / app_zh_CN.qm / app_ja_JP.qm   ← lrelease 生成
│   └─ qtbase_zh_CN.qm / qtbase_ja_JP.qm            ← 可选(Qt 基础控件翻译)
├─ resources.qrc
├─ MyI18nApp.pro          (qmake 方案)
└─ CMakeLists.txt         (CMake 方案)

你可选 qmake 或 CMake,其它文件通用。


3. 第一个带翻译标记的 Qt 界面

3.1 在 .ui / .cpp 中使用 tr()

mainwindow.ui 放一个 QLabel 与一个 QPushButton
mainwindow.cpp 中(或直接在 .ui 属性里)加入可翻译文本:

// mainwindow.cpp(示例)
ui->label->setText(tr("Hello, World!"));
ui->pushButton->setText(tr("Switch Language"));

关键:只有被 tr() 包裹的字符串会被提取到 .ts


4. 生成 .ts 翻译文件(lupdate)

qmake 项目

MyI18nApp.pro 中加入:

QT += widgets
TEMPLATE = app
TARGET = MyI18nApp
SOURCES += main.cpp mainwindow.cpp languagemanager.cpp
HEADERS += mainwindow.h languagemanager.h
FORMS   += mainwindow.ui
RESOURCES += resources.qrcTRANSLATIONS += translations/app_en_US.ts \translations/app_zh_CN.ts \translations/app_ja_JP.ts

命令行执行:

lupdate MyI18nApp.pro

CMake 项目(Qt 6)

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(MyI18nApp)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets LinguistTools)set(SRCSmain.cppmainwindow.cpplanguagemanager.cppresources.qrc
)
set(HDRS mainwindow.h languagemanager.h)
set(UIS  mainwindow.ui)set(TS_FILEStranslations/app_en_US.tstranslations/app_zh_CN.tstranslations/app_ja_JP.ts
)qt_add_executable(MyI18nApp ${SRCS} ${HDRS} ${UIS})# 生成 QM 文件(Qt6 推荐)
qt_add_translations(MyI18nApp QM_FILES ${TS_FILES})
target_link_libraries(MyI18nApp PRIVATE Qt6::Widgets)

命令行执行:

cmake -S . -B build
cmake --build build
# 或单独生成 ts:lupdate . -ts translations/app_zh_CN.ts ...

5. 用 Qt Linguist 翻译

  1. 打开 translations/*.ts

  2. 在右侧填入译文;

  3. 保存后状态会从 unfinished 变为 finished

.ts 结构示例(节选):

<TS version="2.1" language="zh_CN"><context><name>MainWindow</name><message><source>Hello, World!</source><translation>你好,世界!</translation></message><message><source>Switch Language</source><translation>切换语言</translation></message></context>
</TS>

6. 生成 .qm 文件(lrelease)

lrelease translations/app_en_US.ts
lrelease translations/app_zh_CN.ts
lrelease translations/app_ja_JP.ts

生成的 .qm 文件放进资源或部署目录。


7. 程序运行时加载 .qm

resources.qrc 中把 .qm 打到资源里:

<RCC><qresource prefix="/"><file alias="translations/app_en_US.qm">translations/app_en_US.qm</file><file alias="translations/app_zh_CN.qm">translations/app_zh_CN.qm</file><file alias="translations/app_ja_JP.qm">translations/app_ja_JP.qm</file><!-- 可选:Qt 基础控件翻译 --><file alias="translations/qtbase_zh_CN.qm">translations/qtbase_zh_CN.qm</file><file alias="translations/qtbase_ja_JP.qm">translations/qtbase_ja_JP.qm</file></qresource>
</RCC>

8. 通式多语言切换(LanguageManager)

一次实现,支持任意多语言;动态切换后 UI 自动刷新;兼容 Qt5/Qt6。

8.1 languagemanager.h

#pragma once
#include <QObject>
#include <QTranslator>
#include <QLocale>
#include <QSet>class LanguageManager : public QObject {Q_OBJECT
public:explicit LanguageManager(QObject* parent=nullptr);void addSupported(const QString& localeName); // "en_US" / "zh_CN" / "ja_JP"QStringList supported() const;QString current() const;bool switchTo(const QString& localeName); // 动态切换signals:void languageChanged(const QString& localeName);private:bool loadTranslators(const QString& localeName);void unloadTranslators();QString m_current;QTranslator m_appTr;QTranslator m_qtbaseTr; // 可选QSet<QString> m_supported;
};

8.2 languagemanager.cpp

#include "languagemanager.h"
#include <QApplication>LanguageManager::LanguageManager(QObject* p): QObject(p) {}void LanguageManager::addSupported(const QString& n){ m_supported.insert(n); }QStringList LanguageManager::supported() const {auto list = QStringList(m_supported.begin(), m_supported.end());std::sort(list.begin(), list.end());return list;
}QString LanguageManager::current() const { return m_current; }bool LanguageManager::switchTo(const QString& name) {if (!m_supported.contains(name)) return false;if (m_current == name) return true;unloadTranslators();if (!loadTranslators(name)) return false;m_current = name;emit languageChanged(name);return true;
}bool LanguageManager::loadTranslators(const QString& name) {const QString app = QString(":/translations/app_%1.qm").arg(name);if (!m_appTr.load(app)) return false;const QString qtbase = QString(":/translations/qtbase_%1.qm").arg(name);m_qtbaseTr.load(qtbase); // 允许失败qApp->installTranslator(&m_appTr);if (!m_qtbaseTr.isEmpty()) qApp->installTranslator(&m_qtbaseTr);return true;
}void LanguageManager::unloadTranslators() {if (!m_appTr.isEmpty())   qApp->removeTranslator(&m_appTr);if (!m_qtbaseTr.isEmpty()) qApp->removeTranslator(&m_qtbaseTr);m_appTr = QTranslator();m_qtbaseTr = QTranslator();
}

8.3 mainwindow.h

#pragma once
#include <QMainWindow>
class LanguageManager;
namespace Ui { class MainWindow; }class MainWindow : public QMainWindow {Q_OBJECT
public:explicit MainWindow(LanguageManager* lm, QWidget* parent=nullptr);~MainWindow();private slots:void onLanguageChanged(const QString&); // 信号响应
private:void rebuildLanguageMenu(); // 动态构建“语言”菜单void retranslateUi();       // 统一刷新 UIUi::MainWindow* ui;LanguageManager* m_lang;
};

8.4 mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "languagemanager.h"
#include <QActionGroup>
#include <QSettings>
#include <QLocale>static QString pretty(const QString& n){const QLocale loc(n);return QString("%1 (%2)").arg(QLocale::languageToString(loc.language())).arg(QLocale::countryToString(loc.country()));
}MainWindow::MainWindow(LanguageManager* lm, QWidget* parent): QMainWindow(parent), ui(new Ui::MainWindow), m_lang(lm) {ui->setupUi(this);connect(m_lang, &LanguageManager::languageChanged,this, &MainWindow::onLanguageChanged);rebuildLanguageMenu();retranslateUi();
}MainWindow::~MainWindow(){ delete ui; }void MainWindow::rebuildLanguageMenu() {// 在 .ui 中放一个菜单:objectName = menuLanguageui->menuLanguage->clear();auto* group = new QActionGroup(this); group->setExclusive(true);for (const auto& n : m_lang->supported()){auto* act = ui->menuLanguage->addAction(pretty(n));act->setCheckable(true);act->setData(n);if (n == m_lang->current()) act->setChecked(true);group->addAction(act);}connect(group, &QActionGroup::triggered, this, [this](QAction* a){m_lang->switchTo(a->data().toString());});
}void MainWindow::onLanguageChanged(const QString&){retranslateUi();rebuildLanguageMenu();QSettings s("YourCompany","MyI18nApp");s.setValue("lang", m_lang->current());
}void MainWindow::retranslateUi(){ui->retranslateUi(this); // 刷新 .ui 文本// 如果有纯代码里的动态字符串,也在这里用 tr() 重新设置
}

8.5 main.cpp

#include "mainwindow.h"
#include "languagemanager.h"
#include <QApplication>
#include <QSettings>
#include <QLocale>int main(int argc, char *argv[]) {QApplication a(argc, argv);LanguageManager lm;// 新增语言只需要在这里加一行,或做目录扫描自动添加lm.addSupported("en_US");lm.addSupported("zh_CN");lm.addSupported("ja_JP");// 1) 读取上次选择;2) 否则按系统语言;3) 再回退英文QSettings s("YourCompany","MyI18nApp");QString target = s.value("lang").toString();if (target.isEmpty()) {const QString sys = QLocale().name();target = lm.supported().contains(sys) ? sys : "en_US";}lm.switchTo(target);MainWindow w(&lm);w.show();return a.exec();
}

9. 自动记忆 & 系统语言优先

  • QSettings 持久化当前语言,下次启动沿用;

  • 首次运行优先用 QLocale().name() 与已支持语言匹配;

  • 不匹配时回退到 en_US(或你希望的默认语言)。


10. 打包与部署(含 Qt 基础控件翻译)

  • 资源内置:使用 :/translations/... 最省心;

  • 外部目录:用磁盘路径加载,便于热更新;

  • Qt 基础控件翻译:拷贝 qtbase_xx_YY.qm(随 Qt 安装提供)一起部署,文件对话框等系统控件才会被翻译;

  • 路径排查QTranslator::load() 失败 90% 是路径问题,建议配合 QFile::exists() 调试。


11. 常见问题与踩坑总结

现象常见原因解决方案
切换后部分文本不变忘记刷新 UI切换后统一调用 ui->retranslateUi(this),并在其中重设纯代码字符串
.ts 内容很少/为空忘记 tr() 或未扫描 .ui所有文本用 tr();确保 .pro/CMake 把 .ui/.cpp/.h 都包含
.qm 无效installTranslator() 或加载到旧文件removeTranslator()installTranslator();确认 .qm 最近 lrelease 过
对话框仍英文未加载 qtbase_*.qm额外加载 qtbase 对应语言
多窗口没刷新新窗口在切换后才创建languageChanged 信号或在构造时再次 retranslateUi()

12. 源码清单(可直接复制运行)

提示:把以下所有文件按章节名保存到你的工程里,lupdate / lrelease 后即刻运行。

12.1 MyI18nApp.pro(qmake 选其一)

QT += widgets
TEMPLATE = app
TARGET = MyI18nAppSOURCES += main.cpp mainwindow.cpp languagemanager.cpp
HEADERS += mainwindow.h languagemanager.h
FORMS   += mainwindow.ui
RESOURCES += resources.qrcTRANSLATIONS += translations/app_en_US.ts \translations/app_zh_CN.ts \translations/app_ja_JP.ts

12.2 CMakeLists.txt(CMake 选其一)

cmake_minimum_required(VERSION 3.16)
project(MyI18nApp)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)find_package(Qt6 REQUIRED COMPONENTS Widgets LinguistTools)set(SRCSmain.cppmainwindow.cpplanguagemanager.cppresources.qrc
)
set(HDRS mainwindow.h languagemanager.h)
set(UIS  mainwindow.ui)set(TS_FILEStranslations/app_en_US.tstranslations/app_zh_CN.tstranslations/app_ja_JP.ts
)qt_add_executable(MyI18nApp ${SRCS} ${HDRS} ${UIS})
qt_add_translations(MyI18nApp QM_FILES ${TS_FILES})target_link_libraries(MyI18nApp PRIVATE Qt6::Widgets)

12.3 resources.qrc

<RCC><qresource prefix="/"><file alias="translations/app_en_US.qm">translations/app_en_US.qm</file><file alias="translations/app_zh_CN.qm">translations/app_zh_CN.qm</file><file alias="translations/app_ja_JP.qm">translations/app_ja_JP.qm</file><!-- 可选:Qt 基础控件翻译 --><file alias="translations/qtbase_zh_CN.qm">translations/qtbase_zh_CN.qm</file><file alias="translations/qtbase_ja_JP.qm">translations/qtbase_ja_JP.qm</file></qresource>
</RCC>

12.4 main.cpp

#include "mainwindow.h"
#include "languagemanager.h"
#include <QApplication>
#include <QSettings>
#include <QLocale>int main(int argc, char *argv[]) {QApplication a(argc, argv);LanguageManager lm;lm.addSupported("en_US");lm.addSupported("zh_CN");lm.addSupported("ja_JP");QSettings s("YourCompany","MyI18nApp");QString target = s.value("lang").toString();if (target.isEmpty()) {const QString sys = QLocale().name();target = lm.supported().contains(sys) ? sys : "en_US";}lm.switchTo(target);MainWindow w(&lm);w.show();return a.exec();
}

12.5 languagemanager.h / languagemanager.cpp

见第 8 章,原样复制即可。

12.6 mainwindow.h

#pragma once
#include <QMainWindow>
class LanguageManager;
namespace Ui { class MainWindow; }class MainWindow : public QMainWindow {Q_OBJECT
public:explicit MainWindow(LanguageManager* lm, QWidget* parent=nullptr);~MainWindow();
private slots:void onLanguageChanged(const QString&);
private:void rebuildLanguageMenu();void retranslateUi();Ui::MainWindow* ui;LanguageManager* m_lang;
};

12.7 mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "languagemanager.h"
#include <QActionGroup>
#include <QSettings>
#include <QLocale>static QString pretty(const QString& n){const QLocale loc(n);return QString("%1 (%2)").arg(QLocale::languageToString(loc.language())).arg(QLocale::countryToString(loc.country()));
}MainWindow::MainWindow(LanguageManager* lm, QWidget* parent): QMainWindow(parent), ui(new Ui::MainWindow), m_lang(lm) {ui->setupUi(this);connect(m_lang, &LanguageManager::languageChanged,this, &MainWindow::onLanguageChanged);rebuildLanguageMenu();retranslateUi();
}MainWindow::~MainWindow(){ delete ui; }void MainWindow::rebuildLanguageMenu() {ui->menuLanguage->clear();auto* group = new QActionGroup(this); group->setExclusive(true);for (const auto& n : m_lang->supported()) {auto* act = ui->menuLanguage->addAction(pretty(n));act->setCheckable(true); act->setData(n);if (n == m_lang->current()) act->setChecked(true);group->addAction(act);}connect(group, &QActionGroup::triggered, this, [this](QAction* a){m_lang->switchTo(a->data().toString());});
}void MainWindow::onLanguageChanged(const QString&) {retranslateUi();rebuildLanguageMenu();QSettings s("YourCompany","MyI18nApp");s.setValue("lang", m_lang->current());
}void MainWindow::retranslateUi() {ui->retranslateUi(this);// 代码构造的字符串也在这里使用 tr() 重新设置
}

12.8 mainwindow.ui 关键点

  • 放一个 QMenuBar,增加一个菜单,objectName = menuLanguage(作为“语言”菜单)。

  • 放一个 QLabel(文本:Hello, World!),一个 QPushButton(文本:Switch Language)。

  • .ui 自动使用 tr(),会被 lupdate 提取到 .ts


结束语

到这里,你已经完成了 Qt 国际化的全链路

  • tr() 标记 → .ts 提取(lupdate) → Linguist 翻译 → .qm 编译(lrelease)

  • 程序运行时加载/卸载翻译器

  • 通式多语言切换 + 自动记忆 + Qt 基础控件翻译

  • qmake/CMake 均支持,工程可即刻运行

http://www.dtcms.com/a/477909.html

相关文章:

  • GitPuk入门到实战(8) - 使用GitPuk + Arbess进行CICD自动化部署
  • 网站后台登录地址修改怎么查询一个网站有没有做竞价
  • 《Qt应用开发》笔记p5
  • 【AI4S】AI设计小分子药物的三大底层逻辑
  • 网站建设费入什么科目2018把网站做静态化是什么意思
  • Node.js 事件循环(Event Loop)
  • C语言结构体详解:从定义、内存对齐到位段应用
  • 单片机进入 B. 中断无限循环异常解决方法
  • 探索Apache APISIX:动态高性能API网关
  • 【储能学习】电力基础知识
  • 2025 年项目管理转型白皮书:AI 驱动下的能力重构与跨域突破
  • linux网站建设技术指南台州 网站建设
  • AI超级智能体学习笔记
  • 海量域名SSL证书的免费批量签发
  • 基于 PyTorch 的手写数字识别
  • 悟空 AI CRM 中的线索功能:开启销售增长新引擎
  • 网站建设和维护方案吉林省城乡建设厅网站6
  • 互联网视频推拉流平台EasyDSS视频转码有哪些技术特点和应用?
  • 肥城网站建设费用lol做框网站
  • 微信小程序入门学习教程,从入门到精通,电影之家小程序项目知识点详解 (17)
  • CoRL2025口头报告:基于最优传输对齐人类视角和机器人视角的多模态数据,真正解决跨模态数据融合的问题
  • 线程进阶:线程池、单例模式与线程安全深度解析
  • ELK运维之路(Logstash7Kibana接入ES集群-7.17.24)
  • # Pandas 与 Spark 数据操作完整教程
  • 大数据实战项目-基于K-Means算法与Spark的豆瓣读书数据分析与可视化系统-基于python的豆瓣读书数据分析与可视化大屏
  • AI 数字人小程序功能全拆解:从用户体验到商业落地的产品设计逻辑
  • Agent 开发设计模式(Agentic Design Patterns )第 6 章:规划设计模式 Planning
  • 厦门做网站xm37如何增加网站内链建设
  • css变量的使用。
  • 全网首发 OpenAI Apps SDK 使用教程