原文请看:http://hi.baidu.com/dbzhang800/item/d850488767bdc3cdee083d43

题外话:何时使用 tr ?

在论坛中漂,经常遇到有人遇到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::setCodecForTr(QTextCodec::codecForName("GB2312"));
QTextCodec::setCodecForTr(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, const char *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 类的实例,我们继续看一下该类的源码:

/*!
 \internal
*/
 QString QMetaObject::tr(const char *s, const char *c) const
 {
 return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr);
 }
 /*!
 \internal
*/
QString QMetaObject::trUtf8(const char *s, const char *c) const
{
return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8);
}

至此,我们应该都看清楚了。我们的 Q_OBJECT 宏展开后为生成 tr ,tr调用QCoreApplication的translate函数。而该函数需要指定编码。

Qt中translate、tr关系 与中文问题的更多相关文章

  1. 关于qt中的tr()函数

    关于qt中的tr()函数 在论坛中漂,经常遇到有人遇到tr相关的问题.用tr的有两类人: (1)因为发现中文老出问题,然后搜索,发现很多人用tr,于是他也开始用tr (2)另一类人,确实是出于国际化的 ...

  2. Qt中绘图坐标QPainter,Viewport与Window的关系

    在Qt中常常要自己重载一些paintEvent函数,这个时候往往忽略了两个很关键的API,那就是setViewport和setWindow. Viewport,顾名思义,反应的是物理坐标,就是你实际想 ...

  3. Qt 中一些常用类中文说明

    Qt 中一些常用类中文说明是本文讲述的内容,这篇文章主要是介绍Qt 当中经常使用的类,采取的是使用字母索引的方式,下面的类是被经常使用的. QDataStream 为QIODevice提供了一串的二进 ...

  4. Qt中中文字符 一劳永逸的解决方法

    QT中中文字符问题,有没有一劳永逸的解决方法? 目前遇到有以下问题 1.字符串中有中文时,编译提示"常量中含有换行符" 2.在控制台窗口输出中文时无法正常显示,中文全部显示为? 目 ...

  5. qt中qlineedit和qtextedit右键菜单翻译成中文

    没有linguist和lupdate等命令需要安装Linguist: 在Terminal中输入: sudo apt-get install qt4-dev-tools qt4-doc qt4-qtco ...

  6. QT中QString与string的转化,解决中文乱码问题

    在QT中,使用QString输出到控件进行显示时,经常会出现中文乱码,网上查了一圈,发现大部分都是针对QT4增加4条语句:</span> [cpp] view plain copy QTe ...

  7. Qt编写可换肤的中文双拼汉字输入法

    时间过得真快,不知不觉已到2015年,农历春节一眨眼就过去了,端正状态收拾心情整装待发出发. 曾经有段时间,我有一个很执着的梦想,我要导演出一部空前绝后的巨幕.不过现实无情地碾碎我的梦想,也同时将我推 ...

  8. 【转载】Qt中图像的显示与基本操作

    Qt可显示基本的图像类型,利用QImage.QPxmap类可以实现图像的显示,并且利用类中的方法可以实现图像的基本操作(缩放.旋转). 参考:Qt中图像的显示与基本操作 - ykm0722的专栏 - ...

  9. Qt中内存泄露和退出崩溃的问题 delete

    Qt中帮程序员做了一些内存回收的事情,但正因为这些反而让对此不熟悉的人会屡屡犯错. 收录一篇不错的文章: 在C++中学习过程中,我们都知道: delete 和 new 必须 配对使用(一 一对应):d ...

随机推荐

  1. js-之闭包的理解

    说说你对闭包的理解? 答:闭包是能够读取其它函数内部变量的函数.本质上闭包是将函数内部和函数外部连接起来的一座桥梁.由于js的链式作用域,因为函数也是对象,函数内部访问函数外部的变量就类似于子对象一级 ...

  2. Spring 多数据源 @Transactional 注解事务管理

    在 Spring,MyBatis 下两个数据源,通过 @Transactional 注解 配置简单的事务管理 spring-mybatis.xml <!--******************* ...

  3. 从零搭建SSM框架(五)Maven实现Tomcat热部署

    配置tomcat 第一步:需要修改tomcat的conf/tomcat-users.xml配置文件.添加用户名.密码.权限. <role rolename="manager-gui&q ...

  4. 详解H5中的history单页面,手动实现单页面开发,细说h5单页面原理

    就目前来看,前端的单页面开发占了很大一部分,一方面无刷新的切换增强了体验,并且浏览器记录依然存在,前进后退都没问题,在之前我们通地址栏中的hash改变来触发onhashchange方法来实现单页面应用 ...

  5. 黑色的cms商城网站后台管理模板——后台

    链接:http://pan.baidu.com/s/1hst6Lbm 密码:9ad7

  6. perl6正则 5: [ ] / | / ||

    也就是可以把多种要匹配的写进[ ] 中, 第种用 | 分开就行了. | 与 || 有差别 |的话, 当匹配位置 相同时, 会取最长的, 而 || , 当前面的匹配成功, 后面的就不会再去匹配. / / ...

  7. Linux下文件目录权限和对应命令的总结

    Linux下的权限有rwx三种,分别对应读,写,执行三种,在对文件和目录时,分别是下列含义: 对应权限的命令为: 文件: r-- cat, more, head, tail w-- echo, vi ...

  8. [Leetcode] Combination Sum 系列

    Combination Sum 系列题解 题目来源:https://leetcode.com/problems/combination-sum/description/ Description Giv ...

  9. 【项目管理】git和码云的使用【转】

    转自:https://www.cnblogs.com/riverdubu/p/6491944.html 缘起 说了那么多关于git和码云相关的事,一直都没给大伙讲解这个码云究竟是个啥玩意儿. 今天就给 ...

  10. STL hashtable阅读记录

    unordered_map,unordered_set等相关内容总结: unordered_map和unordered_set是在开发过程中常见的stl数据结构.其本质是hashtable.在SGI_ ...