QT 国际化扩展所感 an extending QT Translator (自己实现翻译逻辑,编辑更方便)

来源:互联网 发布:亚投行 日本 知乎 编辑:程序博客网 时间:2024/06/06 08:24

QT中提供了支持国际化的QTranslator, 这一工具确实很方便实现简单而且功能丰富的国际化功能,但是如何自己实现自定义的国家化翻译工具呢,如何通过file-driven来实现翻译工具呢?
相比大家知道,我在上篇文章中提到了关于如何使用QTranslator的心得和建议。通过lupdate,linguist,lrelease来对代码中我们标定的tr()字符来进行翻译。


转载请注明出处: http://blog.csdn.net/elfprincexu


总结下来就是:

  • surround all literal strings (the ones to be translated) with tr() functions, i.e. tr("This will be translated");
  • use lupdate command to extract translatable text into translation files (.ts)
  • translate the text files by means of Qt Linguist (since .ts files are actually XML files, they can even be edited with any text editor)
  • use lrelease command to transform the translated .ts files (text) into a binary representation format (.qm) files

具体参考我的上一篇文章: 个人亲测: QT Translate 国际化和本地化的一些使用心得和注意点 http://blog.csdn.net/elfprincexu/article/details/37698129


我想大部分代码工作者都会这么做,确实,但是当你不断想增加一些翻译资料,你就不得不反复的重复上述的步骤。


这里我提供一个基于文件的翻译机制给大家分享一下:

首先,我们定义XML文件来用于存储或者编辑将来要用到的翻译资料:

文件名可以类似  translations_en_US.trn

<translations locale="es_ES">  <entry Id="save">Guardar</entry>  <entry Id="save_as">Guardar como</entry>    <entry Id="open">Abrir</entry>  <entry Id="exit">Salir</entry>  <entry Id="error_network">Error de la red</entry></translations>


其次,我们需要一个类来对这些文件进行阅读并且解析他们。

loadFile() 用来加载我们上面的翻译文件;

parseXml() 用来解析我们的翻译文件;

_mapDefaultLocal 默认的备用的翻译key-value信息。

_mapCurrentLocal 真正装载的本地化信息。


我们定义一个类,Mytranslator, 用来实现我们的功能,具体代码如下:


头文件:

  typedef QMap<QString,QString> LocalMap;  class MyTranslator               //inner class  {  public :      MyTranslator();      virtual ~MyTranslator();      QString translate(const QString &sourceText) const;      bool loadFile(const QString &filename, const QString &locale, const QString &suffix=".trn");      bool parseXml(const QString&filename, const QString& locale, const QString& suffix, LocalMap &mapLocale);      LocalMap _mapDefaultLocal;      LocalMap _mapCurrentLocal;      QString _sCurrentLocal;  };

实现文件:

MyTranslator::MyTranslator() : _sCurrentLocal(""){    _mapCurrentLocal.clear();       //initialization empty    _mapDefaultLocal.clear();       //initialization empty}MyTranslator::~MyTranslator(){}bool MyTranslator::loadFile(const QString &filename, const QString &locale, const QString &suffix){    bool bLoadOk = false;    if (_sCurrentLocal != locale);    {        //while loading  a new locale, clear the maps        _mapCurrentLocal.clear();        _mapDefaultLocal.clear();    }    // first , load default local  en_us    parseXml(filename,"en_US",suffix, _mapDefaultLocal);        // as a backup data if _mapCurrentLocal not contains such data, double safe    //second, parse the correct locale file    bLoadOk =  parseXml(filename,locale,suffix,_mapCurrentLocal);    if (bLoadOk)    {        //we did it, so we change        _sCurrentLocal = locale;        qDebug()<<"UserLoginDlg::MyTranslator::loadFile:  :"<< bLoadOk ;    }    return bLoadOk;}bool MyTranslator::parseXml(const QString &filename, const QString &locale, const QString &suffix, LocalMap &mapLocale){    QXmlStreamReader xml;    QString realname = filename + locale + (suffix.isNull()? QString::fromLatin1(".trn"): suffix);    Str completeFileName = SlxHomeDir().etcFile(qPrintable(realname));      //put them into etc folder;    qDebug()<<"UserLoginDlg::MyTranslator::parseXml: completeFileName :"<< completeFileName.c_str() ;    QFile file(completeFileName.c_str());    bool bSuccess = file.open(QFile::ReadOnly);    if (bSuccess)    {        xml.addData(file.readAll());        QString key;        while(!xml.atEnd())        {            xml.readNext();            if (xml.isStartElement())            {                if (xml.name() == "translations")                {                    if (xml.attributes().value("locale").toString() != locale)                    {                        qDebug()<<"UserLoginDlg::MyTranslator::parseXml: parse error :"<< xml.attributes().value("locale").toString() << "not match with "<< locale;                        bSuccess = false;                        break;                    }                }                else if (xml.name() == "entry")                {                    key = xml.attributes().value("Id").toString();                    mapLocale[key] = xml.readElementText();                }            }            if (xml.hasError())   // for some negative errors (like xml not well formed). need to carefully handle, remove the tmp file and return false            {                qDebug()<<"UserLoginDlg::MyTranslator::parseXml: file : "<< completeFileName.c_str() <<" ,read error: [erroString :"<< xml.errorString()<<"],[lineNumber :" << xml.lineNumber()<<"],[columNumber :"<<xml.columnNumber()<<"]";                file.close();                return false;            }        }    }    else    {        qDebug()<<"UserLoginDlg::MyTranslator::parseXml: Failed to open file"<< file.fileName() << file.errorString();    }    return bSuccess;}QString UserLoginDlg::MyTranslator::translate(const QString &sourceText) const{    QString translation;                        //default empty    translation = _mapCurrentLocal.value(sourceText);    if (translation.isEmpty())    {        //not found in the currrent language        translation = _mapDefaultLocal.value(sourceText);        if (translation.isEmpty())        {            //still not found! show the sourceText            translation = sourceText;        }    }    //qDebug()<<"UserLoginDlg::MyTranslator::translate: return "<< translation;    return translation;}


附上切换逻辑:
void UserLoginDlg::languageCBoxChange(){    qDebug()<<"UserLoginDlg::languageCBoxChange() : current language" << _userLoginUI._languageCBox->currentText();    if ((!_displayReasonsBox) || (!_translator))    {        cerr<<"UserLoginDlg::languageCBoxChange() :_displayReasonsBox false or translator null, shouldn't happen"<<endl;        return;    }    if (_userLoginUI._languageCBox->currentIndex() == 0 ) //english    {        bool loadResult = _translator->loadFile("translations_", "en_US");        this->translateLanguage();        cout<<"UserLoginDlg::languageCBoxChange() :loadResult :  translations_en_US.trn " << loadResult <<endl;    }    else if (_userLoginUI._languageCBox->currentIndex() == 1) //chinese    {        bool loadResult = _translator->loadFile("translations_", "cn_CHN");        this->translateLanguage();        cout<<"UserLoginDlg::languageCBoxChange() :loadResult :  translations_cn_CHN.trn " << loadResult <<endl;    }    else if (_userLoginUI._languageCBox->currentIndex() == 2)  //korean    {        bool loadResult = _translator->loadFile("translations_", "kor_KOR");        this->translateLanguage();        cout<<"UserLoginDlg::languageCBoxChange() :loadResult :  translations_kor_KOR.trn " << loadResult <<endl;    }    else if (_userLoginUI._languageCBox->currentIndex() == 3)   // japnese    {        bool loadResult = _translator->loadFile("translations_", "jpn_JPN");        this->translateLanguage();        cout<<"UserLoginDlg::languageCBoxChange() :loadResult :  translations_jpn_JPN.trn " << loadResult <<endl;    }    else        // if above not satisfied, show english    {        bool loadResult = _translator->loadFile("translations_","en_US");        this->translateLanguage();        cout<<"UserLoginDlg::languageCBoxChange() :loadResult : translations_en_US.trn " << loadResult <<endl;    }}


哪里需要翻译的我们都放在一个函数里面:
void UserLoginDlg::translateLanguage(){    if (_displayReasonsBox &&  _translator  &&  !_totalReasonsList.isEmpty())    {       qDebug()<<"UserLoginDlg::translateLanguage() entered";       for (int i=0; i<_totalReasonsList.size();i++)       {          _userLoginUI._reasonCombo->setItemText(i, _translator->translate(_totalReasonsList.at(i)));       }    }}


好吧,大家现学现用吧,具体逻辑是:


loadFile()你预先编辑好的xml文件。

        对要翻译的地方,使用

_translator->translate(_totalReasonsList.at(i)) 来寻找对应的翻译结果进行显示。

编辑方便,只要往xml文件中增加相应的翻译key-value就可以了。程序中如果要添加翻译的组件显示,同样可以采用相同的逻辑。



0 0
原创粉丝点击