摘要:本文論述瞭如何使用QT實現程序的多語系支持以及多語系的動態切換。
前沿
我們生活中用到的程序大多都是支持單一語言的,比如在中國我們用到的軟件大多是漢語的,也有很少部分使用的是英語的,但是很少有軟件可以實現兩種語言的動態切換。不過隨着近幾年我國的發展支持多國語言的軟件也越來越多,比如上海地鐵售票機,動車組自動售票機等都是支持漢語和英語兩種語言的。使用QT編程可以很容易的編寫支持多國語言的軟件。
用QT實現多國語言支持有兩種情況:
第一種:使用UI編輯器來自動生成界面,這種方式實現多語系的動態切換很容易。
第二種:不使用UI編輯器,自己通過親自編程來設計應用程序界面,這種方式實現多語系動態切換比較繁瑣,注意不是難;
下面先來介紹第一種的實現方法:
voidMainWindow::ch_language()
{
if(this->languageState)
{
this->languageState=CHINESE ;
this->translator.load("test_ch") ;
this->pOwner->installTranslator(&(this->translator));
}
else
{
this->languageState=ENGLISH ;
this->translator.load("test_en") ;
this->pOwner->installTranslator(&(this->translator));
}
}
這個函數是實現動態切換的主要程序,其中languageState是用來記錄當前語言的狀態,pOwner是QApplication對象,我們只需使用QTranslator加載不同的文件就可以實現多語系的動態切換。
第二種方式就不那麼簡單了,除了要運行上述函數外還要將將要切換的語言重新設置一遍。
voidMainWindow::langChang()
{
if(this->langState)
{
this->langState=CHINESE ;
this->translator.load("test_ch") ;
this->pOwner->installTranslator(&(this->translator));
}
else
{
this->langState=ENGLISH ;
this->translator.load("test_en") ;
this->pOwner->installTranslator(&(this->translator));
}
this->setWindowTitle(QObject::tr("hello world"));
this->addFileAction->setText(QObject::tr("NewFile"));
this->langChAction->setText(QObject::tr("Chinese"));
this->playAction->setText(QObject::tr("Play")); ;
this->stopAction->setText(QObject::tr("Stop"));
this->menuBar()->addMenu(QObject::tr("FIle")) ;
this->menuBar()->addMenu(QObject::tr("Control"));
}
因此比較麻煩,特別是界面比較繁瑣的時候,將是很麻煩的。
下面來討論爲什麼第一種方法爲什麼不需要重新設置語言了。因爲使用Ui時有這個函數
voidMainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);//這裏實現語言翻譯器的更新。
下面就來看一下QT中如何製作多語言包。
實現方法:
爲了支持國際化最關鍵的地方是製作多國語言包,然後再實現動態切換。QT裏面既可以採用命令行也可以採用Qt Creator的界面操作來生成,這裏我們利用Qt Creator來生成多國語言包。基本流程是,先生成ts文件,然後生成qm文件,最後通過QTranslator類來加載qm文件,實現多語言包的切換。注意:爲了更全面地實現多語言包,在程序中所有涉及到界面中的按鈕或者菜單中的文字顯示,都必須使用 QObject::tr("...") 的方式將顯示的內容包裹起來,這樣做的原因是:只有添加了QObject::tr()的標記,生成ts文件的時候程序纔會認爲被QObject::tr()包裹的地方是需要製作多語言的,從而在ts中預留出位置。
1> 生成ts文件
在QT的項目文件(.pro)中添加:TRANSLATIONS = XXX.ts YYY.ts(如果是多行,則用 \ 分割)
然後執行【工具】-》【外部】-》【QT語言家】-》【更新翻譯(lupdate)】,如下圖所示,執行完之後項目下就會生成對應的XXX.ts、YYY.ts文件。
注意:如果項目中包含ui文件,如:FORMS += ZZZ.ui,則在生成的ts文件中包含所有ui文件上的字符顯示,而且,在製作ui文件時默認情況下界面上的文字顯示都是通過QObejct::tr(" ")包裹的,因爲在默認情況下ui中的所有控件都存在一個屬性:可翻譯的,就代表了默認用QObject::tr()嵌套了。
2. 生成qm文件
利用QT語言家:Linguist打開生成的ts文件,將裏面需要翻譯的地方寫上對應的語言,如下圖所示:
ts文件翻譯完成後,執行Qt Creator中的【工具】-》【外部】-》【QT語言家】-》【部署翻譯(lrelease)】就會生成最終要用到的qm文件,如下圖所示:
3. 加載qm語言包
到這裏qm語言包製作完成,工作就完成了一大半了。接下來的任務就是在代碼中實現語言包的加載,即:根據不同的選擇加載不同的語言包。
voidLHSyncClientPrivate::InitUiByLanguage(const QString strLanguage)
{
if (strLanguage.isEmpty())
{
return;
}
QString strLanguageFile;
if (strLanguage.compare("en") ==0)
{
strLanguageFile = qApp->applicationDirPath()+QString("/languages/%1/%2").arg(LHT_SYNCCLIENT_VERSION_PRODOCUTNAME).arg(LHT_SYNCCLIENT_EN_FILE);
}
else if(strLanguage.compare("zh") == 0)
{
strLanguageFile =qApp->applicationDirPath() + QString("/languages/%1/%2").arg(LHT_SYNCCLIENT_VERSION_PRODOCUTNAME).arg(LHT_SYNCCLIENT_ZH_FILE);
}
if (QFile(strLanguageFile).exists())
{
m_translator->load(strLanguageFile);
qApp->installTranslator(m_translator);
}
else
{
qDebug() << "[houqd]authclient language file does not exists ...";
}
}
其中,m_translator即爲QTranslator實例,在類的構造函數中賦值:m_translator = new QTranslator;實現過程很簡單,就是取得語言包的絕對路徑,然後利用QTranslator來加載它,最後利用qApp->installTranslator(m_translator)來安裝。
4. 重新設置界面顯示
重新設置界面的顯示,這一步是很多人容易忘記的一步,如果這兒被忽略了,往往就無法完成語言的切換,即:重新設置一下需要顯示的元素,該過程是在上面InitUiByLanguage過程之後進行的,相關代碼如下:
voidLHSyncClientPrivate::RetranslateUi()
{
m_wgtSync->setWindowTitle(tr("DriveClient"));
//! 左側同步信息
m_btnSynchronizing->setText(tr("Synchronizing"));
m_btnSynchronized->setText(tr("Synchronized"));
//! 右側面板
m_lblSyncStatus->setText(tr("looking for fileschanges..."));
m_lblShowRecordsNum->setText(tr("There are n records..."));
m_btnSyncOrPause->setText(tr("SyncOr Pause"));
m_btnClearAll->setText(tr("Clearall"));
m_btnSyncOrPause->setText(tr("SyncOr Pause"));
m_btnClose->setText(tr("Close"));
m_actSync->setText(tr("SyncInfo"));
}
實現效果:
好了,到這裏整個語言包的製作過程就基本完成了。這裏還需要提及一點在網盤客戶端實現時的設計思路:由於網盤在登錄前和登錄後可操作的菜單是不一樣的,要涉及一種動態加載的方式,可以實現一個UiLoader的插件,它實現所有的窗體加載(即LoadUi()返回QWidget句柄)、菜單加載、語言切換,在這些功能中可能UiLoader插件並不完成具體的工作,而僅僅是實現信號的轉發功能。同樣,也需要實現一個邏輯控制插件,它負責所有的菜單邏輯,而對於每個窗體則由各自的窗體插件自行完成。多語言切換的實現效果如下:
切換爲中文:
切換後效果:
加油,堅持每天的學習!!