上一篇博文已經說過如何編寫支持多語言的Qt 命令行應用,這一篇說說Qt GUI 應用多語言支持的坑。html
本人喜歡用代碼來寫佈局,而不是用 Qt Designer 來設計佈局,手寫佈局比 Qt Desiner 佈局有如下優勢:c++
本文示例程序是一個GUI應用,手寫佈局,在工具欄中添加兩個 QAction
,能夠切換中文、英文界面,主界面一個標籤顯示文本,一個按鈕用來退出應用。編程
英文界面以下:ide
中文界面以下:函數
VS 版本: vs2017 社區版
Qt 版本: 5.11.1
Qt VS tools: 2.3.2工具
默認的會建立 UI 文件,直接編譯工程,複製編譯產生的 ui_HelloQt.h
文件,重命名爲 myUI_HelloQt.h
以這個文件爲模板,手工佈局。佈局
setupUI()
中實現佈局使用MVC編程模型,只在 myUI_HelloQt.h
文件中實現GUI,這裏雖然新建了兩個 QAction
和一個 QPushButton
,可是沒有鏈接信號和槽函數。ui
佈局完成調試看看是否佈局合理。this
lupdate
提取字符串,並語言家來翻譯;lrelease
發佈 QM 文件,即 helloqt_zh.qm 文件;HelloQt.qrc
中添加 QM 文件,並把資源重命名爲 :/translations/helloqt_zh
QTranslator *language_zh;
,並在主窗口的構造方法中加載對應的QM文件, language_zh->load(":/translations/helloqt_zh");
加載了 QM 文件還不能切換多語言,須要安裝才行。到底什麼時候安裝呢?這時候想起了前面的兩個 QAction
,只有點擊了對應的工具條才切換對應的語言,在主窗口的構造方法中鏈接信號和槽函數:spa
// signals and slots QObject::connect(ui.act_language_zh, SIGNAL(triggered(bool)), this, SLOT(on_trigger_language_zh(bool))); QObject::connect(ui.act_language_en, SIGNAL(triggered(bool)), this, SLOT(on_trigger_language_en(bool))); QObject::connect(ui.btn_quit, SIGNAL(clicked(bool)), this, SLOT(on_btn_quit_clicked(bool)));
分別實現 action 對應的槽函數,加載中文時安裝 QTranslation
,加載英文時卸載,以下面的代碼所示:
void HelloQt::on_trigger_language_zh(bool checked) { qDebug() << tr("Chinese") << endl; qApp->installTranslator(language_zh); } void HelloQt::on_trigger_language_en(bool checked) { qDebug() << tr("English") << endl; qApp->removeTranslator(language_zh); }
執行完上一步你就急着編譯查看結果,點擊兩個工具欄你卻發現並不能切換語言,爲何呢?由於切換語言的事件尚未處理呢。覆蓋 changeEvent()
便可:
void HelloQt::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { ui.retranslateUi(this); } else { QMainWindow::changeEvent(event); } }
至此兩個工具欄終於能夠正常地切換語言顯示了。
你能夠看到工程中至少出現了3次 retranslateUi()
函數,一次是定義,兩次是調用,第一次調用是在UI 初始化中,第二次調用是 changeEvent()
中切換語言,它所作的工做就是把UI widgets 上顯示的字符串替換爲特定語言的字符串。例如給主窗口設定窗口標題 HelloQtClass->setWindowTitle(QApplication::translate("HelloQtClass", "HelloQt", nullptr));
最關鍵的是裏面的 [static] QString QCoreApplication::translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1)
,這個函數纔是負責翻譯語言的。
第一個參數 context
理解爲上下文,什麼是上下文,Qt 助手說它就是一個類名。不一樣的字符串會分配到不一樣的上下文。分配規則是 tr()
是用哪一個類名來限定的,以下面的代碼,分別調用 QObject::tr("install Chinese")
,HelloQt::tr("install English")
那麼就有兩個上下文,分別是 QObject
和 HelloQt
,這一點也能夠從語言家看到。
void HelloQt::on_trigger_language_zh(bool checked) { qDebug() << QObject::tr("install Chinese") << endl; qApp->installTranslator(language_zh); } void HelloQt::on_trigger_language_en(bool checked) { qDebug() << HelloQt::tr("install English") << endl; qApp->removeTranslator(language_zh); }
語言家界面的顯示:
第二個參數 sourceText
就是源代碼中以 tr()
括起來的字符串。
後面的兩個參數暫時沒有用到,忽略。
一張圖說明上下文,源字符串兩者的關係,若是代碼中某個字符串被刪除了可是 TS 文件中還存在,並且從此不須要這個翻譯,就能夠用記事本打開 TS 文件,直接刪除以 vanished 標記的翻譯:
回到 retranslateUi()
函數,這是一個自定義的函數,用戶在這裏翻譯GUI界面,若是發現GUI上某個 widget 語言沒有變化,就須要在這裏翻譯,以下面的代碼翻譯標籤和按鈕的文本,以及兩個工具欄的文本:
```C++ // add your own translate here. act_language_zh->setText(QApplication::translate("QObject", "Chinese", nullptr)); act_language_en->setText(QApplication::translate("QObject", "English", nullptr)); lbl_hello->setText(QApplication::translate("QObject", "<h2><i>Hello</i><font color=red>Qt!</font></h2>", nullptr)); btn_quit->setText(QApplication::translate("QObject", "&Quit", nullptr)); ```
上面的代碼中標籤文本是一個 HTML 代碼,這個也能夠翻譯的, HTML 樣式保留,只須要替換裏面的 Hello 和 Qt! 便可。
只列出關鍵的源代碼,首先是佈局文件 myUI_HelloQt.h
#pragma once #ifndef MYUI_HELLOQT_H #define MYUI_HELLOQT_H #include <QtCore/QVariant> #include <QtWidgets/QApplication> #include <QtWidgets/QMainWindow> #include <QtWidgets/QMenuBar> #include <QtWidgets/QStatusBar> #include <QtWidgets/QToolBar> #include <QtWidgets/QWidget> #include <QtWidgets/QMenu> #include <QtWidgets/QAction> #include <QtWidgets/QLabel> #include <QtWidgets/QPushButton> #include <QtWidgets/QVBoxLayout> QT_BEGIN_NAMESPACE class Ui_HelloQtClass { public: QMenuBar *menuBar; QToolBar *mainToolBar; QWidget *centralWidget; QStatusBar *statusBar; QAction *act_language_zh; QAction *act_language_en; QLabel *lbl_hello; QPushButton *btn_quit; void setupUi(QMainWindow *HelloQtClass) { if (HelloQtClass->objectName().isEmpty()) HelloQtClass->setObjectName(QStringLiteral("HelloQtClass")); //HelloQtClass->resize(600, 400); HelloQtClass->setFixedSize(400, 160); menuBar = new QMenuBar(HelloQtClass); menuBar->setObjectName(QStringLiteral("menuBar")); HelloQtClass->setMenuBar(menuBar); mainToolBar = new QToolBar(HelloQtClass); mainToolBar->setObjectName(QStringLiteral("mainToolBar")); HelloQtClass->addToolBar(mainToolBar); centralWidget = new QWidget(HelloQtClass); centralWidget->setObjectName(QStringLiteral("centralWidget")); // add actions here. act_language_zh = new QAction(QObject::tr("Chinese"), HelloQtClass); act_language_en = new QAction(QObject::tr("English"), HelloQtClass); mainToolBar->addAction(act_language_zh); mainToolBar->addAction(act_language_en); // add your widgets here. lbl_hello = new QLabel(HelloQtClass); lbl_hello->setText(QObject::tr("<h2><i>Hello</i><font color=red>Qt!</font></h2>")); lbl_hello->setAlignment(Qt::AlignHCenter); btn_quit = new QPushButton(QObject::tr("&Quit"), HelloQtClass); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(lbl_hello); vLayout->addWidget(btn_quit); centralWidget->setLayout(vLayout); HelloQtClass->setCentralWidget(centralWidget); statusBar = new QStatusBar(HelloQtClass); statusBar->setObjectName(QStringLiteral("statusBar")); HelloQtClass->setStatusBar(statusBar); retranslateUi(HelloQtClass); QMetaObject::connectSlotsByName(HelloQtClass); } // setupUi void retranslateUi(QMainWindow *HelloQtClass) { // NOTE: the first parameter `context` in translate() must match the `context` in Qt Linguist. // [static] QString QCoreApplication::translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1) HelloQtClass->setWindowTitle(QApplication::translate("HelloQtClass", "HelloQt", nullptr)); // add your own translate here. act_language_zh->setText(QApplication::translate("QObject", "Chinese", nullptr)); act_language_en->setText(QApplication::translate("QObject", "English", nullptr)); lbl_hello->setText(QApplication::translate("QObject", "<h2><i>Hello</i><font color=red>Qt!</font></h2>", nullptr)); btn_quit->setText(QApplication::translate("QObject", "&Quit", nullptr)); } // retranslateUi }; namespace Ui { class HelloQtClass : public Ui_HelloQtClass {}; } // namespace Ui QT_END_NAMESPACE #endif // MYUI_HELLOQT_H
而後是 HelloQt.h
#pragma once #include <QtWidgets/QMainWindow> #include <QTranslator> #include "myUI_HelloQt.h" class HelloQt : public QMainWindow { Q_OBJECT public: HelloQt(QWidget *parent = Q_NULLPTR); public slots: void on_trigger_language_zh(bool checked); void on_trigger_language_en(bool checked); protected slots: void on_btn_quit_clicked(bool clicked); protected: void changeEvent(QEvent *event) override; private: Ui::HelloQtClass ui; QTranslator *language_zh; };
而後是 HelloQt.c
#include <QDebug> #include "HelloQt.h" HelloQt::HelloQt(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); // load translation language_zh = new QTranslator(this); language_zh->load(":/translations/helloqt_zh"); // signals and slots QObject::connect(ui.act_language_zh, SIGNAL(triggered(bool)), this, SLOT(on_trigger_language_zh(bool))); QObject::connect(ui.act_language_en, SIGNAL(triggered(bool)), this, SLOT(on_trigger_language_en(bool))); QObject::connect(ui.btn_quit, SIGNAL(clicked(bool)), this, SLOT(on_btn_quit_clicked(bool))); } void HelloQt::on_trigger_language_zh(bool checked) { qDebug() << QObject::tr("install Chinese") << endl; qApp->installTranslator(language_zh); } void HelloQt::on_trigger_language_en(bool checked) { qDebug() << HelloQt::tr("install English") << endl; qApp->removeTranslator(language_zh); } void HelloQt::on_btn_quit_clicked(bool clicked) { qApp->quit(); } //************************************ // Method: changeEvent // FullName: HelloQt::changeEvent // Access: protected // Returns: void // Qualifier: // Parameter: QEvent * event // Description: change language. //************************************ void HelloQt::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { ui.retranslateUi(this); } else { QMainWindow::changeEvent(event); } }
而後是翻譯文件 helloqt_zh.ts
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="zh_CN"> <context> <name>HelloQt</name> <message> <location filename="HelloQt.cpp" line="27"/> <source>install English</source> <oldsource>English</oldsource> <translation>安裝英文</translation> </message> </context> <context> <name>HelloQtClass</name> <message> <location filename="myUI_HelloQt.h" line="80"/> <source>HelloQt</source> <translation>你好Qt</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="myUI_HelloQt.h" line="49"/> <location filename="myUI_HelloQt.h" line="83"/> <source>Chinese</source> <translation>中文</translation> </message> <message> <location filename="myUI_HelloQt.h" line="50"/> <location filename="myUI_HelloQt.h" line="84"/> <source>English</source> <translation>英文</translation> </message> <message> <location filename="myUI_HelloQt.h" line="56"/> <location filename="myUI_HelloQt.h" line="85"/> <source><h2><i>Hello</i><font color=red>Qt!</font></h2></source> <translation><h2><i>你好</i><font color=red>Qt!</font></h2></translation> </message> <message> <location filename="myUI_HelloQt.h" line="59"/> <location filename="myUI_HelloQt.h" line="86"/> <source>&Quit</source> <translation>&退出</translation> </message> <message> <location filename="HelloQt.cpp" line="21"/> <source>install Chinese</source> <translation>安裝中文</translation> </message> </context> </TS>
而後是資源文件 HelloQt.qrc
<RCC> <qresource prefix="/translations"> <file alias="helloqt_zh">helloqt_zh.qm</file> </qresource> </RCC>
歡迎轉載,請註明出處和做者,同時保留聲明。
做者:LinTeX9527
出處:http://www.javashuo.com/article/p-hbpvjhvm-gr.html 本博客的文章如無特殊說明,均爲原創,轉載請註明出處。如未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。