简 述: 准备将我写的悬浮网速窗口上面支持国际化(多语言);记录一下通过 CMake + Qt 来对项目设置国际化。

[TOC]


本文初发于 “偕臧的小站” ifmet.cn,同步转载于此。


编程环境:  💻 uos20 amd64 📎 Qt 5.11.3 📎 cmake 3.13.4 📎 gdb8.0


国际化原理

Qt 实现多语言的关键原理如图,先扫描所有的源码文件 .cpp.ui 文件,找到被 tr() 包裹的字符串(多国语言混合也可),然后人使用到 Qt5 Lingust 程序来对每一个 .ts 文件进行翻译,再次编译生成所需的 .qm 文件。


操作步骤

​ 因为要对自己的程序完成国际化,先在 CMakeLists.txt 添加如下代码,标明使用 LinguistTools 来生成 *.ts 文件

set(TS_FILES
        ./translations/zh_CN.ts
        ./translations/zh_TW.ts)
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} LinguistTools REQUIRED)
qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES})

​ 后对项目执行 CMake、编译后,会根据 .cpp.ui 文件里面字符串扫描(字符串可以同时为几国语言混合,但必须使用 tr() 包裹); 会在源码路径的 ./translations/ 下生成两个 zh_CN.ts、zh_TW.ts 文件;使用 Qt5 Lingust ,手工对源文件翻译本国语言保存。


​ 再次编译一遍,在 build-xxx 文件夹中得到 *.qm 文件,一般而言,然后在源码里面加上如下,即完成。若是没生效的话,则可能没执行 ui->retranslateUi(this); 函数

QTranslator trans;
trans.load("./" + QLocale().name() + ".qm");
QCoreApplication::installTranslator(m_trans);

但实际其中最后一步要修改一下,结合实际项目,将多语言按钮写在 QComboBox 控件中;在其中添加

QStringList listLang;
QStringList listData;
listLang << "English" << "简体中文" << "繁體中文(台湾)";
listData << "es_US" << "zh_CN" << "zh_TW";

for (int i = 0; i < listLang.count(); ++i)
    ui->comboBoxLanguage->addItem(listLang[i], listData[i]);

对该控件添加对应的槽函数

void WinSetting::onComboBoxLanguage(int index)
{
    QString language("zh_CN");
    language = ui->comboBoxLanguage->itemData(index).toString();
    bool ok = m_trans->load("./" + language + ".qm");
    qDebug()<< "---------@1--->" << language << ok;
    QCoreApplication::installTranslator(m_trans);
}

其中每次运行 installTranslator() 的时候,都会触发 QEvent::LanguageChange 事件信号;故需要在事件过滤器中,添加对应的处理,响应更新界面更新文字。还要在该 QcomboBox 控件中安装此事件过滤器; 此时就已经完成了,可以不关闭程序切换多语言了。

bool WinSetting::eventFilter(QObject *watched, QEvent *event)
{
	if (watched == ui->comboBoxLanguage) {
        if (event->type() == QEvent::LanguageChange) {
            ui->retranslateUi(this);
            return true;
        }
    } 

    return QWidget::eventFilter(watched, event);
}

注意

  • 若在 QtCreator 中,点击 “清理”,会删除 /translations 下的所有 .ts 文件,再次编译后的生成是空的未翻译的 .ts 文件;坑坑坑!!!

  • 一般使用设计器来设计的界面 UI,也就是程序源码中我们看到的 *.ui文件,在载入翻译器后,我们应该调用 ui->retranslateUi() ,这个函数实际上就是把 界面 控件的text重新载入一遍,可以在 ui_*.cpp 中看到该函数的实现。

  • 当语言进行切换时,需要调用 ui->retranslateUi(this); 更新主窗口。 如果非主窗口,则这个 installTranslator 函数会触发void changeEvent(QEvent *e) 事件。

    原因如下:系统调用完 installTranslator 函数之后,系统会自动给程序中所有的 QWidget 以及其子类发送 QEvent::LanguageChange() 信号,并告知changeEventevent 产生。所以,在要切换语言的每个窗体中都要重写接受 QEvent::LanguageChange() 信号的 changeEvent 函数,从而实现了语言的动态切换。

    注意:加载主程序与子插件程序翻译文件时的别名或者路径不要相同,否则子插件程序翻译有可能不生效。


项目提交

lfxNet 的实时网速程序中,实际提交代码可提供大家参考

  1. Cmake 添加调用 LinguistTools 的代码: #948522d8b
  2. 更新翻译 .ts 文件: #9602aa3e3#4e659fe13
  3. 设置多语言切换: #31b2561bd

参考


系列地址:

QtExamples

欢迎 starfork 这个系列的 QT / DTK 学习,附学习由浅入深的目录。