版权声明:本文系作者原创。未经许可,不得转载。

    本文以skytree-compositor程序为例,讲解如何将程序翻译为多种语言。
    在界面中,点击“设置”,更改“语言”时,dbus会向上层发送一个信号valueChanged,上层应用响应该信号,就可以实时更改语言。
1、从dbus读取语言改变的信号和系统使用的语言名称。类CmosTranslate使用了Qt自带的QTranslator类,并添加了读取dbus的功能。实现了封装,供其他程序使用。一共两个文件。代码如下:

CmosTranslate.h文件


#ifndef CmosTranslate_H
#define CmosTranslate_H
#include <QObject>
#include <QDBusVariant>
#include <QTranslator>
/**
    • 这个类根据dbus发出的信号,从dbus读取当前语言名称,实时改变程序的语言
      */

    1. CmosTranslate : public QObject
      {

         Q_OBJECT
         Q_DISABLE_COPY(CmosTranslate)
         Q_PROPERTY(QString name READ name WRITE setname NOTIFY nameChanged)
         Q_PROPERTY(QString path READ path WRITE setpath NOTIFY pathChanged)
         Q_PROPERTY(QString transflag READ transflag NOTIFY transflagChanged)

      public:

         CmosTranslate(QObject *parent = 0);
         ~CmosTranslate();
         //获取程序名称
         QString name() {
             return m_name;
         }
         //设置程序名称
         void setname(QString value) {
             m_name = value;
             emit nameChanged(m_name);
         }
         //获取多语言文件存放的路径
         QString path() {
             return m_path;
         }
         //获取多语言文件存放的路径
         void setpath(QString value) {
             m_path = value;
             emit pathChanged(m_path);
         }
         QString transflag() { return ""; }
    2. slots:

         void readData(const QString &domain, const QString &key, const QDBusVariant &value);
         //根据读取的语言名称,载入相应的翻译文件
         void trans(QString names="");
         bool appQuit();

      Q_SIGNALS:

         void nameChanged(const QString &);
         void pathChanged(const QString &);
         void langChanged(const QString &);
         void transflagChanged();

      private:

         //程序名称
         QString m_name;
         //翻译文件存放路径
         QString m_path;
         QString m_selfcmd;
         QTranslator m_translator;
         // 静态方法

      public:

         /**
      • 获取单实例
        *

      • @return 指向单实例的指针
        */

      1. CmosTranslate *instance();
        };

      #endif // CmosTranslate_H

      CmosTranslate.cpp文件

      #include "CmosTranslate.h"
      #include <QtDBus/QtDBus>
      #include <QApplication>

    3. QString SETTING_SERVICE_NAME = "cn.cmos.settings.Database";

    4. QString SETTING_OBJECT_PATH = "/";

    5. QString SETTING_INTERFACE_NAME= "cn.cmos.settings.Database";

    6. QString APP_PATH = qgetenv("APPDIR_SYSTEM");

    7. QString LIBRARY_PATH = "/usr/share/library/";
      //如果没有设置路径,则默认为qm路径

    8. QString TRANSLATIONS_PATH = "qm";

    9. QString DOMAIN_VALUE = "cn.cmos.settings.Locale";

    10. QString KEY_VALUE = "SYSTEM_LANGUAGE";
      //设置该程序的默认的翻译文件存放路径

    11. QString QM_FILE_PATH = "/usr/share/translations";
      CmosTranslate::CmosTranslate(QObject *parent):

         QObject(parent)

      {

         QFile file("/proc/self/cmdline");
         file.open(QIODevice::ReadOnly | QIODevice::Text);
         m_selfcmd = file.readAll();
         m_selfcmd= m_selfcmd.left(m_selfcmd.lastIndexOf( QDir::separator() ) );
         m_selfcmd= m_selfcmd.left(m_selfcmd.lastIndexOf( QDir::separator() ) );
         m_name = QApplication::applicationName();
         m_path = QM_FILE_PATH;
         //将dbus的信号与程序连接
         QDBusConnection::sessionBus().connect(SETTING_SERVICE_NAME, SETTING_OBJECT_PATH,
                                               SETTING_INTERFACE_NAME, "valueChanged" ,this,
                                               SLOT(readData(QString, QString, QDBusVariant)));

      }
      CmosTranslate::~CmosTranslate()
      {
      }

    12. CmosTranslate::trans(QString names)
      {

         QString name =names;
         if(name.isEmpty()) {
             //调用dbus的相应方法,读取当前语言名称
             QDBusMessage m = QDBusMessage::createMethodCall(SETTING_SERVICE_NAME,
                                                             SETTING_OBJECT_PATH,
                                                             SETTING_INTERFACE_NAME,
                                                             "value");
             m << "cn.cmos.settings.Locale" << "SYSTEM_LANGUAGE" <<  QVariant::fromValue(QDBusVariant("zh_CN")) ;
             QDBusReply<QDBusVariant> value = QDBusConnection::sessionBus().call(m);
             name = value.value().variant().toString();
         }
         if(name.isEmpty()) {
             name = "zh_CN";
         }
         QString fileName = m_name + "." + name;
         QString path = m_path;
         /**如果系统和程序都没有设置,则到默认路径下寻找翻译文件
      • 如果应用程序存在,则默认路径为/usr/qm;

      • 否则默认路径为/usr/share/library

          */
         if(path.isEmpty()) {
             if(m_name == QApplication::applicationName()) {
                 path = m_selfcmd + QDir::separator()
        • TRANSLATIONS_PATH + QDir::separator();

              }
      1. {

                path = LIBRARY_PATH;
            }
        }
        qDebug()<<"当前语言名称:"<<name;
        qDebug()<<"翻译文件存放路径:"<<path;
        qDebug() << "翻译文件名称:"<<fileName;
        //安装翻译组件
        m_translator.load(fileName , path);
        QApplication::installTranslator(&m_translator);
        //若系统没有设置语言,缺省为英文
        if(name.isEmpty()) {
      2. = "en_US";

        }
        //向程序发出语言改变的信号,这是对dbus信号的封装
      1. langChanged(name);

      2. transflagChanged();
        }

    13. CmosTranslate::readData(const QString &domain, const QString &key, const QDBusVariant &value)
      {

         if(domain == DOMAIN_VALUE && key == KEY_VALUE){
             QString name = value.variant().toString();
             trans(name);
         }

      }

    14. CmosTranslate::appQuit()
      {

         QDBusMessage m = QDBusMessage::createMethodCall("com.nomovok.skytree.compositor",
                                                         "/Compositor",
                                                         "com.nomovok.skytree.CompositorInterface",
                                                         "appQuit");
         m <<QVariant::fromValue<pid_t>(QCoreApplication::applicationPid());
         QDBusReply<bool> back = QDBusConnection::systemBus().call(m);
         return back.value();

      }
      /

      • 静态方法
        /
        /**

      • 获取单实例
        *

      • @return 指向单实例的指针
        */
        CmosTranslate *CmosTranslate::instance()

      {

         static CmosTranslate *instance = 0;
         if (!instance)
         {
             instance = new CmosTranslate;
         }
         return instance;

      }

      2、在主程序中增加组件

      main.cpp文件

      #include "CmosTranslate.h"
      ……

    15. main(int argc, char *argv[]) {

      ……
      QQmlEngine engine;
      ……
      //向QML端添加组件

         engine.rootContext()->setContextProperty("cmostranslate", CmosTranslate::instance());
      

      ……
      }

      3、在qml文件中响应该组件发出的信号

      CancelButton.qml文件

    16. QtQuick 2.0
      //定义关机界面底部的“取消”按钮
      Rectangle {

             id: cancelButton       
             anchors.fill: parent
             
             Text {
                 id:cancelLabel            
                 anchors.centerIn: parent
                 font.pixelSize : 30
             }
             
             //该控件的信号
             signal languageChanged(string name)
             //该控件的相应信号的响应函数
             onLanguageChanged: {
                 translator()
             }
             //构造函数
             Component.onCompleted: {
                 // 连接组件信号和控件的槽
                 cmostranslate.langChanged.connect(cancelButton.languageChanged)
                 // 调用组件函数初始化语言名称
                 cmostranslate.trans();
             }
             //析构函数
             Component.onDestruction: {
                 //断开组件信号和控件槽
                 cmostranslate.langChanged.disconnect(cancelButton.languageChanged);
             }
             //翻译
             function translator() {
                 cancelLabel.text = qsTr("CANCEL")
             }
         }
      

      4、修改pro文件,将CmosTranslate.h和CmosTranslate.cpp加入到编译选项中,以及设置qm文件的路径。此路径必须与CmosTranslate.cpp中设置的路径一致。为了防止修改时出现不一致的情况,可以略作改进。如:可以在某个配置文件中统一设置,其他文件获取该配置。

      skytree-compositor.pro文件

      ……
      HEADERS += CmosTranslate.h
      SOURCES += CmosTranslate.cpp
      ……

      # translate
      TARGET_DIR = /usr/share/translations
      qm.path = $$TARGET_DIR
      qm.files = *.qm
      INSTALLS += qm

      5、修改spec文件。在spec文件中,将qm文件配置成安装时装载到指定路径。
      此路径必须与CmosTranslate.cpp中设置的路径一致。为了防止修改时出现不一致的情况,可以略作改进。如:可以在某个配置文件中统一设置,其他文件获取该配置。

      skytree-compositor.spec文件

      ……
      %files
      /usr/share/translations/%{name}.zh_CN.qm
      ……

      6、生成qm文件。在应用程序根目录,即pro文件和spec文件所在的目录。用Qt的工具lupdate、linguist、lrelease 生成ts文件和qm文件。ts文件和qm文件的命名规则必须和CmosTranslate.cpp中设定的一致,否则会找不到文件,无法载入。本程序中命名规则为:程序名.语言名.后缀名。

      $ lupdate . -ts skytree-compositor.zh_CN.ts
      递归抓取程序中所有需要翻译的字符串。Ts文件内容:

      skytree-compositor.zh_CN.ts文件

      <?xml version="1.0" encoding="utf-8"?>
      <!DOCTYPE TS>
      <TS version="2.0" language="zh_CN">
      <context>

         <name>CancelButton</name> 
         <message> 
             <location filename="shutdownscreen/CancelButton.qml" line="67"/> 
             <source>CANCEL</source> 
             <translation type="unfinished"></translation> 
         </message> 

      </context>
      </TS>

      $ linguist skytree-compositor.zh_CN.ts
      将字符串翻译完成,保存退出。此时,ts文件内容有改变:

      skytree-compositor.zh_CN.ts文件

      <?xml version="1.0" encoding="utf-8"?>
      <!DOCTYPE TS>
      <TS version="2.0" language="zh_CN">
      <context>

         <name>CancelButton</name> 
         <message> 
             <location filename="shutdownscreen/CancelButton.qml" line="67"/> 
             <source>CANCEL</source> 
             <translation type="unfinished">取消</translation> 
         </message> 

      </context>
      </TS>

      $ lrelease skytree-compositor.zh_CN.ts
      将翻译好的ts文件生成qm文件。qm文件不是文本格式。


    lansheng228
    256 声望4 粉丝