• 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 
    
    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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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);
    }
    

  • 相关阅读:
    编程随笔:控制复杂度是计算机编程的本质。
    2021 年河南省中等职业教育技能大赛“网络安全”项目比赛任务书解析教程
    6134. 找到离给定两个节点最近的节点-力扣双百代码
    (二十八)大数据实战——Flume数据采集之kafka数据生产与消费集成案例
    最佳实践之部署安全且具有韧性的AI系统
    Android---DVM以及ART对JVM进行优化
    JAVASE语法零基础——static成员和代码块
    多线程-阻塞队列
    【爬虫】7.1. JavaScript动态渲染界面爬取-Selenium
    数据库到底应该如何存储密码?
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/16564866.html