QT国际化支持
Qt内部采用的全Unicode编码,这从根本上保证了多国语界面实现的正确性和便捷性。Qt本身提供的linguist工具,用来实现翻译过程十分方便。MFC中利用资源DLL切换资源,或使用多个RC文件进行不同语言版本编译等方法都十分麻烦,如果你曾经使用过MFC,QT解决多语言问题的便捷性绝对会让你感觉是一种享受。本文讨论以下几个方面内容:
1、QT中解决中文乱码的方法;
2、QT中实现国家化支持。
3、对话框实现多语言
一、中文乱码
1、在程序中直接使用中文,需要在程序中加入以下代码:
- #include<QTextCodec>
- int main( int argc, char **argv)
- {
- QApplicationapp(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、解决读取中文文件中文的乱码
- QFilefile( "xxxx.txt" );
- QTextStreamstream(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[])
- {
- QApplicationapp(argc,argv);
- QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
- //安装QT运行库翻译器
- QTranslatortranslatorQT;
- {
- QStringListenvironment=QProcess::systemEnvironment();
- QStringstr;
- 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'tfindthetranslationfileforChinese!" );
- }
- else
- {
- qDebug()<<QObject::tr( "PleasesettheenvironmentvariableQTDIR" );
- }
- }
- //安装程序自身翻译器
- QTranslatortranslatorApp;
- {
- QStringstrLanguageDir=QCoreApplication::applicationDirPath();
- strLanguageDir.append( "/Language/" );
- QStringstrFilePath=QApplication::applicationFilePath();
- QStringstrFileName=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'tFindTheTranslation'sFileForChinese!" );
- }
- }
- CDialogLogindlg;
- return dlg.exec();
- }
DialogLogin.h
- #pragmaonce
- #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( "UserName:" ));
- 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( "UserNameorPasswordiswrong!" ),QMessageBox::Yes);
- m_pUsrLineEdit->setFocus();
- }
- }
其中英文界面如图:
图1.2英文界面
图1.3中文界面