本文讲述在QT中动态切换多语言.
我会动态生成一个菜单,这个菜单会列出所有的语言,用户可以单选一种语言,选择语言后,界面就会切换到指定的语言
1.兜底的语言
当一个语言(字符串)没有被翻译时,他会用你代码中的语言(字符串)来显示, 这个语言(字符串)就是兜底的语言.
也就是说,如果你编码的菜单,字符串等用的是中文,我们就认为兜底的语言是中文
如果你编码的菜单,字符串用的是英文,那我们就认为兜底的是英文.
强烈建议,您用英文进行编码(兜底的语言是英文),我测试的情况是,如果用中文,生成的ts文件乱码!没测试QT5,不知道QT5是否会有同样的问题,乱码图片如下:
2.编码中的需要使用多语言的地方请用tr("")包围
比如: xxxCtrl->setText(tr("您好"));
用tr("")包围是告诉QT,这个字符串要当多语言来处理
3.菜单等QT设计器上输入的文本,已经被tr("")包围了,不用管
现在我们就来一步一步地实现多语言吧
a).编辑.pro文件,增加多个ts,在我们的实例中,我们要实现两个语言,一个是zh_CN,一个是en_US,如下:
TRANSLATIONS += res/language/zh_CN.ts \
res/language/en_US.ts
注意:这里的res/language/是表示要生成ts的目录,你也可以不写res/language/那生成的ts文件就和pro在同一个目录下.
如果你写了res/language/或者其他什么目录,你就需要手动创建这两个文件夹,res和.pro文件同一目录,language在res目录下
编辑好的样子如图:
b). 先用界面设计器设计两个菜单,一个是File,一个是Help,
然后拖两个控件上去,一个是lable,一个是LineEdit
lable用于静态显示一个文本,设置内容为"Static Text"
LineEdit用于编码显示文本,在代码中设置内容为"Dynamic Text 100"
差不多就是下面这个样子
void MainWindow::UpdateDynamicControls()
{
QString strText = QString(tr("Dynamic Text %1")).arg(m_nValue);
ui->lineEditDynamic->setText(strText);
}
c). 还记得我们的a)步骤吗,现在我们就要生成这两个ts文件了,方法如下:
工具->外部->QT语言专家->更新翻译
执行完后,就会生成en_US.ts和zh_CN.ts两个文件了,不妨可以打开看看,是个xml文件,记录了所有要翻译的文本和他们所在的位置.
此时两个文件是一模一样的,为啥呢? 因为虽然QT支持多语言,但翻译还是得我们自己来....
d). 翻译
找到Linguist,通常在QT的安装目录下的bin文件中,我是直接在开始中搜索到的(位于C:\Qt\4.8.6\bin\linguist.exe)
执行,后打开zh_CN.ts,开始翻译成英文的工作.
在弹出的对话框中,目标语言已经设置好了,就是Chinese
确定后就一个一个地翻译,如果某个你不想翻译,那也没有关系,就显示"兜底"显示的内容
翻译完了后,保存一下.退出.
d). 发布翻译,生成qm文件
工具->外部->QT语言专家->发布翻译
执行后,会生成两个文件,一个是zh_CN.qm一个是en_US.qm
生成的qm文件才是最终使用的文件.
e). 程序启动的时候,加载qm文件.
把zh_CN.qm和en_US.qm加到资源文件中去(您也可以不加入到资源文件,只要exe最终能找到qm文件就可以了)
加载后如图所示
程序启动的时候,需要加载.qm文件,加载的代码如下
void MyMultiLanguage::Switch(QString strNewLang)
{
if (0 != m_strCurLanguage.compare(strNewLang))
{
QString strQM = QString(":/res/language/%1.qm").arg(strNewLang);
if (QFile(strQM).exists())
{
QTranslator* translator = new QTranslator;
if (translator->load(strQM))
{
m_strCurLanguage = strNewLang;
if (NULL != m_translator)
{
qApp->removeTranslator(m_translator);
delete m_translator;
}
m_translator = translator;
qApp->installTranslator(m_translator);
}
else
{
delete translator;
translator = NULL;
}
}
}
}
这段代码并不复杂,代码几乎不言自明
比如传入的参数是zh_CN
那么就先判断":/res/language/zh_CN.qm"是否存在
如果文件存在,则new 一个QTranslator(QTranslator就什么呢?你这么理解好了,一个QTranslator就是一个qm)
如果QTranslator load成功,则把原来的QTranslator删除(removeTranslator,如果有的话),加载最新的QTranslator
最后,安装多语言依赖QApplication
qApp->installTranslator(m_translator);
加载翻译这段代码(g_MultiLanguage.Init("zh_CN");)在函数入口处(QApplication后)执行
int main(int argc, char *argv[])
{
QTextCodec *codec = QTextCodec::codecForName("UTF-8"); //获取系统编码
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
QApplication a(argc, argv);
//初始化多语言, 切换多语言依赖于QApplication
g_MultiLanguage.Init("zh_CN");
MainWindow w;
w.show();
int nRet = a.exec();
//反初始化
g_MultiLanguage.UnInit();
return nRet;
}
运行,因为我们默认加载的是zh_CN.qm,所以运行界面显示为中文了,如下:
f). 加入顶层菜单language,供用户切换语言,代码如下:
//在帮助之前,动态插入菜单language
QMenu *languageMenu = new QMenu(tr("language"), menuBar());
menuBar()->insertMenu(ui->menuHelp->menuAction(), languageMenu);
//action_zh_CN = new QAction(QIcon(":/res/language/zh_CN.png"), "简体中文", this);
//action_en_US = new QAction(QIcon(":/res/language/en_US.png"), "英文", this);
//菜单项"简体中文",注意没有用tr包围
QAction* action_zh_CN = new QAction("简体中文", this);
action_zh_CN->setData("zh_CN");
action_zh_CN->setCheckable(true);
//菜单项"English",注意没有用tr包围
QAction* action_en_US = new QAction("English", this);
action_en_US->setData("en_US");
action_en_US->setCheckable(true);
//根据当前的语言设置选中菜单
if (0 == g_MultiLanguage.GetCurLanguage().compare("zh_CN"))
{
action_zh_CN->setChecked(true);
}
else if (0 == g_MultiLanguage.GetCurLanguage().compare("en_US"))
{
action_en_US->setChecked(true);
}
//将简体中文和英文加入到language菜单中去,并设置好处理函数OnLanguageChanged
QActionGroup* languageGroup = new QActionGroup(this);
languageMenu->addAction(languageGroup->addAction(action_zh_CN));
languageMenu->addAction(languageGroup->addAction(action_en_US));
connect(languageGroup, SIGNAL(triggered(QAction *)), this, SLOT(OnLanguageChanged(QAction *)));
执行结果如下:
注意一下,我并没有把两个菜单项目"简体中文"和"English"用tr包围,因为这两个是不需要翻译的,他本身就代表用户要选择的语言.
处理语言切换的slot代码如下:
void MainWindow::OnLanguageChanged(QAction* action)
{
if (NULL != action) {
// load the language dependant on the action content
//loadLanguage(action->data().toString());
//setWindowIcon(action->icon());
qDebug() << action->data().toString() << "\n";
g_MultiLanguage.Switch(action->data().toString());
}
}
g). 到此,我们离成功非常接近了.
我们切换语言时,会调用 qApp->installTranslator(m_translator); 这个函数会导致QEvent :: LanguageChange被发射出来
我们可以在这个事件的处理函数中,重新更新UI,完成多语言切换.
我们需要继承实现virtual void changeEvent(QEvent * event);
void MainWindow::changeEvent(QEvent * event)
{
if (NULL != event) {
switch (event->type()) {
// this event is send if a translator is loaded
case QEvent::LanguageChange:
qDebug() << "case QEvent::LanguageChange" << endl;
ui->retranslateUi(this);
UpdateDynamicControls();
break;
default:
break;
}
}
QMainWindow::changeEvent(event);
}
最后这一步也是关键的一步,执行了两个函数:
ui->retranslateUi(this);这个函数是系统控件重新更新UI(语言)
UpdateDynamicControls();是我自己写的函数,也是动态去更新LineEdit的内容(语言),代码如下:
void MainWindow::UpdateDynamicControls()
{
QString strText = QString(tr("Dynamic Text %1")).arg(m_nValue);
ui->lineEditDynamic->setText(strText);
}
到此,切换语言工作完成!用户就可以在菜单里面选择自己想要的语言啦!
切换语言的调试输出:
"en_US"
case QEvent :: LanguageChange
说明每切换一次语言,就会收到QEvent :: LanguageChange一次
代码见: http://q1024.com/files/qt_window-master.zip 000400目录
参考:https://wiki.qt.io/How_to_create_a_multi_language_application
[思考]
顶层菜单language没有翻译,不能切换语言,你知道怎么操作完成这个项目的翻译和语言切换吗?