1. 程式人生 > >關於Qt中的tr()函式講解

關於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);

}