Qt入門(12)——Qt國際化

尹成發表於2014-09-30
應用的國際化就是使應用成為能被非本國的人使用的過程。


有的情況下,國際化很簡單,例如,使一個US應用可被Australian或者British使用者理解,工作可能少於幾個拼寫修正。但是使一個US應用可以被Japanese使用者使用,或者一個Korean應用可被German使用者使用,就會需要軟體不僅工作於不同語言下,還要使用不同的輸入技術、字元編碼和表達習慣。

對所有使用者可見的文字使用QString
既然QString內部就使用Unicode編碼,那麼使用常見的文字處理手段,就可以透徹地處理世界上的每種語言。同時,既然所有向使用者呈現文字的Qt函式都把QString作為引數,也就沒有了char*到QString的轉換的時間開銷。
在“程式設計師空間”(例如QObject的名稱和檔案格式文字)的字串不需要使用QString;傳統的char*或者QCString類就夠用了。
你不大可能注意到你在使用Unicode;QString和QChar就如同早期版本的傳統C中的粗糙的const char*和char。

對所有文字形式的文字使用tr()
無論你的程式在哪裡對將會呈現給使用者的文字使用了"quoted text",要確保它被QApplication::translate()函式處理過。其實做到這一點只需要使用QObject::tr()。例如,假設LoginWidget是QWidget的一個子類:

    LoginWidget::LoginWidget()
    {
        QLabel *label = new QLabel( tr("Password:"), this );
        ...
    }


這就解決了你可能要寫的使用者可見的字串的99%。
如果這些quoted text不是在QObject子類的成員函式中,可以使用一個適當的類的tr()函式,或者直接使用QApplication::translate()函式:
    void some_global_function( LoginWidget *logwid )
    {
        QLabel *label = new QLabel(
                LoginWidget::tr("Password:"), logwid );
    }


    void same_global_function( LoginWidget *logwid )
    {
        QLabel *label = new QLabel(
                qApp->translate("LoginWidget", "Password:"),
                logwid );
    }



如果你需要不在函式裡的可翻譯文字,有兩個巨集可以幫忙:QT_TR_NOOP()和QT_TRANSLATE_NOOP()。它們僅僅標示出文字,以便於被下面描述的lupdate工具提取。巨集擴充套件為只是文字(沒有上下文)。

QT_TR_NOOP()的例子:


    QString FriendlyConversation::greeting( int greet_type )
    {
        static const char* greeting_strings[] = {
            QT_TR_NOOP( "Hello" ),
            QT_TR_NOOP( "Goodbye" )
        };
        return tr( greeting_strings[greet_type] );
    }
QT_TRANSLATE_NOOP()的例子:


    static const char* greeting_strings[] = {
        QT_TRANSLATE_NOOP( "FriendlyConversation", "Hello" ),
        QT_TRANSLATE_NOOP( "FriendlyConversation", "Goodbye" )
    };


    QString FriendlyConversation::greeting( int greet_type )
    {
        return tr( greeting_strings[greet_type] );
    }


    QString global_greeting( int greet_type )
    {
        return qApp->translate( "FriendlyConversation",
                                greeting_strings[greet_type] );
    }


如果你使用定義的巨集QT_NO_CAST_ASCII編譯你的軟體,從而關閉了從const char*到QString的自動轉換,你很可能會捕捉到你錯過的字串。更多資訊參見QString::fromLatin1()。關閉這個轉換會使程式設計有點兒麻煩。


如果你的原始碼語言使用Latin-1之外的字符集,你會發現QObject::trUtf8()比QObject::tr()更好用,因為tr()依賴於QApplication::defaultCodec(),這使它比QObject::trUtf8()更脆弱。


對於加速鍵值(Accelerator value)使用QKeySequence()


加速鍵值,例如Ctrl+Q或者Alt+F,也需要翻譯。 如果你的應用給“Quit”直接編碼(hardcode)為CTRL+Key_Q,翻譯者就不能過載它了。正確的習慣用法是


    QPopupMenu *file = new QPopupMenu( this );
    file->insertItem( tr("&Quit"), this, SLOT(quit()),
                      QKeySequence(tr("Ctrl+Q", "File|Quit")) );


對簡單引數使用QString::arg()


對於國際化的文字,在字串中類似printf()風格的插入引數一般是不好的選擇,因為有時候有必要在翻譯時改變引數的順序。不管怎樣,QString::arg()函式為引數替換提供了一種簡單的途徑:


    void FileCopier::showProgress( int done, int total,
                                   const QString& current_file )
    {
        label.setText( tr("%1 of %2 files copied.\nCopying: %3")
                        .arg(done)
                        .arg(total)
                        .arg(current_file) );
    }


相關文章