16-1_Qt 5.9 C++开发指南_多语言界面

news2024/11/16 4:52:55

文章目录

  • 1. 多语言界面设计概述
  • 2. tr()函数的使用
  • 3. 生成语言翻译文件
  • 4. 使用Qt Linguist 翻译 ts 文件
  • 5. 调用翻译文件改变界面语言
    • 5.1 生成qm文件
    • 5.2 项目启动时设置界面语言
    • 5.3 动态切换语言

1. 多语言界面设计概述

有些软件需要开发多语言界面版本,如中文版和英文版,并且在软件里可以方便地切换界面语言。Qt 为多语言界面提供了很好的支持,使用 Qt 的一些规则和工具,可以很方便地为应用程序开发提供多语言界面支持。
用 Qt 开发多语言界面应用程序,主要包括以下几个步骤。

(1)在程序设计阶段,程序代码中每一个用户可见的字符串都用 tr()函数封装,以便 Qt 提取界面字符串用于生成翻译资源文件。用 UI设计器可视化设计窗体时统一用一种语言,如汉语。

(2)在项目配置文件 (.pro 文件)中设置需要导出的翻译文件 (.ts 文件)名称,使用 lupdate工具扫描项目文件中需要翻译的字符串,并生成翻译文件。

(3)使用Qt的 Linguist 程序打开生成的翻译文件,将程序中的字符串翻译为需要的语言,如将所有中文字符串翻译为英文。

(4)使用lrelease 工具编译翻译好的翻译文件,生成更为紧凑的“.qm”文件。

(5)在应用程序中用QTranslator 调用不同的“qm”文件,实现不同的语言界面

2. tr()函数的使用

为了让 Qt 能自动提取程序中用户可见的字符串,对于每个字符串都需要使用tr()函数封装。tr()是 QObject 的一个静态函数,在使用了Q_OBJECT 宏定义的类或 Object 的子类中,都可以直接使用tr()函数,否则需要使用 QObject::tr()进行调用。或者在类定义中用 Q_DECLARE_TR_FUNCTIONS 宏把tr()函数添加到类中之后,再直接调用 tr()函数。

tr()函数的定义是:

[static] QString QObject::tr(const char *sourceText, const char *disambiguation = nullptr, int n = -1)

其中,sourceText 是源字符串,disambiguation 是为翻译者提供额外信息的字符串,用于对一些容易混淆的地方作说明,内容如下:

LabCellPos = new QLabel(tr("当前单元格:"),this);
QMessageBox::information(thistr("信息")tr("信息提示?),QMessageBox::Yes);
QString str1=tr("左右",“大约的意思");
QString str2=tr("左右""掌握、控制的意思");

使用tr()函数,需要注意以下一些事项。

尽量使用常量字符串,不要使用字符串变量。在tr()函数中应直接传递字符串常量,而不是用变量传递字符串,如下面的代码使用了字符串变量,使用 lupdate 工具提取项目中的字符串时,将不能提取“不能删除记录”这个字符串。

char *errorStr="不能删除记录";
QString str2=tr(errorStr);

使用字符串变量时需要用 Qt_TR_NOOP()宏进行标记。若要在tr()函数中使用字符串变量,需要在定义字符串的地方用 Qt_TR_NOOP()宏进行标记,这在使用字符串数组时比较有用,例如:

const char *cities [4] = {
    Qt_TR_NOOP("Beijing"),
    Qt_TR_NOOP("Qingdao"),
    Qt_TR_NOOP("Wuhan")};
for (int i=0;i<4;i++)
    comboBOx->addItem(tr(cities[i]));

tr()不能使用拼接的动态字符串。tr()不能使用拼接的动态字符串,例如,下面的用法是错误的:

LabCellPos->setText(tr("第"+ QString::number(current,row()) +"行");

正确的方式如下:

LabCellPos->setText(tr("第 %1 行").arg(current.row()));

翻译的字符串是"第 %1 行",然后再用 QString 的 arg()去替换占位符“%1”的内容。

Qt_NO_CAST_FROM_ASCII 的作用。在一个需要翻译为多语言的应用程序中,如果编写程序时忘了对某个字符串使用 tr()函数,lupdate 生成的翻译资源文件就会遗漏这个字符串。为了避免这种疏忽错误,可以在项目配置文件 (.pro 文件) 中添加如下的定义:

DEFINES += Qt_NO_CAST_FROM_ASCII

这样在编译时,会禁止从const char* 到 QString 的隐式转换,强制每个字符串都必须使用 tr()或QLatin1String()封装,避免出现遗漏未翻译的字符串。

3. 生成语言翻译文件

要生成多语言界面相关的翻译文件,除了之前所说的在对每个字符串都使用 tr()函数封装之外,还需要在项目配置文件 (.pro 文件) 中使用 TRANSLATIONS 定义语言翻译文件(.ts 文件),并使用 lupdate 工具生成语言翻译文件。

作为实例,将第 6 章的 samp6_2 作为多语言界面设计实例,复制项目 samp6_2 的全部文件,并将项目名称更改为 samp16_1。在项目的配置文件中增加如下的设置语句:

TRANSLATIONS  =samp16_1_cn.ts\
              samp16_1_en.ts

这里设置生成两个语言翻译文件“samp16_1_cn.ts”和“samp16_1_en.ts”,分别是中文和英文翻译文件。文件名称可以任意设计,只要有所区分即可。

原始的程序设计采用中文。为了便于进行语言切换,在主窗口上设置了两个工具栏按钮,分别用于切换中文和英文界面 (如图 16-1 所示,界面语言切换的代码实现会在下一小节介绍

在这里插入图片描述

为了让 lupdate 工具能提取项目代码内的字符串,这里对项目程序里的字符串全部采用 tr()函数封装,对于不符合 tr()函数使用规则的地方进行修改。例如,之前在状态栏上显示当前单元格的行号和列号的程序是:

LabCellPos->setText(QString::asprintf("当前单元格:%d 行,%d列",current.row(),current.column()));

现在就修改为如下形式:

LabCellPos->setText(QString::asprintf(tr("当前单元格:%d 行,%d列"),current.row(),current.column()));

在项目设计期间,任何时候都可以使用 lupdate 工具生成或更新翻译文件,方法是单击 QCreator 主菜单的“Tools”-“External”-“Qt 语言家”-“Update Translations(lupdate)”菜单项,若项目的源程序目录下没有 samp16_1_cn.ts 和 samp16_1_en.ts 这两个文件,就会自动生成,如果文件已经存在,则会更新这两个文件的内容

4. 使用Qt Linguist 翻译 ts 文件

生成的 samp16_1_cn.ts 和 samp16_1_en.ts 文件内包含了项目源程序和 UI界面里的所有字符串,使用 QtLinguist 可以将这些字符串翻译为需要的语言版本。在 Qt 安装后的程序组里可以找到Qt Linguist 软件。

samp16_1_cn.ts是中文界面的翻译文件,由于源程序的界面就是用中文设计的,所以无需再翻译。samp16_1_en.ts是英文翻译文件,需要将提取的所有中文字符串翻译为英文。

在 Linguist 软件中打开文件 sampl6_1_en.ts,当第一次打开一个ts 文件时,Linguist 会出现如图 16-2 所示的语言设置对话框,用于设置目标语言和所在国家和地区。这个对话框也可以通过Linguist 主菜单的“编辑”->“翻译文件设置”菜单项调出。samp16_1_en.ts 是用英文界面的翻译文件,所以选择语言“English”,国家/地区可选择“UnitedStates"。

在这里插入图片描述

打开samp16_1_en.ts 文件后的Linguist软件界面如下图所示。左侧“上下文”列表里列出了项目中的所有窗口或类,这个项目有 4 个窗口。“字符串”列表里列出了从项目的 UI窗口和代码文件中提取的字符串,右侧“短语和表单”会显示窗口界面的预览或字符串在源程序中出现的代码段。

在“字符串”列表中选择一个源文后,在下方会出现译文编辑框,在此填写字符串对应的英文译文。Linguist 可以同时打开项目的多个 ts 文件,在选中一个源文后,在下方会出现对应的多个语言的译文编辑框,可以同时翻译为多个语言版本。

在这里插入图片描述

5. 调用翻译文件改变界面语言

5.1 生成qm文件

使用 Linguist 软件编辑翻译文件,将所有字符串都翻译后,在 Qt Creator 中单击主菜单项“Tools”-“External”-“Qt 语言家”-“Release Translations(lrelease)”,会在项目源程序目录下生成与ts 文件对应的 qm 文件,这是更为紧凑的翻译文件。本实例生成的是 samp16_1_cn.qm和samp16_1_en.qm。

5.2 项目启动时设置界面语言

使用QTranslator 类设置界面的不同语言版本,需在应用程序启动时设置界面语言翻译文件,即在main()函数中进行处理。项目 samp16_1的main.cpp 的代码如下:

#include "mainwindow.h"
#include    <QApplication>
#include    <QTranslator>

#include    <QSettings>

QTranslator *trans=NULL;

QString readSetting();

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    trans=new QTranslator;
    QString curLang=readSetting(); //读取语言设置
    if (curLang=="EN")
        trans->load("samp16_1_en.qm");
    else
        trans->load("samp16_1_cn.qm");
    app.installTranslator(trans);

    MainWindow w;
    w.show();
    return app.exec();
}

QString readSetting()
{//从注册表读取上次设置的语言
    QString organization="WWB-Qt";//用于注册表,
    QString appName="samp16_1"; //HKEY_CURRENT_USER/WWB-Qt/amp13_1
    QSettings  settings(organization,appName);//创建
    QString Language=settings.value("Language","EN").toString();//读取 saved键的值
    return  Language;
}

这里定义了一个全局变量 trans,在 main.cpp 里定义了一个函数readSetting(),用于从注册表里读取上次设置的界面语言版本。注册表里数据的读取和写入使用到 QSetings 类,在6.5 节有详细介绍。

在main()函数中,创建QTranslator 类的对象trans 后,调用readSetting()函数从注册表里读取上次的语言版本,若为“EN”,就用 load()函数载入编译后的英文翻译文件 samp16_1_en.qm,否则就载入中文翻译文件 samp16_1_cn.qm。然后再执行app.installTranslator(trans),就可以给应用程序安装翻译器,实现需要的界面版本。
samp16_1_en.qm 和samp16_1_cn.qm 文件是被编译到项目的可执行文件中的,无需将这两个文件复制到可执行文件目录下。

在 main()函数里加载翻译器是相比之下一劳永逸的方法,这样一来,随后应用程序的任何窗口都会自动应用开始设置的语言。所以,一些大型的软件在重新设置了语言版本后,通常都会要求重新启动软件才生效。

5.3 动态切换语言

在软件运行时可以动态切换语言,即无需重启软件就可以切换界面语言。在 samp16_1 的主窗口上有“中文”和“English”两个工具栏按钮,用于实现中文和英文界面的切换。下面是这两个按钮的响应代码:

void MainWindow::on_actLang_CN_triggered()
{//中文界面
    qApp->removeTranslator(trans);
    delete trans;

    trans=new QTranslator;
    trans->load("samp16_1_cn.qm");
    qApp->installTranslator(trans);
    ui->retranslateUi(this);

    QSettings   settings("WWB-Qt","samp16_1"); //注册表键组
    settings.setValue("Language","CN"); //界面语言,汉语
}

void MainWindow::on_actLang_EN_triggered()
{//英文界面
    qApp->removeTranslator(trans);
    delete trans;

    trans=new QTranslator;
    trans->load("samp16_1_en.qm");
    qApp->installTranslator(trans);
    ui->retranslateUi(this);

    QSettings   settings("WWB-Qt","samp16_1"); //注册表键组
    settings.setValue("Language","EN"); //界面语言,英语
}

一个应用程序只能加载一个翻译器,因为在 main()函数里已经加载了一个翻译器,所以需要先移除当前的翻译器,才能重新创建新的翻译器,加载翻译文件,并为应用程序重新加载新翻译器。
完成这些后还必须调用 UI的 retranslateUi()函数来刷新界面。

retranslateUi()函数是在窗口的“ui_”头文件中自动生成的,如 mainwindow.ui 主窗口对应的头文件 ui_mainwindow.h 里就有函数 retranslateUi(),这个函数使用 QApplication::translate()函数将所有界面字符串进行翻译,类似于 tr()函数的功能。

窗口在被创建时会自动调用此 retranslateUi()函数,在程序运行中动态切换界面语言时,必须手工调用此retranslateUi()函数,才可以立即更新界面语言。

若不是用 UI Designer 设计的窗口,而是完全由代码实现的窗口界面,需要专门设计一个retranslateUi()函数,将所有界面字符串用 tr()函数进行翻译,并在动态切换语言时调用此函数。很显然,这样做比较麻烦,特别是当软件比较大,窗口非常多时。所以,大型的软件在重新设置语言版本后,一般要求重新启动软件才生效,在程序启动时根据上次的设置加载一次翻译器即可。

按钮响应代码的最后是将设置的语言版本写入注册表,以便下次程序启动时自动加载相应的语言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/838633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HCIP---OSPF的优化

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.汇总&#xff1a; 目的&#xff1a;减少骨干区域的LSA的更新量 作用&#xff1a;OSPF的…

设计模式概述与UML图

文章目录 一、设计模式概述1. 软件设计模式的产生背景2. 软件设计模式的概念3. 学习设计模式的必要性4. 设计模式分类&#xff08;1&#xff09;创建型模式&#xff08;2&#xff09;结构型模式&#xff08;3&#xff09;行为型模式 二、UML图1. 类图概述2. 类图作用3. 类图表示…

freeswitch的mod_xml_curl模块动态获取dialplan

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 mod_xml_curl模块支持从web服务获取xml配置&#xff0c;本文介绍如何动态获取dialplan配置。 环境 centos&#xff1a;CentOS release 7.0 (Final)或以上版本 freeswitch&#xff1a;v1.6.20 GCC&#xff1a;4.8.5…

十四.redis哨兵模式

redis哨兵模式 1.概述2.测试3.哨兵模式优缺点 redis哨兵模式基础是主从复制 1.概述 主从切换的技术方法&#xff1a;当主节点服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费时费力&#xff0c;还会造成一段时间内服…

MySQL进阶--性能分析

目录 一、简介二、什么的SQL性能分析三、性能分析的方式1.SQL执行频率2.慢查询日志3.profile详情4.explain执行计划 PS: 一、简介 本文的内容讲的是MySQL的性能分析&#xff0c;包括执行频率、慢查询日志、profile详情和explain执行计划~ 二、什么的SQL性能分析 SQL性能分析…

【分布式系统】前言

争取写一下阅读笔记&#xff0c;更新有关分布式系统的一切&#xff0c;先开个坑。 现在的心得如下&#xff1a; 不知道啥时候能破解哈&#xff5e;&#xff5e; 内容包括部分6.824 读的论文 DDIA&#xff1a; DDIA mapreduce GFS VMwareFT Raft zookeeper chain replication…

STM32——STM32F401x系列标准库的下载+环境搭建+建工程步骤(更完整)

文章目录 标准库的下载环境搭建建工程最后的话 标准库的下载 1.STM32标准库的官网下载网站https://www.st.com/content/st_com/en.html 2. 3. 4. 5. 6. 7.点击之后下滑 8.选择自己需要的版本下载 环境搭建建工程 大致步骤同之前我写的一篇STM32——建工程差不多&#xff0…

【ChatGPT 指令大全】怎么使用ChatGPT写履历和通过面试

目录 怎么使用ChatGPT写履历 寻求履历的反馈 为履历加上量化数据 把经历修精简 为不同公司客制化撰写履历 怎么使用ChatGPT通过面试 汇整面试题目 给予回馈 提供追问的问题 用 STAR 原则回答面试问题 感谢面试官的 email 总结 在职场竞争激烈的今天&#xff0c;写一…

3d 地球与卫星绕地飞行

1 创建场景 2 创建相机 3 创建地球模型 4 创建卫星中心 5 创建卫星圆环及卫星 6 创建控制器 7 创建渲染器 <template><div class"home3dMap" id"home3dMap"></div> </template><script> import * as THREE from three impo…

git之reflog分析

写在前面 本文一起看下reflog命令。 1&#xff1a;场景描述 在开发的过程中&#xff0c;因为修改错误&#xff0c;想要通过git reset命令恢复到之前的某个版本&#xff0c;但是选择提交ID错误&#xff0c;导致多恢复了一个版本&#xff0c;假定&#xff0c;该版本对应的内容…

【rust/入门】windows安装rust gnu环境(折腾)

说在前面 首先说明&#xff0c;我是rust入门选手&#xff0c;之前都是在wsl写rust&#xff0c;突然想在windows下装下rust。windows版本&#xff1a;windows11 22H2原文换源 心路历程 看到教程我陷入了沉默&#xff0c;(官方推荐) 打开Microsoft C Build Tools我开始不解&…

三 动手学深度学习v2 —— Softmax回归+损失函数+图片分类数据集

三 动手学深度学习v2 —— Softmax回归损失函数图片分类数据集 目录: softmax回归损失函数 1. softmax回归 回归vs分类: 回归估计一个连续值分类预测一个离散类别 从回归到多类分类 回归 单连续数值输出自然区间R跟真实值的误差作为损失 分类 通常多个输出输出i是预测为第…

Jmeter组件作用域及执行顺序

目录 一、Jmeter八大可执行元件 二、组件执行顺序 三、组件作用域 四、特殊说明 一、Jmeter八大可执行元件 配置元件---Config Element 用于初始化默认值和变量&#xff0c;以便后续采样器使用。配置元件大其作用域的初始阶段处理&#xff0c;配置元件仅对其所在的测试树分…

使用ubuntu-base制作根文件系统

1&#xff1a;ubuntu官网下载最小根文件系统&#xff1a; 放置到电脑的ubuntu中&#xff0c; Mkdir Ubuntu_rootfs Cd Ubuntu_rootfs Sudo tar –zxvf Ubuntu-bash-xxxxxx.tar.gz 2&#xff1a;电脑的ubuntu安装qemu搭建arm模拟系统 将/usr/bin/qemu-arm-static/(64位拷贝…

zookeeper --- 基础篇

一、zookeeper简介 1.1、什么是zookeeper zookeeper官网&#xff1a;https://zookeeper.apache.org/ 大数据生态系统里的很多组件的命名都是某种动物或者昆虫&#xff0c;他是用来管 Hadoop&#xff08;大象&#xff09;、Hive(蜜蜂)、Pig(小 猪)的管理员。顾名思义就是管理…

openpnp - 8mm物料编带的厚度

文章目录 openpnp - 8mm物料编带的厚度概述笔记END openpnp - 8mm物料编带的厚度 概述 做了一个散料飞达, 回来后试了一下. 并不是所有8mm编带都能顺利插入散料飞达. 原来, 不同物料的8mm编带厚度是不一样的. 那就量一下. 笔记 参考电阻的厂家说明书(e.g. C2907561_贴片电阻…

车载总线系列——J1939三

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 没有人关注你。也无需有人关注你。你必须承认自己的价值&#xff0c;你不能站在他人的角度来反对自己。人…

【Java】如何判断线程池任务执行完?

文章目录 前言1.需求分析2.实现概述3.具体实现3.1 统计完成任务数3.2 FutureTask3.3 CountDownLatch和CyclicBarrier 小结 前言 论是在项目开发中&#xff0c;还是在面试中过程中&#xff0c;总会被问到或使用到并发编程来完成项目中的某个功能。 例如某个复杂的查询&#xf…

etcd

文章目录 etcd单机安装设置键值对watch操作读取键过往版本的值压缩修订版本lease租约&#xff08;过期机制&#xff09;授予租约撤销租约keepAlive续约获取租约信息 事务基于etcd实现分布式锁原生实现官方 concurrency 包实现 服务注册与发现Go 操作 Etcd 参考 etcd etcd 是一…

【Java】批量生成条码

批量生成PDF条码 效果图&#xff1a; //调用下方接口注意编码格式if(CollectionUtil.isNotEmpty(productExList)){String exportFileName URLEncoder.encode("商品条码", "UTF-8") DateUtil.format(new Date(), "yyyyMMddHHmmss");response.…