Qt 國際化翻譯

簡介

Qt Linguist 提供了一套加速應用程式翻譯和國際化的工具。Qt 使用單一的源碼樹和單一的應用程式二進位包就可同時支援多個語言和書寫系統。

使用 QTranslator 來載入生成的 qm 文件,就可以讓程式顯示指定的語言。

// 國際化翻譯
QString language = "CH"; // 默認為中文,後期可以使用ini方式保存語言選項
QTranslator translator;
translator.load(QString(":/Translate_") + language);
a.installTranslator(&translator);

要進行多語言的切換,需要執行以下步驟:

  • 對用戶可見的文本資訊全部使用 tr() 進行封裝

  • 提供用戶可以用來切換語言的一種方法。

  • 對於每一個窗口部件或者對話框,重寫 changeEvent 事件,當事件類型為QEvent::LanguageChange時,翻譯文本進行重新調用(為了簡單我把它放在一個單獨的函數translateUI()中)。

多語言切換實例效果

Qt_Translate_D.gif

添加翻譯源

為了方便,這裡只介紹中、英文之間的切換。

在pro中添加:

TRANSLATIONS += Translate_EN.ts \
               Translate_CH.ts

選擇:工具->外部->Qt 語言家->更新翻譯,則會生成對應的 ts 文件。

Qt_Translate_A.png

翻譯

使用Qt Linguist打開要翻譯的ts文件,對翻譯源進行相應語言的翻譯。

Qt_Translate_B.png

發布翻譯

選擇:文件->發布,就會生成對應的 qm 文件。

Qt_Translate_C.png

源碼分析

我們來看一個簡單的示例:主介面可根據選擇不同語言下拉選項實現語言的動態切換!

main.cpp:

#include "Translate.h"

#include <QApplication>

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

    // 國際化翻譯
    QString language = "CH"; // 默認為中文,後期可以使用ini方式保存語言選項
    QTranslator translator;
    translator.load(QString(":/Translate_") + language);
    a.installTranslator(&translator);

    Translate w;
    w.setTranslator(&translator);
    w.show();

    return a.exec();
}

Translate.h:

#ifndef TRANSLATE_H
#define TRANSLATE_H

#include <QWidget>
#include <QTranslator>
#include <QLabel>
#include <QComboBox>
#include <QVBoxLayout>
#include <QEvent>
#include <QApplication>
#include <QDebug>

class Translate : public QWidget
{
    Q_OBJECT

public:
    Translate(QWidget *parent = nullptr);
    void setTranslator(QTranslator* translator); // 設置翻譯對象

protected:
    void changeEvent(QEvent *event); // 改變事件

private:
    void translateUI(); // 統一設置需要被翻譯的文本

    QLabel *m_pLabText;
    QComboBox *m_pComboBox;
    QTranslator *m_translator; // 國際化翻譯對象
};
#endif // TRANSLATE_H

Translate.cpp

#include "Translate.h"

Translate::Translate(QWidget *parent)
    : QWidget(parent)
{
    // 初始化介面
    this->setFixedSize(400, 200);

    // 初始化控制項
    m_pLabText = new QLabel;
    m_pComboBox = new QComboBox;
    m_pComboBox->addItem("Chinese");
    m_pComboBox->addItem("English");

    // 主布局
    QVBoxLayout *m_pLayoutMain = new QVBoxLayout(this);
    m_pLayoutMain->addStretch();
    m_pLayoutMain->addWidget(m_pLabText, 0, Qt::AlignCenter);
    m_pLayoutMain->addSpacing(20);
    m_pLayoutMain->addWidget(m_pComboBox, 0, Qt::AlignCenter);
    m_pLayoutMain->addStretch();
    m_pLayoutMain->setMargin(0);

    // 連接訊號槽
    connect(m_pComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](int index) {
        QString language_qm;
        if(index == 0)
            language_qm = QString(":/Translate_CH.qm");
        else
            language_qm = QString(":/Translate_EN.qm");

        m_translator->load(language_qm);
        qApp->installTranslator(m_translator); // 安裝翻譯器
    });

    // 統一設置需要被翻譯的文本
    translateUI();
}

// 設置翻譯對象
void Translate::setTranslator(QTranslator* translator)
{
    m_translator = translator;
}

// 改變事件:調用installTranslator後,系統會給窗體發送訊號觸發changeEvent事件
void Translate::changeEvent(QEvent *event)
{
    switch (event->type())
    {
    case QEvent::LanguageChange:
        translateUI();
        break;
    default:
        QWidget::changeEvent(event);
    }
}

// 統一設置需要被翻譯的文本
void Translate::translateUI()
{
    m_pLabText->setText(tr("這是需要測試的文本"));
}

FloatWidget.cpp

#include "HelperWidget.h"

HelperWidget::HelperWidget(QWidget *parent) : QWidget(parent)
{
    /* 介面初始化 */
    this->setFixedSize(500, 200);
    this->setWindowFlags(Qt::FramelessWindowHint);
    this->setObjectName("FloatWidget");
    setAttribute(Qt::WA_StyledBackground); // 不繼承父窗口樣式

    m_pLabName = new QLabel;
    m_pLabIp = new QLabel;
    m_pBtnGet = new QPushButton;
    m_pBtnPush = new QPushButton;
    m_pBtnVideo = new QPushButton;
    m_pLabSet = new QLabel;
    m_pLabName->setText(tr("運維平台主屏"));
    m_pLabIp->setText("192.168.1.71");
    m_pBtnGet->setText("接管");
    m_pBtnPush->setText("推送");
    m_pBtnVideo->setText("影片");
    m_pLabSet->setText("設置");
    m_pLabSet->installEventFilter(this);

    // 懸浮小窗口-窗口部件初始化
    m_pWidgetFloatSet = new QWidget;
    m_pBtnUser = new QPushButton;
    m_pBtnMatrix = new QPushButton;
    m_pBtnShortCut = new QPushButton;
    m_pWidgetFloatSet->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
    m_pWidgetFloatSet->installEventFilter(this);
    m_pBtnUser->setText("用戶許可權");
    m_pBtnMatrix->setText("矩陣");
    m_pBtnShortCut->setText("快捷鍵");
    QVBoxLayout *pVLayoutSet = new QVBoxLayout(m_pWidgetFloatSet);
    pVLayoutSet->addWidget(m_pBtnUser);
    pVLayoutSet->addWidget(m_pBtnMatrix);
    pVLayoutSet->addWidget(m_pBtnShortCut);

    QHBoxLayout *pHLayoutBtn = new QHBoxLayout;
    pHLayoutBtn->addWidget(m_pBtnGet);
    pHLayoutBtn->addWidget(m_pBtnPush);
    pHLayoutBtn->addWidget(m_pBtnVideo);
    pHLayoutBtn->addWidget(m_pLabSet);

    QVBoxLayout *pVLayoutMain = new QVBoxLayout(this);
    pVLayoutMain->addWidget(m_pLabName);
    pVLayoutMain->addWidget(m_pLabIp);
    pVLayoutMain->addLayout(pHLayoutBtn);
    pVLayoutMain->addSpacing(60);


    // 訊號槽鏈接
    connect(m_pBtnGet, &QPushButton::clicked, [=]() {
        emit sigBtnClickedGet();
    });
    connect(m_pBtnPush, &QPushButton::clicked, [=]() {
        emit sigBtnClickedPush();
    });
    connect(m_pBtnVideo, &QPushButton::clicked, [=]() {
        emit sigBtnClickedVideo();
    });

    // 在eventFilter中處理顯隱則導致滑鼠進入不了懸浮窗就會隱藏,所以用定時器去做
    m_pTimerFloat = new QTimer;
    m_pTimerFloat->setInterval(100);
    connect(m_pTimerFloat, &QTimer::timeout, [=]() {
        if ((m_pWidgetFloatSet != nullptr) && (m_pWidgetFloatSet->isVisible()))
        {
            // 判斷滑鼠是否遊離到了懸浮窗之外,如果遊離出去了,那麼隱藏窗口
            QPoint currentPos = QCursor::pos();
            QRect floatWidgetRect = m_pWidgetFloatSet->rect();
            QRect rect(m_pWidgetFloatSet->pos().x(), m_pWidgetFloatSet->pos().y(), floatWidgetRect.width(), floatWidgetRect.height());
            if (!rect.contains(currentPos)){
               m_pWidgetFloatSet->hide();
               m_pTimerFloat->stop();
            }
        }
    });
}


// 事件過濾器(實現懸浮小窗口)
bool HelperWidget::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == m_pLabSet)
    {
        if (event->type() == QEvent::Enter)
        {
            QPoint oWidgetPoint = this->mapToGlobal(m_pLabSet->pos());
            m_pWidgetFloatSet->setGeometry(oWidgetPoint.x(), oWidgetPoint.y() + m_pLabSet->height(), 80, 80);
            m_pWidgetFloatSet->show();

            m_pTimerFloat->stop();
            return true;
        }
        else if (event->type() == QEvent::Leave) //如果是其他事件,可以進行進一步的處理
        {
            m_pTimerFloat->start();
            return false;
        }
        else
            return false;
    }
    else if (obj == m_pWidgetFloatSet)
    {
        if (event->type() == QEvent::Leave)
        {
            m_pWidgetFloatSet->hide();
            return false;
        }
        else
            return false;
    }
    else
        return QWidget::eventFilter(obj, event);
}

Tags: