2017-05-08 50 views
1

Qt的網站推薦將本地化字符串就在這樣的代碼中間:存儲可本地化字符串的習慣Qt方式?

fileMenu = menuBar()->addMenu(tr("&File")); 

不過,我應該如何存儲出現在項目中多次串?把它們放在一個單獨的作品,但tr()呼叫意味着我必須單獨對它們進行初始化:

struct MyLocalizableStrings 
{ 
    QString mErrorMessageFileNotFound; 
    QString mErrorMessageNoCanDoThis; 

    MyLocalizableStrings() : 
     mErrorMessageFileNotFound(QObject::tr("File not found.")), 
     mErrorMessageNoCanDoThis(QObject::tr("Operation is not possible at the moment.")) 
     {} 
};   

很笨拙,容易陷入困境;我寧願保持聲明和初始化。當然可以將一系列const char*保存在專用的命名空間中,但是在呼叫站點存在遺漏tr()的風險 - 整個方法嚴重不標準。

有什麼更好的點子?

+1

只要使用tr(「foo」),只要你需要它。儘管它看起來像代碼重複,但它是最好的方法。在字符串中存儲本地化並不是一個好主意。您的MyLocalizableStrings可防止例如動態語言的變化,除非你添加一個重新翻譯功能...而這裏又變得越來越複雜。所以,只要使用tr(「foo」)就可以了。拼寫錯誤很容易通過語言學家發現。 – Lorenz

+1

http://doc.qt.io/qt-5/i18n-source-translation.html#using-qt-tr-noop-and-qt-translate-noop-in-c – Evgeny

+0

@洛倫茲它比代碼重複更糟糕,這是數據重複。我會在另一個函數中寫一個函數「Operation not possible」,在另一個函數中寫作「此刻不可能的操作」,並且在一年之內,我將無法記住這裏是否存在任何語義差異。更糟糕的是,它可能不是我,而是一個完全不同的人,沒有能力/時間來檢查代碼,將代碼翻譯成語言這樣的語言。最佳實踐存在的原因是:不會複製硬編碼的用戶可讀消息。 – sigil

回答

1

出現多次的字符串和意思是相同的需要在一個或多個專用類中 - 所以你幾乎是對的。課程需要翻譯環境,以便翻譯人員更容易理解這些是常見的信息。你也應該充分利用其在C++ 11的成員初始化到幹:

首先,讓我們得到了一個基類和必要的助手建立:

#include <QCoreApplication> 

template <typename Derived> 
class LocalizableStringBase { 
    Q_DISABLE_COPY(LocalizableStringBase) 
protected: 
    using S = QString; 
    static LocalizableStringBase * m_instance; 
    LocalizableStringBase() { 
     Q_ASSERT(!m_instance); 
     m_instance = this; 
    } 
    ~LocalizableStringBase() { 
     m_instance = nullptr; 
    } 
public: 
    static const Derived * instance() { 
     return static_cast<const Derived*>(m_instance); 
    } 
    void reset() { 
    auto self = static_cast<const Derived*>(this); 
    self->~Derived(); 
    new (self) Derived(); 
    } 
}; 

#define DEFINE_LOCALIZABLE_STRINGS(Derived) \ 
    template <> \ 
    LocalizableStringBase<Derived> * LocalizableStringBase<Derived>::m_instance = {}; \ 
    const Derived & Derived##$() { return *(Derived::instance()); } 

然後,對於每一組你需要本地化的字符串:

// Interface 

class MyLocalizableStrings : public LocalizableStringBase<MyLocalizableStrings> { 
    Q_DECLARE_TR_FUNCTIONS(MyLocalizableStrings) 
public: 
    S errorMessageFileNotFound = tr("File not found."); 
    S errorMessageNoCanDoThis = tr("Operation is not possible at the moment."); 
}; 

// Implementation 

DEFINE_LOCALIZABLE_STRINGS(MyLocalizableStrings) 

用法:

#include <QDebug> 

void test() { 
    qDebug() << MyLocalizableStrings$().errorMessageFileNotFound; 
} 

int main(int argc, char ** argv) 
{ 
    QCoreApplication app{argc, argv}; 
    MyLocalizableStrings str1; 
    test(); 
    // Change language here 
    str1.reset(); 
    test(); 
} 

這是相當可讀沒有重複的標識符。它也避免了靜態初始化順序失敗。

+0

謝謝你的傳統能力和全面的答案!也許我會用它來取代我昨天解決的劣勢'std :: map'方法,這主要是因爲它的簡單性。 – sigil

+0

至少對我而言,仍然存在這樣的問題:這種方法不支持動態語言更改。一個簡單的靜態類函數是不夠的? 'class TrStrings:public QObject {Q_OBJECT public:static QString errorMessage(){return tr(「error」);}};' – Lorenz

+0

@Lorenz它確實支持動態語言更改。您必須在語言更改時重新創建「MyLocalizableStrings」對象,並在頂級窗口上調用QWidget :: update(),並假定所有小部件都配置爲直接從字符串類獲取文本。 –