与QString("我是中文")完全一样,你必须告诉tr这个窄字符串是何种编码?你不告诉它,它就用latin1。于是所谓的乱码问题就出来了。
在论坛中漂,经常遇到有人遇到tr相关的问题。用tr的有两类人:
- (1)因为发现中文老出问题,然后搜索,发现很多人用tr,于是他也开始用tr
- (2)另一类人,确实是出于国际化的需要,将需要在界面上显示的文件都用tr包起来,这有分两种:
- (2a) 用tr包住英文(最最推荐的用法,源码英文,然后提供英文到其他语言的翻译包)
- (2b) 用tr包住中文(源码用中文,然后提供中文到其他语言的翻译包)
注意哦,如果你正在用tr包裹中文字符,却不属于(2b),那么,这是个信号:
- 你在误用tr
- 你需要的是QString,而不是tr
如果你确实属于(2b),请做好心理准备,你可能还会遇到很多困难,请考虑Qt国际化(源码含中文时)的点滴分析
tr 是做什么的?下面二者的区别是什么?
QString text1 = QObject::tr("hello"); QString text2 = QString("hello");
tr是用来实现国际化,如果你为这个程序提供了中文翻译包(其中hello被翻译成中文"你好"),那么text1的内容将是中文"你好";如果你为程序提供且使用日文翻译包,那么text1的内容将是日文。
tr是经过多级函数调用才实现了翻译操作,是有代价的,所以不该用的时候最好不要用。
关注的对象
本文关注的是tr或translate中包含中文字符串的情况:
QObject::tr()
QCoreApplication::translate()
QTextCodec::setCodecForTr
这个问题本多少可说的。因为涉及到的编码问题和QString 与中文问题中是完全一样的,只不过一个是用的setCodecForCStrings一个用的是setCodecForTr。
简单回顾QString的中文问题
- QString 采用的unicode,在中文支持上不存在任何问题
"我是中文" 这是传统的 const char * 的窄字符串
- 当将窄字符串赋值到QString时,我们需要告诉它我们的窄串采用的何种编码(gbk?、utf-8?)
- 究竟何种编码主要取决于我们的源代码文件的编码(windows上一般是gbk,其他平台一般utf-8)
例子:
QString s1 = "我是中文"; QString s2("我是中文"); QString s3; s3 = "我是中文"
s1、s2 用的是QString的构造函数QString ( const char * str )
s3 用的是QString的赋值操作符 QString & operator= ( const char * str)
如果不指定编码,s1,s2,s3将全部都是(国内大多数人所称的)乱码。因为QString将这些const char *按照latin1来解释的,而不是用户期待的gbk或utf8。
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"))
这两条语句中的一条可以解决问题,至于如何选择,此处不再重复。
QObject::tr
说实话,在tr中使用中文不是个好主意。不过既然总有人用(无论是(1)还是(2b)),而且总有人遇到问题,所以还是简单整理一下吧。
相比QCoreApplication::translate,大家用tr应该用的很多了,尽管不少人不清楚tr究竟是做什么的^_^
tr("我是中文");
这调用的是下面这个函数(至少我们可这么认为是)。
QString QObject::tr ( const char * sourceText, const char * disambiguation = 0, int n = -1 )
与QString("我是中文")完全一样,你必须告诉tr这个窄字符串是何种编码?你不告诉它,它就用latin1。于是所谓的乱码问题就出来了。
如何告诉tr你写的这几个汉字在磁盘中保存的是何种编码呢?这正是
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"))
所做的。这两个选择的原则,由于和前文完全一样,此处也不再重复。
如果你的编码采用的utf8,可以直接使用trUtf8而不必设置setCodecForTr。
如果你只关心乱码问题,到此为止就可以了(下面不再关注编码)。如果想对tr进一步了解,不妨。。继续。。
QCoreApplication::translate
我们知道tr是用于实现程序的国际化(或者说多语言翻译),看Qt相关资料的话,我们知道实现该功能的还有下面这个函数:
QString QCoreApplication::translate ( const char * context, const char * sourceText, const char * disambiguation, Encoding encoding, int n )
其实,这个才是真正进行翻译操作的函数,前面我们提到的tr最终是通过调用该函数来实现翻译功能的(稍后我们会看tr是如何调用translate的)。
对tr和这个函数,manual中都有比较详尽的解释。我们这儿简单看一下它的这几个参数:
- context 上下文,一般就是需要翻译的字符串所在的类的名字
- sourceText 需要翻译的字符串。(我们关注的编码其实就是它的编码)
- disambiguation 消除歧义用的。(比如我们的类内出现两处"close",一处含义是关闭,另一处含义是亲密的。显然需要让翻译人员知道这点区别)
- encoding 指定编码。它有两个值
CodecForTr 使用setCodecForTr()设置的编码来解释 sourceText
- UnicodeUTF8 使用utf8编码来解释 sourceText
- 其实这两个分别对应tr和trUtf8
- n 处理单复数(对中文来说,不存在这个问题)
tr与translate
这两个函数的说明,一个在QObject的manual,另一个在QCoreApplication的manual中。
介绍一下tr与translate的关系。前面提到了,tr调用的是translate。如果仅仅这样一说,没有证据,还真难以让大家相信。好吧,继续
tr 在何处定义
你可能说:这不废话吗,manual中写得明白的,它是QObject的静态成员函数。而且还有源码为证:
//来自 src/corelib/kernel/qobject.h #ifdef qdoc static QString tr(const char *sourceText,const char *comment = 0, int n = -1); static QString trUtf8(const char *sourceText, constchar *comment = 0, int n = -1); #endif
嘿嘿,差点就被骗了,发现没:它们被预处理语句包住了。
这说明了什么呢?说明了这段代码仅仅是用来生成Qt那漂亮的文档的(qdoc3从代码中抽取信息,生成一系列的html格式的manual)。
啊,也就是说,这是假的。那么真正的定义呢??在一个大家都很熟悉的地方,猜猜看?
这就是
Q_OBJECT
该宏的定义在src/corelib/kernel/qobjectdefs.h中
#define Q_OBJECT \ public: \ Q_OBJECT_CHECK \ static const QMetaObject staticMetaObject; \ Q_OBJECT_GETSTATICMETAOBJECT \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *); \ QT_TR_FUNCTIONS \virtual int qt_metacall(QMetaObject::Call, int, void **); \ private:
其中的宏QT_TR_FUNCTIONS
# define QT_TR_FUNCTIONS \ static inline QString tr(const char *s, const char *c = 0) \ { return staticMetaObject.tr(s, c); } \ static inline QString trUtf8(const char *s, const char *c = 0) \ { return staticMetaObject.trUtf8(s, c); } \ static inline QString tr(const char *s, const char *c, int n) \ { return staticMetaObject.tr(s, c, n); } \static inline QString trUtf8(const char *s, const char *c, int n) \ { return staticMetaObject.trUtf8(s, c, n); }
现在看到:tr调用的是 staticMetaObject对象的tr函数,staticMetaObject 的定义在moc生成的 xxx.moc 或 moc_xxx.cpp 文件内(你随时可以验证的)。
staticMetaObject 是一个 QMetaObject 类的实例,我们继续看一下该类的源码:
QString QMetaObject::tr(const char *s, const char *c) const {returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr); } QString QMetaObject::trUtf8(const char *s, const char *c) const {returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8);
}
http://blog.sina.com.cn/s/blog_a401a1ea0101bws1.html
与QString("我是中文")完全一样,你必须告诉tr这个窄字符串是何种编码?你不告诉它,它就用latin1。于是所谓的乱码问题就出来了。的更多相关文章
- QString 与中文问题
原文请看:http://www.cnblogs.com/phoenixlaozhu/articles/2553180.html (更新:本文的姊妹篇Qt5与中文问题) 首先呢,声明一下,QString ...
- php 查找字符串里面中文字符第一次出现的位置,并插入字符串
//查找字符串里面中文字符第一次出现的位置,并插入字符串 function find_first_chinese_insert($str,$insert_str){ $count = mb_strle ...
- 中文字符串和UTF-8编码字符串相互转换
中文字符串和UTF-8编码字符串相互转换 //UTF字符转换 var UTFTranslate = { Change: function(pValue) { ) { ).replace(/(%u)(\ ...
- java对含有中文的字符串进行Unicode编码
public class MyUtil { public static void main(String[] args) throws Exception { String s = "a中a ...
- QString与中文,QString与std::wstring的相互转换(使用fromStdWString和u8关键字)
Qt版本:5.5.1 Qt的QString功能丰富,对非英语语言的支持也不是问题,但支持得不够直接.例如,像 ? 1 QString str("死亡使者赛维"); 这样直接用带中文 ...
- 3、树莓派的配置:改静态IP、连接ssh、安装中文字体、安装谷歌输入法、增加USB电流、修改触摸屏分辨率、扩展sd卡空间、修复vi和vim乱码问题、安装配置远程桌面vnc
本博文仅作本人操作过程的记录,留作备忘.自强不息 QQ1222698 1.连接上HDMI线,插上触摸屏,插上键盘,鼠标,网线,启动.系统正常启动,但是一直闪烁,不停的黑屏,是由于触摸屏的usb口供电不 ...
- 判断QString是否为纯数字,查找自身最长重复子字符串
1.判断QString是否为纯数字 bool IsDigitString(QString strSource) { bool bDigit = false; if (strSource.isEmpty ...
- Qt中translate、tr关系 与中文问题
原文请看:http://hi.baidu.com/dbzhang800/item/d850488767bdc3cdee083d43 题外话:何时使用 tr ? 在论坛中漂,经常遇到有人遇到tr相关的问 ...
- 关于qt中的tr()函数
关于qt中的tr()函数 在论坛中漂,经常遇到有人遇到tr相关的问题.用tr的有两类人: (1)因为发现中文老出问题,然后搜索,发现很多人用tr,于是他也开始用tr (2)另一类人,确实是出于国际化的 ...
随机推荐
- Linux下搭建Oracle11g RAC(1)----IP分配与配置IP
首先需要说明的,我的RAC搭建不是在虚拟机上完成的,而是在实际部署中,二者之间有些许差异,本人水平有限,请见谅. 其中,每台机器至少需要配置3个IP地址,在安装操作系统的过程中,我们需要配置公网IP和 ...
- android 5.0 创建多用户 双开多开应用(1)
Andriod5.0多用户 双开应用 android多用户是5.0之后有的,类似windows的账户系统 不过官方还没有完全确认,API大都是hide状态 我这里提供一种方式并不适用所有的,由于我们有 ...
- Windows7服务无法启动的解决
这周六,我接到了一个很诡异的案例,表现为任务栏右下角网络连接图标始终为一个红叉,已排除网卡硬件.链路和网卡驱动的问题.主板都新换了一块,可是问题依旧,这无疑将问题的根源指向了操作系统.本想通过网络疑难 ...
- Linux安装QQ 2017
网上有很多wineQQ,是基于2012或者2013做的,然而当安装好后登录他会提示版本过来,我在优麒麟的应用商店里找到了一个基于国际版QQ的Wine版本,这里说下安装过程. 先上两张成果图: 下载地址 ...
- php 半角与全角相关的正则
半角的全部确认,带小初音的确认法则 ^[ア-ン゙゚ァ-ョッヲー -]+$ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset// ...
- Android学习之旅:五子棋
在学完了Android的基础之后,我开始尝试着写一些小项目练练手,同时进一步巩固自己的基础知识,而我选的的第一个项目就是做一个简单的人人对战的五子棋小游戏. 首先,我们要新建一个自定义控件类Panel ...
- UDP—Socket,套接字聊天简单的聊天程序。
思路:(发送端) 1.既然需要聊天.就应该怎么建立聊天程序,,DatagramSocket对象http://www.w3cschool.cc/manual/jdk1.6/ DatagramSocket ...
- iOS开发进阶--1.多线程简介
学习是由已知的知识模型推理未知的知识模型的的过程. 本文适合学习完objective-c基础,想进一步提高做iOS开发的同学阅读. 在说线程的时候,我们先看看进程. 1.进程 每一个运行在系统中的应用 ...
- jQuery 遍历祖先
祖先是父.祖父或曾祖父等等. 通过 jQuery,您能够向上遍历 DOM 树,以查找元素的祖先. 向上遍历 DOM 树 这些 jQuery 方法很有用,它们用于向上遍历 DOM 树: parent() ...
- ios专题 -归档保存数据
关键类:NSKeyedArchiver 与 NSKeyedUnarchiver 采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCo ...