QT國際化支持
Qt內部采用的全Unicode編碼,這從根本上保證了多國語界面實現的正確性和便捷性。Qt本身提供的linguist工具,用來實現翻譯過程十分方便。MFC中利用資源DLL切換資源,或使用多個RC文件進行不同語言版本編譯等方法都十分麻煩,如果你曾經使用過MFC,QT解決多語言問題的便捷性絕對會讓你感覺是一種享受。本文討論以下幾個方面內容:
1、 QT中解決中文亂碼的方法;
2、 QT中實現國家化支持。
3、 對話框實現多語言
一、 中文亂碼
1、 在程序中直接使用中文,需要在程序中加入以下代碼:
- #include <QTextCodec>
- int main(int argc, char **argv)
- {
- QApplication app(argc, argv);
- QTextCodec *codec = QTextCodec::codecForName("GB2312");
- QTextCodec::setCodecForLocale(codec);
- QTextCodec::setCodecForCStrings(codec);
- QTextCodec::setCodecForTr(codec);
- …… ……
- return app.exec();
- }
這樣在程序中使用tr(“中文”)或者直接使用“中文”了;
2、 解決讀取ini文件中中文亂碼
QSettings settings("xxxx.ini",QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("GB2312")); settings.beginGroup("company");
3、 解決讀取中文文件中文的亂碼
- QFile file("xxxx.txt");
- QTextStream stream(file,QIODevice::ReadOnly);
- stream.setCodeC( QTextCodec::codecForName("GB2312") );
- stream.readAll();
二、 國際化支持
QT中實現多國語言,建議在程序中直接英文,而后通過不同的翻譯文件實現多語言的支持。實現多國語的步驟有如下幾步(提及的工具均為QT自帶):
Ø 在需要被翻譯的字符串前面加標識tr,如QString str = tr(“hello,world!”); 這很重要,因為翻譯工具會把源碼中tr標識的字符串提取出來,翻譯成其他語言,如果沒有用tr標識的,不會被工具提取。在界面中輸入的文字,默認已經是加上tr的了,所以在翻譯時也能看見。
Ø 在QT工程文件*.pro中增加一項:TRANSLATIONS += *.ts,擴展名為.ts是翻譯的源文件。一般會在命名中把區域加進去,更好的注釋這些文件是用於什么語言的,可以根據“語言_國家”的形式形成文件名。比如中命名為myapp_zh_CN.ts, zh表示簡體中文,而CN表示的就是中華人名共和國。可以參照ISO語言與國家代碼標准:http://blog.csdn.net/alicehyxx/archive/2009/12/06/4952318.aspx
Ø 使用lupdate工具提取翻譯源文件,【運行】中輸入CMD,打開命令行窗口,利用CD命令切換到QT安裝目錄的BIN目錄中,而后輸入:
lupdate *.pro
*.pro包含pro文件的全路徑。lupdate會解析*.pro文件,生成TRANSLATIONS中的 *.ts 文件,這些文件可以被linguist工具打開,按照提示一個一個的翻譯成需要的文件並保存。
Ø 重復以上兩步! (針對以上兩步,VS2005中可以直接使用菜單【QT】à 【Create new translations File】創建,如果文件已經存在,可以通過圖1.1菜單進行更新。)
圖1.1 VS2005_lupdate
Ø 使用lrelease工具發布翻譯文件的二進制文件,這樣在程序運行時載入會大大的加快速度。在命令行窗口中繼續輸入:
lrelease *.ts
*.ts包含ts文件的全路徑。這個工具會提示你多少語句被翻譯,多少被忽略了等。生成的文件是*.qm,與同名的 *.ts只是換了一個擴展名。這個就是我們程序需要使用到的文件。
(VS2005中可以使用圖1.1中的菜單lrelease來實現該步驟)
Ø 使用*.qm文件。程序可以通過兩種方式加載翻譯文件,一種硬編碼方式,直接指定加載的語言,代碼如下:
int main(int argc,char* argv[])
{
QApplication app(arcg,argv);
QTranslator translator;
translator.load(“basicdraw_zh_CN”);
app.installTranslator(&translator);
}
另外一種是自動判斷翻譯當前的locale,再裝入相應的翻譯文件,如下所示:
int main(int argc,char* argv[])
{
QApplication app(arcg,argv);
QString locale = QLocale::system().name();
QTranslator translator;
translator.load(QString(“basicdraw_”) + locale);
app.installTranslator(&translator);
}
其中QLocale::system().name()返回以“語言_國家”形式形成的字符串,比如zh_CN。
至於通過控件,比如ComboBox選擇語言,並實現動態切換,以后再討論。
三、 對話框實現多語言
在實際程序中實現多語言切換,需要生成的qm文件應該包含兩個:
Ø QT運行庫相關的qm文件:在QT安裝目錄的translations目錄下,存在需要*.ts文件,利用lrelease命令生成對應的qm文件。
Ø 利用“二”中的步驟生成程序本身需要的*.ts文件,並生成qm文件。
QApplication支持多個翻譯文件,並根據后加入先使用的搜索順序進行搜索。
具體代碼如下: main.cpp
- #include "stdafx.h"
- #include <QtGui/QApplication>
- #include <QtGui/QtGui>
- #include "DialogLogin.h"
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
- // 安裝QT運行庫翻譯器
- QTranslator translatorQT;
- {
- QStringList environment = QProcess::systemEnvironment();
- QString str;
- bool bFinded = false;
- foreach(str, environment)
- {
- if(str.startsWith("QTDIR="))
- {
- bFinded = true;
- break;
- }
- }
- if(bFinded)
- {
- str = str.mid(6);
- bFinded = translatorQT.load("qt_" + QLocale::system().name(),str.append("/translations/"));
- if(bFinded)
- app.installTranslator(&translatorQT);
- else
- qDebug() <<QObject::tr("Can't find the translation file for Chinese!");
- }
- else
- {
- qDebug() << QObject::tr("Please set the environment variable QTDIR");
- }
- }
- // 安裝程序自身翻譯器
- QTranslator translatorApp;
- {
- QString strLanguageDir = QCoreApplication::applicationDirPath();
- strLanguageDir.append("/Language/");
- QString strFilePath = QApplication::applicationFilePath();
- QString strFileName = strFilePath.right(strFilePath.size() - strFilePath.lastIndexOf('/') - 1);
- strFileName = strFileName.left(strFileName.indexOf('.'));
- strFileName.append('_');
- strFileName.append(QLocale::system().name());
- bool bFinded = translatorApp.load(strFileName,strLanguageDir);
- if(bFinded)
- app.installTranslator(&translatorApp);
- else
- {
- qDebug() << QObject::tr("Can't Find The Translation's File For Chinese!");
- }
- }
- CDialogLogin dlg;
- return dlg.exec();
- }
DialogLogin.h
- #pragma once
- #include <QtGui/QDialog>
- class QLineEdit;
- class CDialogLogin : public QDialog
- {
- Q_OBJECT
- public:
- CDialogLogin(QWidget* parent = 0);
- ~CDialogLogin(void);
- public slots:
- virtual void accept();
- private:
- QLineEdit* m_pUsrLineEdit;
- QLineEdit* m_pPwdLineEdit;
- };
程序中使用了兩個QTranslator對象,在app利用函數installTranslator()進行翻譯器安裝時,並沒有拷貝qm文件,而是在需要的時候在qm文件中進行查找。也即是說:QTranslator在load以后,並沒有把qm文件中的數據拷貝一份。如果qm在這期間被刪除或修改,對程序都是有影響的。擴展開來,QTranslator必須保證要一直有效,如果在函數中定義的局部變量,函數結束后就自動釋放掉了,那么翻譯工作就不能正常進行。 DialogLogin.cpp
- #include "stdafx.h"
- #include "DialogLogin.h"
- #include <QtGui/QtGui>
- CDialogLogin::CDialogLogin(QWidget* parent/* = 0 */)
- : QDialog(parent)
- {
- QLabel* pUsrLabel = new QLabel(tr("User Name:"));
- QLabel* pPwdLabel = new QLabel(tr("Password:"));
- m_pUsrLineEdit = new QLineEdit();
- m_pPwdLineEdit = new QLineEdit();
- m_pPwdLineEdit->setEchoMode(QLineEdit::Password);
- QGridLayout* pGridLayout = new QGridLayout();
- pGridLayout->addWidget(pUsrLabel,0,0,1,1);
- pGridLayout->addWidget(m_pUsrLineEdit,0,1,1,3);
- pGridLayout->addWidget(pPwdLabel,1,0,1,1);
- pGridLayout->addWidget(m_pPwdLineEdit,1,1,1,3);
- pGridLayout->setSpacing(25);
- QPushButton* pBtnOK = new QPushButton(tr("Login"));
- QPushButton* pBtnCancel = new QPushButton(tr("Cancel"));
- QHBoxLayout* pBtnLayout = new QHBoxLayout();
- pBtnLayout->setSpacing(60);
- pBtnLayout->addWidget(pBtnOK);
- pBtnLayout->addWidget(pBtnCancel);
- QVBoxLayout* pDlgLayout = new QVBoxLayout();
- pDlgLayout->setMargin(30);
- pDlgLayout->addLayout(pGridLayout);
- pDlgLayout->addStretch(40);
- pDlgLayout->addLayout(pBtnLayout);
- pDlgLayout->setSpacing(40);
- setLayout(pDlgLayout);
- connect(pBtnOK,SIGNAL(clicked()),this,SLOT(accept()));
- connect(pBtnCancel,SIGNAL(clicked()),this,SLOT(reject()));
- setWindowTitle(tr("Login"));
- resize(300,200);
- }
- CDialogLogin::~CDialogLogin(void)
- {
- }
- void CDialogLogin::accept()
- {
- if(m_pUsrLineEdit->text().trimmed() == tr("lcf") && m_pPwdLineEdit->text().trimmed() == tr("lcf"))
- {
- QDialog::accept();
- }
- else
- {
- QMessageBox::warning(this,tr("Warning"),tr("User Name or Password is wrong!"),QMessageBox::Yes);
- m_pUsrLineEdit->setFocus();
- }
- }
其中英文界面如圖:
圖1.2 英文界面
中文界面如圖:
圖1.3 中文界面