Qt多语言实现和动态切换(国际化)
Qt 界面实现多国语言的切换实例是本文要介绍的内容,一直认为Qt界面相对于还是很好实现的一种开发。多国语界面的实现,在MFC中是很别扭的。以前在作MFC时,实现多国语言的界面,只有把资源文件做成各个语言的资源DLL,在程序启动时,根据选择判断选择载入哪个DLL来获取资源。MFC的资源也是分语言的,在创建资源的时候要选择,但是这样的实现还有有弊端。最根本的原因是MFC的资源文件不是Unicode编码的,而是不同语言的本地码,至少VC6是这样的。这样在中文系统中载入日文的资源,界面出现的是乱码。
Qt内部采用的全Unicode编码,这从根本上保证了多国语界面实现的正确性和便捷性。Qt本身提供的linguist工具,就是来实现这个翻译过程的。实现多国语的步骤大体上说来有这么几步:
1、在需要被翻译的字符串前面标识tr,如QString str=tr(“hello,world!”); ,这很重要,因为翻译工具会把源码中tr标识的字符串提取出来,翻译成其他语言,如果没有用tr标识的,不会被工具提取。在界面中输入的文字,默认已经是加上tr的了,所以在翻译时也能看见。
点击(此处)折叠或打开
-
ui->pushButton_CN->setText(tr("Chinese"));
-
ui->pushButton_DE->setText(tr("Germen"));
-
ui->pushButton_EN->setText(tr("English"));
-
ui->pushButton->setText(tr("Switch"));
-
ui->radioButton_CN->setText(tr("Chinese"));
-
ui->radioButton_DE->setText(tr("Germen"));
-
ui->radioButton_EN->setText(tr("English"));
- setWindowTitle(tr("MainWindow"));
2、在工程文件***.pro中,添加一项 TRANSLATIONS += ***.ts ****.ts 扩展名为.ts是翻译的源文件,表示生成这几个文件。一般我们会在命名中把区域加进去,更好的注释这些文件是用于什么语言的,比如中文大多会这样命名 myapp_zh_CN.ts, zh_CN表示的就是中国。
点击(此处)折叠或打开
-
TRANSLATIONS+=cn.ts \
-
de.ts \
- en.ts
3、使用lupdate工具提取翻译源文件, 命令是这样的 #lupdate ***.pro ,或者通过Qt Creator的图形界面来生成***.ts文件。lupdate会解析***.pro即工程文件,生成TRANSLATIONS中的 ***.ts 几个文件,这些文件可以被linguist工具打开,按照提示一个一个的翻译成需要的文件,然后保存就OK,
linguist的使用很简单,一看界面基本就会了。上面提到的这些工具都是Qt自带的。
4、使用lrelease工具发布翻译文件的二进制文件,这样在程序运行时载入会大大的加快速度。使用方式是#lrelease ***.pro,或者通过Qt Creator的图形界面来生成***.qm文件。这个工具会提示你多少语句被翻译,多少被忽略了等。生成的文件是 ***.qm,于同名的 ***.ts只是换了一个扩展名。而这才是我们程序需要使用到的文件。
5、使用***.qm文件。关于这个,我想还是摘抄书上的原文来说明一下:
切换语言分为两种情况:
方法1:手动导入XXX.qm文件,在更新tr("XXX")的文件。如果有子窗口的话,子窗口通过模式对话框显示,子窗口翻译可以更新;如果用非模式对话框,子窗口翻译无法更新
1. 程序载入的时候,根据当前的区域设置,自动选择语言包(.qm),即可;
2. 要求在程序运行过程中动态切换语言,需要
点击(此处)折叠或打开
-
void MainWindow::loadLanguage()
-
{
-
QTranslator translator;
-
bool b = false;
-
b = translator.load(":/Lan/cn");
-
qApp->installTranslator(&translator);
-
ui->radioButton_CN->setChecked(true);
-
RefreshUI();
-
}
-
-
void MainWindow::RefreshUI()
-
{
-
ui->pushButton_CN->setText(tr("Chinese"));
-
ui->pushButton_DE->setText(tr("Germen"));
-
ui->pushButton_EN->setText(tr("English"));
-
ui->pushButton->setText(tr("Switch"));
-
ui->radioButton_CN->setText(tr("Chinese"));
-
ui->radioButton_DE->setText(tr("Germen"));
-
ui->radioButton_EN->setText(tr("English"));
-
setWindowTitle(tr("MainWindow"));
- }
点击(此处)折叠或打开
-
void MainWindow::loadLanguage()
-
{
-
QTranslator translator;
-
bool b = false;
-
b = translator.load(":/Lan/cn");
-
qApp->installTranslator(&translator);
-
ui->radioButton_CN->setChecked(true);
-
RefreshUI();
-
}
-
-
void MainWindow::RefreshUI()
-
{
-
ui->pushButton_CN->setText(tr("Chinese"));
-
ui->pushButton_DE->setText(tr("Germen"));
-
ui->pushButton_EN->setText(tr("English"));
-
ui->pushButton->setText(tr("Switch"));
-
ui->radioButton_CN->setText(tr("Chinese"));
-
ui->radioButton_DE->setText(tr("Germen"));
-
ui->radioButton_EN->setText(tr("English"));
-
setWindowTitle(tr("MainWindow"));
- }
需要说明的时, 一般我们使用设计器来设计界面UI,也就是程序源码中我们看到的 ***.ui文件,在载入翻译器后,我们应该调用 ui->retranslateUi() ,这个函数实际上就是把界面控件的text重新载入一遍,可以在 ui_***.cpp中看到该函数的实现。
点击(此处)折叠或打开
-
#include "mainwindow.h"
-
#include "ui_mainwindow.h"
-
-
-
MainWindow::MainWindow(QWidget *parent) :
-
QMainWindow(parent),
-
ui(new Ui::MainWindow)
-
{
-
ui->setupUi(this);
-
// Refresh();
-
initial();
-
}
-
-
MainWindow::~MainWindow()
-
{
-
delete ui;
-
lan.close();
-
}
-
void MainWindow::initial()
-
{
-
m_lan_flag = LAN_EN;
-
m_translator.load(":/Lan/en");
-
ui->radioButton_EN->setChecked(true);
-
qApp->installTranslator(&m_translator);
-
RefreshUI();
-
}
-
-
void MainWindow::RefreshUI()
-
{
-
ui->pushButton_CN->setText(tr("Chinese"));
-
ui->pushButton_DE->setText(tr("Germen"));
-
ui->pushButton_EN->setText(tr("English"));
-
ui->pushButton->setText(tr("Switch"));
-
ui->radioButton_CN->setText(tr("Chinese"));
-
ui->radioButton_DE->setText(tr("Germen"));
-
ui->radioButton_EN->setText(tr("English"));
-
setWindowTitle(tr("MainWindow"));
-
}
-
-
void MainWindow::on_pushButton_EN_clicked()
-
{
-
m_lan_flag = LAN_EN;
-
autoLoadLanguage();
-
}
-
-
void MainWindow::on_pushButton_CN_clicked()
-
{
-
m_lan_flag = LAN_CN;
-
// ui->radioButton_CN->setChecked(true);
-
autoLoadLanguage();
-
}
-
-
void MainWindow::on_pushButton_DE_clicked()
-
{
-
m_lan_flag = LAN_DE;
-
autoLoadLanguage();
-
}
-
-
void MainWindow::on_pushButton_clicked()
-
{
-
// Method 1: Load language direct
-
loadLanguage();
-
-
// Method 2: Auto load language by QEvent::LanguageChange
-
// autoLoadLanguage();
-
-
-
}
-
-
void MainWindow::on_radioButton_CN_clicked()
-
{
-
m_lan_flag = LAN_CN;
-
ui->radioButton_CN->setChecked(true);
-
autoLoadLanguage();
-
}
-
void MainWindow::on_radioButton_EN_clicked()
-
{
-
m_lan_flag = LAN_EN;
-
ui->radioButton_EN->setChecked(true);
-
autoLoadLanguage();
-
}
-
void MainWindow::on_radioButton_DE_clicked()
-
{
-
m_lan_flag = LAN_DE;
-
ui->radioButton_DE->setChecked(true);
-
autoLoadLanguage();
-
}
-
void MainWindow::loadLanguage()
-
{
-
QTranslator translator;
-
bool b = false;
-
b = translator.load(":/Lan/cn");
-
qApp->installTranslator(&translator);
-
ui->radioButton_CN->setChecked(true);
-
-
// Method A: model dialog, translate is success in sub dialog
-
//lan.exec();
-
-
// Method B: model dialog, translate is success in sub dialog
-
lan.show();
-
lan.raise();
-
lan.activateWindow();
-
-
}
-
void MainWindow::autoLoadLanguage()
-
{
-
switch(m_lan_flag)
-
{
-
case LAN_CN:
-
//m_translator.load(QString("../LanguageChange/Lan/cn")); // Use
qm file by relative address
-
m_translator.load(QString(":/Lan/cn")); // Use
lan.qrc to load language
-
break;
-
case LAN_EN:
-
m_translator.load(QString(":/Lan/en"));
-
break;
-
case LAN_DE:
-
m_translator.load(QString(":/Lan/de"));
-
break;
-
}
-
qApp->installTranslator(&m_translator);
-
-
}
-
// Method 2: Use ChangeEvent to retranslateUi
-
void MainWindow::changeEvent(QEvent *event)
-
{
-
if(event->type() == QEvent::LanguageChange)
-
ui->retranslateUi(this);
-
else
-
QWidget::changeEvent(event);
- }
6,导入XXX.qm文件,
1) 可以通过XXX.qrc文件导入,但是通过XXX.qrc文件导入的话,每次qm文件有修改或更新,需要从新导入
2)也可以通过相对或绝对路径指定。
点击(此处)折叠或打开
-
case LAN_CN:
- //m_translator.load(QString("../LanguageChange/Lan/cn")); // Use qm file by relative address
7、在帮助文档中,关于 QTranslator::load有这样一句话。
The data is not copied. The caller must be able to guarantee that data will not be deleted or modifiled.
这段话明确的说明了,QTranslator在load以后,并没有把qm文件中的数据拷贝一份,而是在需要的时候去查询字符串。如果qm在这期间被删除或修改,对程序都是有影响的。扩展开来,QTranslator必须保证要一直有效,如果在函数中定义的局部变量,函数结束后就自动释放掉了,那么翻译工作就不能正常进行。所以建议在private中定义个成员变量 QTranslator*
app_translator;来确保整个翻译工作的正确性。
程序主要代码和运行效果
点击(此处)折叠或打开
-
QT += core gui
-
-
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-
TARGET = LanguageChange
-
TEMPLATE = app
-
-
-
SOURCES += main.cpp\
-
mainwindow.cpp \
-
languagewidget.cpp
-
-
HEADERS += mainwindow.h \
-
languagewidget.h
-
-
FORMS += mainwindow.ui \
-
languagewidget.ui
-
RESOURCES += lan.qrc
-
-
-
TRANSLATIONS+=cn.ts \
-
de.ts \
- en.ts
主窗口代码
点击(此处)折叠或打开
-
#include "mainwindow.h"
-
#include "ui_mainwindow.h"
-
-
-
MainWindow::MainWindow(QWidget *parent) :
-
QMainWindow(parent),
-
ui(new Ui::MainWindow)
-
{
-
ui->setupUi(this);
-
// Refresh();
-
initial();
-
}
-
-
MainWindow::~MainWindow()
-
{
-
delete ui;
-
lan.close();
-
}
-
void MainWindow::initial()
-
{
-
m_lan_flag = LAN_EN;
-
m_translator.load(":/Lan/en");
-
ui->radioButton_EN->setChecked(true);
-
qApp->installTranslator(&m_translator);
-
RefreshUI();
-
}
-
-
void MainWindow::RefreshUI()
-
{
-
ui->pushButton_CN->setText(tr("Chinese"));
-
ui->pushButton_DE->setText(tr("Germen"));
-
ui->pushButton_EN->setText(tr("English"));
-
ui->pushButton->setText(tr("Switch"));
-
ui->radioButton_CN->setText(tr("Chinese"));
-
ui->radioButton_DE->setText(tr("Germen"));
-
ui->radioButton_EN->setText(tr("English"));
-
setWindowTitle(tr("MainWindow"));
-
}
-
-
void MainWindow::on_pushButton_EN_clicked()
-
{
-
m_lan_flag = LAN_EN;
-
ui->radioButton_EN->setChecked(true);
-
autoLoadLanguage();
-
}
-
-
void MainWindow::on_pushButton_CN_clicked()
-
{
-
m_lan_flag = LAN_CN;
-
ui->radioButton_CN->setChecked(true);
-
autoLoadLanguage();
-
}
-
-
void MainWindow::on_pushButton_DE_clicked()
-
{
-
m_lan_flag = LAN_DE;
-
ui->radioButton_DE->setChecked(true);
-
autoLoadLanguage();
-
}
-
-
void MainWindow::on_pushButton_clicked()
-
{
-
// Method 1: Load language direct
-
//loadLanguage();
-
-
// Method 2: Auto load language by QEvent::LanguageChange
-
autoLoadLanguage();
-
-
-
}
-
-
void MainWindow::on_radioButton_CN_clicked()
-
{
-
m_lan_flag = LAN_CN;
-
ui->radioButton_CN->setChecked(true);
-
autoLoadLanguage();
-
}
-
void MainWindow::on_radioButton_EN_clicked()
-
{
-
m_lan_flag = LAN_EN;
-
ui->radioButton_EN->setChecked(true);
-
autoLoadLanguage();
-
}
-
void MainWindow::on_radioButton_DE_clicked()
-
{
-
m_lan_flag = LAN_DE;
-
ui->radioButton_DE->setChecked(true);
-
autoLoadLanguage();
-
}
-
void MainWindow::loadLanguage()
-
{
-
QTranslator translator;
-
bool b = false;
-
b = translator.load(":/Lan/cn");
-
qApp->installTranslator(&translator);
-
ui->radioButton_CN->setChecked(true);
-
-
// Method A: model dialog, translate is success in sub dialog
-
//lan.exec();
-
-
// Method B: model dialog, translate is success in sub dialog
-
lan.show();
-
lan.raise();
-
lan.activateWindow();
-
-
}
-
void MainWindow::autoLoadLanguage()
-
{
-
switch(m_lan_flag)
-
{
-
case LAN_CN:
-
//m_translator.load(QString("../LanguageChange/Lan/cn")); // Use
qm file by relative address
-
m_translator.load(QString(":/Lan/cn")); // Use
lan.qrc to load language
-
break;
-
case LAN_EN:
-
m_translator.load(QString(":/Lan/en"));
-
break;
-
case LAN_DE:
-
m_translator.load(QString(":/Lan/de"));
-
break;
-
}
-
qApp->installTranslator(&m_translator);
-
lan.show();
-
lan.raise();
-
lan.activateWindow();
-
-
}
-
// Method 2: Use ChangeEvent to retranslateUi
-
void MainWindow::changeEvent(QEvent *event)
-
{
-
if(event->type() == QEvent::LanguageChange)
-
ui->retranslateUi(this);
-
else
-
QWidget::changeEvent(event);
- }
子窗口代码
点击(此处)折叠或打开
-
#include "languagewidget.h"
-
#include "ui_languagewidget.h"
-
-
languageWidget::languageWidget(QDialog *parent) :
-
QDialog(parent),
-
ui(new Ui::languageWidget)
-
{
-
ui->setupUi(this);
-
m_lan_flag = LAN_EN;
-
RefreshUI();
-
}
-
-
languageWidget::~languageWidget()
-
{
-
delete ui;
-
}
-
-
void languageWidget::RefreshUI()
-
{
-
ui->pushButton_CN->setText(tr("Chinese"));
-
ui->pushButton_EN->setText(tr("English"));
-
ui->pushButton_GE->setText(tr("Germen"));
-
setWindowTitle(tr("Form"));
-
}
-
-
void languageWidget::on_pushButton_EN_clicked()
-
{
-
m_lan_flag = LAN_EN;
-
autoLoadLanguage();
-
}
-
-
void languageWidget::on_pushButton_CN_clicked()
-
{
-
m_lan_flag = LAN_CN;
-
autoLoadLanguage();
-
}
-
-
void languageWidget::on_pushButton_GE_clicked()
-
{
-
m_lan_flag = LAN_DE;
-
autoLoadLanguage();
-
}
-
void languageWidget::setlanguage(int language)
-
{
-
m_lan_flag = language;
-
}
-
-
void languageWidget::autoLoadLanguage()
-
{
-
switch(m_lan_flag)
-
{
-
case LAN_CN:
-
//m_translator.load(QString("../LanguageChange/Lan/cn")); // Use
qm file by relative address
-
m_translator.load(QString(":/Lan/cn")); // Use
lan.qrc to load language
-
break;
-
case LAN_EN:
-
m_translator.load(QString(":/Lan/en"));
-
break;
-
case LAN_DE:
-
m_translator.load(QString(":/Lan/de"));
-
break;
-
}
-
qApp->installTranslator(&m_translator);
-
}
-
-
// Method 2: Use ChangeEvent to retranslateUi
-
void languageWidget::changeEvent(QEvent *event)
-
{
-
if(event->type() == QEvent::LanguageChange)
-
ui->retranslateUi(this);
-
else
-
QWidget::changeEvent(event);
- }
子窗口弹出
语言自动切换