Qt国际化 - 动态翻译的一个案例

setting.h

#pragma once

#pragma execution_character_set("utf-8") // 编译时把程序里的字符串使用 UTF-8 进行处理

#include <QTranslator>
#include <QWidget>
#include <QMutex>

#include "ui_setting.h"

#include "vanxkr/config/config.h"

class Setting : public QWidget {
    Q_OBJECT
public:
    inline static Setting *Setting::getInstance() {
        if (Q_NULLPTR == instance) {
            QMutexLocker lock(&mutex);
            if (Q_NULLPTR == instance) {
                Setting *instance_ = new Setting();
                instance = instance_;
            }
        }
        return instance;
    }

    // 常量
    const QMap<QString, QString> cLanguageMap = {
        {"中文", "zh"},
        {"English", "en"},
    };

    inline QTranslator& getTranslator() {
        return translator;
    }

public slots:
    inline void setLanguage(const QString &language) {
        ui.comboBox_language->blockSignals(true);
        ui.comboBox_language->setCurrentText(language);
        on_comboBox_language_currentTextChanged(language);
        ui.comboBox_language->blockSignals(false);
    }

protected:
    void changeEvent(QEvent *event);

private:
    Setting(QWidget *parent = Q_NULLPTR);
    ~Setting();
    static Setting *instance;
    static QMutex mutex;
    class GC {  // GC 机制 自动回收
    public:
        ~GC() { // 可以在这里销毁所有的资源
            if (Q_NULLPTR != instance) {
                instance->deleteLater();
                instance = Q_NULLPTR;
            }
        }
        static GC gc;  // 用于释放单例
    };

    // 常量
    const QString cQmPrefix = ":/qm/";

    Ui::Setting ui;

    Config* config = Config::getInstance();
    QString language = Q_NULLPTR;
    QTranslator translator;

singnals:
    void languageChanged(); // 直接发送语言切换 其他类不需要再写 changeEvent

private slots:
    void initWidget();  // 
    void retranslateUi();
    void setLanguagePrivate(const QString &language);

    void on_comboBox_language_currentTextChanged(const QString &text);
};

setting.cpp

#pragma execution_character_set("utf-8") // 编译时把程序里的字符串使用 UTF-8 进行处理

#include <QDebug>

#include "setting.h"

Setting *Setting::instance = Q_NULLPTR;
QMutex Setting::mutex;

void Setting::changeEvent(QEvent *event) {
    if (QEvent::LanguageChange == event->type()) {
        emit languageChanged(); // 
        retranslateUi();
    }
    QWidget::changeEvent(event);
}

Setting::Setting(QWidget *parent)
    : QWidget(parent) {

    setWindowModality(Qt::ApplicationModal);    // 打开子窗口 锁定父窗口
    setWindowFlags(Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint);   // 设置窗口只保留关闭按钮 且 固定大小

    ui.setupUi(this);

    initWidget();
}

Setting::~Setting() {
}

void Setting::initWidget() {    // 
    QStringList languageList;
    for (auto i = cLanguageMap.cbegin(); i != cLanguageMap.cend(); ++i) { // 只读
        languageList.append(i.key());
    }
    ui.comboBox_language->blockSignals(true);
    ui.comboBox_language->addItems(languageList);
    ui.comboBox_language->blockSignals(false);
}

void Setting::retranslateUi() {
    ui.retranslateUi(this);
}

void Setting::setLanguagePrivate(const QString &language) {
    if (this->language != language) {   // 
        this->language = language;
        QString qm = cQmPrefix + cLanguageMap[language];
        bool ret = translator.load(qm);
        if (ret) {  // 成功了才写入
            config->iniWrite("Setting/language", language);
        }
    }
}

void Setting::on_comboBox_language_currentTextChanged(const QString &text) {
    setLanguagePrivate(text);
}

translate.h

#pragma once

#pragma execution_character_set("utf-8") // 编译时把程序里的字符串使用 UTF-8 进行处理

#include <QtWidgets/QMainWindow>

#include "ui_translate.h"

#include "setting.h"

class Translate : public QMainWindow {
    Q_OBJECT
public:
    inline static Translate *Translate::getInstance() {
        if (Q_NULLPTR == instance) {
            QMutexLocker lock(&mutex);
            if (Q_NULLPTR == instance) {
                Translate *instance_ = new Translate();
                instance = instance_;
            }
        }
        return instance;
    }

protected:
    void changeEvent(QEvent *event);

private:
    Translate(QWidget *parent = 0);
    ~Translate();
    static Translate *instance;
    static QMutex mutex;
    class GC {  // GC 机制 自动回收
    public:
        ~GC() { // 可以在这里销毁所有的资源
            if (Q_NULLPTR != instance) {
                delete instance;
                instance = Q_NULLPTR;
            }
        }
        static GC gc;  // 用于释放单例
    };

    Ui::Translate ui;

    Setting* setting = Setting::getInstance();

    QAction* actionSetting = new QAction();

private slots:
    void retranslateUi();
    void initWidget();  // 
    void initConnect();
};

translate.cpp

#pragma execution_character_set("utf-8") // 编译时把程序里的字符串使用 UTF-8 进行处理

#include <QDebug>

#include "translate.h"

Translate *Translate::instance = Q_NULLPTR;
QMutex Translate::mutex;

void Translate::changeEvent(QEvent *event) {
    if(QEvent::LanguageChange == event->type()) {
        retranslateUi();
    }
    QMainWindow::changeEvent(event);
}

Translate::Translate(QWidget *parent)
    : QMainWindow(parent) {
    ui.setupUi(this);

    initWidget();
    initConnect();
}

Translate::~Translate() {
    delete actionSetting;
}

void Translate::retranslateUi() {
    ui.retranslateUi(this);
    actionSetting->setText(tr("设置(Setting)"));
}


void Translate::initWidget() {  // 
    ui.menuBar->addAction(actionSetting);
}

void Translate::initConnect() {
    connect(actionSetting, &QAction::triggered, this, [&]() {
        setting->show();
    });
}

main.cpp

#pragma execution_character_set("utf-8") // 编译时把程序里的字符串使用 UTF-8 进行处理

#include <QtWidgets/QApplication>
#include <QTextCodec>
#include <QDebug>
#include <QDir>

#include "translate.h"

Translate::GC Translate::GC::gc;    // 单例
Setting::GC Setting::GC::gc;    // 单例

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

    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));   // 使用 UTF-8 的运行时环境
    QDir::setCurrent(QCoreApplication::applicationDirPath());   // 设置当前目录为 app所在目录

    Setting* setting = Setting::getInstance();
    a.installTranslator(&Setting::getInstance()->getTranslator());
    setting->setLanguage(
        Config::getInstance()->iniRead(
            "Setting/language", 
            setting->cLanguageMap.cbegin().key()
        ).toString()
    );  // 加载配置文件语言

    Translate::getInstance()->show();

    return a.exec();
}

(╯#-_-)╯~~PS

动态翻译的关键在于:

  1. 对用户可见的文本信息全部使用tr()进行封装 (中文是可以的 此处反驳一下那些说不能用tr()包中文的人 (#‵′)凸)
  2. 使用lupdate导出项目翻译文件:.ts (要多少种语言就导出多少种 项目使用的原始语言也要导出 只是在翻译时不需要进行任何翻译直接发布即可)
  3. 使用Qt Linguist.ts文件进行翻译并发布成为.qm
  4. 项目中实现语言切换功能 顺序很重要:
    1. QApplication安装QTranslator
    2. 再使用QTranslator::load 翻译文件.qm (一定要记得要是上面安装的那个QTranslator)
    3. 以上操作成功即会给所有界面发送changeEvent(QEvent::LanguageChange)事件
    4. 在每一个对用户可见的文本信息显示的类里面实现并在以上的事件响应retranslateUi()操作 (ui文件已帮你实现retranslateUi(Ui::Class)翻译Ui自带的翻译内容 记得调用哦 (→_→))

以上<( ̄︶ ̄)>

有更好的方案欢迎骚扰 []~( ̄▽ ̄)~* vanxkr@qq.com(链接是打开QQ小窗)

ฅ(• - •)ฅ 喜欢就留个赞啵~ ฅʕ•̫͡•

补充 - 2021-3-2 17:29:37

在每一个界面写一次 void changeEvent(QEvent *event); 相对麻烦点

这里有一个方案

我是这么做的

  1. setting.cppvoid changeEvent(QEvent *event); 里面 emit languageChanged(); 信号
  2. 在其他界面 connect(setting, &Setting::languageChanged, this, &Class::retranslateUi); 即可

本文作者:vanxkr

本文链接:http://www.vanxkr.com/2020/6/tr

版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0许可协议。转载请注明出处!

Qt单例模式
0 条评论
已登录,注销 取消