QT中文亂碼與國際化支援

pamxy發表於2013-03-27

轉自:http://blog.csdn.net/alicehyxx/article/details/4960571

QT國際化支援

    Qt內部採用的全Unicode編碼,這從根本上保證了多國語介面實現的正確性和便捷性。Qt本身提供的linguist工具,用來實現翻譯過程十分方便。MFC中利用資源DLL切換資源,或使用多個RC檔案進行不同語言版本編譯等方法都十分麻煩,如果你曾經使用過MFC,QT解決多語言問題的便捷性絕對會讓你感覺是一種享受。本文討論以下幾個方面內容:

1、  QT中解決中文亂碼的方法;

2、  QT中實現國家化支援。

3、  對話方塊實現多語言

一、       中文亂碼

1、  在程式中直接使用中文,需要在程式中加入以下程式碼:

  1. #include <QTextCodec>  
  2.   
  3. int main(int argc, char **argv)  
  4. {  
  5.            QApplication app(argc, argv);  
  6.            QTextCodec *codec = QTextCodec::codecForName("GB2312");  
  7.   
  8.            QTextCodec::setCodecForLocale(codec);  
  9.            QTextCodec::setCodecForCStrings(codec);  
  10.            QTextCodec::setCodecForTr(codec);  
  11.   
  12.            …… ……  
  13.             return app.exec();  
  14. }  

這樣在程式中使用tr(“中文”)或者直接使用“中文”了;

2、  解決讀取ini檔案中中文亂碼

QSettings settings("xxxx.ini",QSettings::IniFormat);

settings.setIniCodec(QTextCodec::codecForName("GB2312")); settings.beginGroup("company");

3、  解決讀取中文檔案中文的亂碼

  1. QFile file("xxxx.txt");  
  2. QTextStream stream(file,QIODevice::ReadOnly);  
  3. stream.setCodeC( QTextCodec::codecForName("GB2312") );  
  4. 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

 

  1. #include "stdafx.h"  
  2. #include <QtGui/QApplication>  
  3. #include <QtGui/QtGui>  
  4. #include "DialogLogin.h"  
  5.   
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QApplication app(argc, argv);  
  9.     QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());  
  10.   
  11.     // 安裝QT執行庫翻譯器  
  12.     QTranslator translatorQT;  
  13.     {  
  14.         QStringList environment = QProcess::systemEnvironment();  
  15.         QString str;  
  16.         bool bFinded = false;  
  17.   
  18.         foreach(str, environment)  
  19.         {  
  20.             if(str.startsWith("QTDIR="))  
  21.             {  
  22.                 bFinded = true;  
  23.                 break;  
  24.             }  
  25.         }  
  26.   
  27.         if(bFinded)  
  28.         {  
  29.             str = str.mid(6);  
  30.             bFinded = translatorQT.load("qt_" + QLocale::system().name(),str.append("/translations/"));  
  31.   
  32.             if(bFinded)  
  33.                 app.installTranslator(&translatorQT);  
  34.             else  
  35.                 qDebug() <<QObject::tr("Can't find the translation file for Chinese!");  
  36.         }  
  37.         else  
  38.         {  
  39.             qDebug() << QObject::tr("Please set the environment variable QTDIR");  
  40.         }  
  41.     }  
  42.   
  43.     // 安裝程式自身翻譯器  
  44.     QTranslator translatorApp;  
  45.     {  
  46.         QString strLanguageDir = QCoreApplication::applicationDirPath();  
  47.         strLanguageDir.append("/Language/");  
  48.   
  49.         QString strFilePath = QApplication::applicationFilePath();  
  50.         QString strFileName = strFilePath.right(strFilePath.size() - strFilePath.lastIndexOf('/') - 1);  
  51.   
  52.         strFileName = strFileName.left(strFileName.indexOf('.'));  
  53.         strFileName.append('_');  
  54.         strFileName.append(QLocale::system().name());  
  55.         bool bFinded = translatorApp.load(strFileName,strLanguageDir);  
  56.   
  57.         if(bFinded)  
  58.             app.installTranslator(&translatorApp);  
  59.         else  
  60.         {  
  61.             qDebug() << QObject::tr("Can't Find The Translation's File For Chinese!");  
  62.         }  
  63.     }  
  64.   
  65.     CDialogLogin dlg;  
  66.   
  67.     return dlg.exec();  
  68. }  

DialogLogin.h

  1. #pragma once  
  2. #include <QtGui/QDialog>  
  3.   
  4. class QLineEdit;  
  5. class CDialogLogin : public QDialog  
  6. {  
  7.     Q_OBJECT  
  8.   
  9. public:  
  10.     CDialogLogin(QWidget* parent = 0);  
  11.     ~CDialogLogin(void);  
  12.   
  13. public slots:  
  14.     virtual     void    accept();  
  15.   
  16. private:  
  17.     QLineEdit*  m_pUsrLineEdit;  
  18.     QLineEdit*  m_pPwdLineEdit;  
  19. };  

程式中使用了兩個QTranslator物件,在app利用函式installTranslator()進行翻譯器安裝時,並沒有拷貝qm檔案,而是在需要的時候在qm檔案中進行查詢。也即是說:QTranslator在load以後,並沒有把qm檔案中的資料拷貝一份。如果qm在這期間被刪除或修改,對程式都是有影響的。擴充套件開來,QTranslator必須保證要一直有效,如果在函式中定義的區域性變數,函式結束後就自動釋放掉了,那麼翻譯工作就不能正常進行。
DialogLogin.cpp

  1. #include "stdafx.h"  
  2. #include "DialogLogin.h"  
  3. #include <QtGui/QtGui>  
  4.   
  5. CDialogLogin::CDialogLogin(QWidget* parent/* = 0 */)  
  6.     : QDialog(parent)  
  7. {  
  8.     QLabel* pUsrLabel = new QLabel(tr("User Name:"));  
  9.     QLabel* pPwdLabel = new QLabel(tr("Password:"));  
  10.   
  11.     m_pUsrLineEdit = new QLineEdit();  
  12.     m_pPwdLineEdit = new QLineEdit();  
  13.     m_pPwdLineEdit->setEchoMode(QLineEdit::Password);  
  14.   
  15.     QGridLayout* pGridLayout = new QGridLayout();  
  16.   
  17.     pGridLayout->addWidget(pUsrLabel,0,0,1,1);  
  18.     pGridLayout->addWidget(m_pUsrLineEdit,0,1,1,3);  
  19.     pGridLayout->addWidget(pPwdLabel,1,0,1,1);  
  20.     pGridLayout->addWidget(m_pPwdLineEdit,1,1,1,3);  
  21.     pGridLayout->setSpacing(25);  
  22.   
  23.     QPushButton* pBtnOK = new QPushButton(tr("Login"));  
  24.     QPushButton* pBtnCancel = new QPushButton(tr("Cancel"));  
  25.   
  26.     QHBoxLayout* pBtnLayout = new QHBoxLayout();  
  27.     pBtnLayout->setSpacing(60);  
  28.     pBtnLayout->addWidget(pBtnOK);  
  29.     pBtnLayout->addWidget(pBtnCancel);  
  30.   
  31.     QVBoxLayout* pDlgLayout = new QVBoxLayout();  
  32.     pDlgLayout->setMargin(30);  
  33.     pDlgLayout->addLayout(pGridLayout);  
  34.     pDlgLayout->addStretch(40);  
  35.     pDlgLayout->addLayout(pBtnLayout);  
  36.     pDlgLayout->setSpacing(40);  
  37.     setLayout(pDlgLayout);  
  38.   
  39.     connect(pBtnOK,SIGNAL(clicked()),this,SLOT(accept()));  
  40.     connect(pBtnCancel,SIGNAL(clicked()),this,SLOT(reject()));  
  41.   
  42.     setWindowTitle(tr("Login"));  
  43.     resize(300,200);  
  44. }  
  45.   
  46. CDialogLogin::~CDialogLogin(void)  
  47. {  
  48. }  
  49.   
  50. void CDialogLogin::accept()  
  51. {  
  52.     if(m_pUsrLineEdit->text().trimmed() == tr("lcf") && m_pPwdLineEdit->text().trimmed() == tr("lcf"))  
  53.     {  
  54.         QDialog::accept();  
  55.     }  
  56.     else  
  57.     {  
  58.         QMessageBox::warning(this,tr("Warning"),tr("User Name or Password is wrong!"),QMessageBox::Yes);  
  59.   
  60.         m_pUsrLineEdit->setFocus();  
  61.     }  
  62. }  


其中英文介面如圖:

圖1.2 英文介面

 


中文介面如圖:

圖1.3 中文介面

 


相關文章