關於Qt中的tr()函式講解
轉載自https://blog.csdn.net/andy_93/article/details/52836369
在論壇中漂,經常遇到有人遇到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, 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 類的例項,我們繼續看一下該類的原始碼:
/*! \internal */ QString QMetaObject::tr(const char *s, const char *c) const { returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr); } /*! \internal */ QString QMetaObject::trUtf8(const char *s, const char *c) const { returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8);
}