【大话QT之十四】QT实现多语言切换

功能需求:

网盘客户端要能够实现多国语言的切换,第一版要支持中、英文的切换。在实现过程中感觉QT对多国语言的支持还是很不错的,制作多语言包很方便,切换的逻辑也很简单。下面就来看一下QT中如何制作多语言包。

实现方法:

为了支持国际化最关键的地方是制作多国语言包,然后再实现动态切换。QT里面既可以采用命令行也可以采用Qt Creator的界面操作来生成,这里我们利用Qt Creator来生成多国语言包。基本流程是,先生成ts文件,然后生成qm文件,最后通过QTranslator类来加载qm文件,实现多语言包的切换。注意:为了更全面地实现多语言包,在程序中所有涉及到界面中的按钮或者菜单中的文字显示,都必须使用 QObject::tr("...") 的方式将显示的内容包裹起来,这样做的原因是:只有添加了QObject::tr()的标记,生成ts文件的时候程序才会认为被QObject::tr()包裹的地方是需要制作多语言的,从而在ts中预留出位置。

1> 生成ts文件

在QT的项目文件(.pro)中添加:TRANSLATIONS = XXX.ts YYY.ts(如果是多行,则用 \ 分割)

然后执行【工具】-》【外部】-》【QT语言家】-》【更新翻译(lupdate)】,如下图所示,执行完之后项目下就会生成对应的XXX.ts、YYY.ts文件。

注意:如果项目中包含ui文件,如:FORMS += ZZZ.ui,则在生成的ts文件中包含所有ui文件上的字符显示,而且,在制作ui文件时默认情况下界面上的文字显示都是通过QObejct::tr(" ")包裹的,因为在默认情况下ui中的所有控件都存在一个属性:可翻译的,就代表了默认用QObject::tr()嵌套了。

2. 生成qm文件

利用QT语言家:Linguist打开生成的ts文件,将里面需要翻译的地方写上对应的语言,如下图所示:

ts文件翻译完成后,执行Qt Creator中的【工具】-》【外部】-》【QT语言家】-》【部署翻译(lrelease)】就会生成最终要用到的qm文件,如下图所示:

3. 加载qm语言包

到这里qm语言包制作完成,工作就完成了一大半了。接下来的任务就是在代码中实现语言包的加载,即:根据不同的选择加载不同的语言包。

void LHSyncClientPrivate::InitUiByLanguage(const QString strLanguage)
{
    if (strLanguage.isEmpty())
    {
        return;
    }

    QString strLanguageFile;
    if (strLanguage.compare("en") == 0)
    {
        strLanguageFile = qApp->applicationDirPath() + QString("/languages/%1/%2").arg(LHT_SYNCCLIENT_VERSION_PRODOCUTNAME).arg(LHT_SYNCCLIENT_EN_FILE);
    }
    else if (strLanguage.compare("zh") == 0)
    {
        strLanguageFile = qApp->applicationDirPath() + QString("/languages/%1/%2").arg(LHT_SYNCCLIENT_VERSION_PRODOCUTNAME).arg(LHT_SYNCCLIENT_ZH_FILE);
    }

    if (QFile(strLanguageFile).exists())
    {
        m_translator->load(strLanguageFile);
        qApp->installTranslator(m_translator);
    }
    else
    {
        qDebug() << "[houqd] authclient language file does not exists ...";
    }
}

其中,m_translator即为QTranslator实例,在类的构造函数中赋值:m_translator = new QTranslator;实现过程很简单,就是取得语言包的绝对路径,然后利用QTranslator来加载它,最后利用qApp->installTranslator(m_translator)来安装。

4. 重新设置界面显示

重新设置界面的显示,这一步是很多人容易忘记的一步,如果这儿被忽略了,往往就无法完成语言的切换,即:重新设置一下需要显示的元素,该过程是在上面InitUiByLanguage过程之后进行的,相关代码如下:

void LHSyncClientPrivate::RetranslateUi()
{
    m_wgtSync->setWindowTitle(tr("Drive Client"));

    //! 左侧同步信息
    m_btnSynchronizing->setText(tr("Synchronizing"));
    m_btnSynchronized->setText(tr("Synchronized"));

    //! 右侧面板
    m_lblSyncStatus->setText(tr("looking for files changes..."));
    m_lblShowRecordsNum->setText(tr("There are n records ..."));
    m_btnSyncOrPause->setText(tr("Sync Or Pause"));
    m_btnClearAll->setText(tr("Clear all"));
    m_btnSyncOrPause->setText(tr("Sync Or Pause"));

    m_btnClose->setText(tr("Close"));
    m_actSync->setText(tr("Sync Info"));
}

实现效果:

好了,到这里整个语言包的制作过程就基本完成了。这里还需要提及一点在网盘客户端实现时的设计思路:由于网盘在登录前和登录后可操作的菜单是不一样的,要涉及一种动态加载的方式,可以实现一个UiLoader的插件,它实现所有的窗体加载(即LoadUi()返回QWidget句柄)、菜单加载、语言切换,在这些功能中可能UiLoader插件并不完成具体的工作,而仅仅是实现信号的转发功能。同样,也需要实现一个逻辑控制插件,它负责所有的菜单逻辑,而对于每个窗体则由各自的窗体插件自行完成。多语言切换的实现效果如下:

切换为中文:

切换后效果:

加油,坚持每天的学习!!

时间: 2024-11-08 21:04:25

【大话QT之十四】QT实现多语言切换的相关文章

Go语言开发(十四)、Go语言常用标准库四

Go语言开发(十四).Go语言常用标准库四 一.heap 1.heap简介 heap仅仅提供了最小堆的操作,没有提供堆的数据结构,堆的数据结构必须由开发者自己实现.heap提供了一个heap.Interface接口来作为堆的操作和堆的数据结构(开发者自己实现)之间的桥梁,堆的数据结构必须满足此接口: type Interface interface { sort.Interface Push(x interface{}) // add x as element Len() Pop() inter

大话设计模式第十四章--观察者模式

<?php abstract class Subject { private $_observers = array(); public function attach(Observer $observer) { $this->_observers[] = $observer; } public function detach(Observer $observer) { if (isset($this->_observers[$observer])) { unset($this->

一起talk C栗子吧(第一百三十四回:C语言实例--创建线程时的内存细节)

各位看官们,大家好,上一回中咱们说的是"创建进程时的内存细节"的例子,这一回咱们说的例子是:创建线程时的内存细节.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在前面章回中介绍过创建线程的例子,创建线程时使用的函数是pthread_create.今天我们一起说一下使用该函数创建线程时内存的一些细节问题.我们介绍的的重点还是内存布局中的四个分区.这点和前一回中介绍创建进程时内存细节的思路相同. 1.在主线程中使用pthread_create函数可以创建一个新线程,我们叫

一起talk C栗子吧(第一百五十四回:C语言实例--socket通信地址系统调用二)

各位看官们,大家好,上一回中咱们说的是socket通信地址系统调用的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回介绍的通信地址系统调用有效地解决了数据存储方式的问题,不过,还有一个系统调用也可以解决这种问题,这一回我们将介绍该系统调用:getaddrinfo. 函数原型 该系统调用从其名字上看是用来获取地址的信息,这里的地址主要指套接字通信地址.它获取到的地址信息不需要进行字节序转换,我们可以直接用来进行套接字通信.不过,我们不能只看名字

一起talk C栗子吧(第一百二十四回:C语言实例--内置宏)

各位看官们,大家好,上一回中咱们说的是显示变量和函数地址的样例,这一回咱们说的样例是:内置宏.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在编译程序的时候,假设有语法错误,编译器就会提示,在某个文件的某一行有错误,这是怎么做到的呢?事实上是使用了C语言的内置宏. 说到宏,我想大家都知道,而所谓的内置宏相似于C语言的关键字,它是C语言自定义的,因此我们不须要定义宏,就能够直接使用.经常使用的内置宏有"_LINE_"和"_FILE_".假设把它们放到

一起talk C栗子吧(第七十四回:C语言实例--DIY cd命令)

各位看官们,大家好,上一回中咱们说的是DIY pwd命令的例子,这一回咱们说的例子是:DIY cd命令.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,在Linux系统中,终端提供的cd命令是我们最常用的命令之一,相信大家对它一定很熟悉了.今天,让我们一起来DIY cd命令吧.下面是具体的操作步骤: 1.从用户输入的内容中提取路径名称: 2.把刚才获取的路径名称传递给chdir函数,使用该函数切换到名称所在的目录中: 3.确认函数运行的结果,如果不能切换,给用户一个提示. 下面是我们

一起talk C栗子吧(第三十四回:C语言实例--巧用溢出计算最值)

各位看官们,大家好,上一回中咱们说的是巧用移位的例子,这一回咱们说的例子是:巧用溢出计算最值. 闲话休提,言归正转.让我们一起talk C栗子吧! 大家都知道,程序中的变量都有一个取值范围,这个范围也计算机和编译器都有关系.我们举个实际的例 子进行说明:在32位的计算机上,如果使用4个字节存储int类型的变量也就是说使用了32位的存储空间. 这时int类型变量的取值范围是:负2的32次方到正2的32次方-1,具体的数值是-2147483648到2147483647. 如果把不在这个范围内的数值赋

一起talk C栗子吧(第一百七十四回:C语言实例--关闭终端中的缓冲功能二)

各位看官们,大家好,上一回中咱们说的是关闭终端中缓冲功能的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们, 我们在上一回中介绍了如何关闭终端中的缓冲功能,当时是借助系统命令stty实现该功能的,这一回中我们将介绍另外一种关闭终端中回显功能的方法.该方法是通过终端的termios编程接口来操作终端的.关于termios接口的介绍和编程接口,我们在一百七十一回中介绍过了,因此,我们直接介绍如何通过termios编程接口来关闭终端缓冲功能. 下面是详细的操作步

一起talk C栗子吧(第八十四回:C语言实例--使用信号进行进程间通信一)

各位看官们,大家好,上一回中咱们说的是进程间通信的例子,这一回咱们说的例子是:使用信号进行进程间通信.闲话休提,言归正转.让我们一起talk C栗子吧! 我们在上一回中提到过进程之间通信需要解决的三个问题,时间不长,我想大家都记得.今天我们就来解决第一个问题:进程之间如何进行通信. 信号的概念 在解决问题前,我们先介绍一下信号.信号是Unix/Linux系统提供的一种机制,它本质上一种软件中断.信号为我们提供了一种异步的事件处理方法,当进程收到信号时就会采取某种操作.例如,当进程收到终止信号(S