如何使用QT国际化

时间:2018-12-07 17:01:46

标签: qt qml

这似乎是一个愚蠢的问题,但是我很难在QT 5.12中使国际化顺利进行。

我至少要做两件事:

  • 可以保存用户选择的语言,并在用户下次运行其选择的应用程序时保存该语言(但可能至少需要一个文件来保存该语言),或以本机语言运行该应用程序SO。
  • 具有动态翻译功能,这是指在应用程序运行时自动更改的语言。

关于第一点,我知道要安装系统本地语言的翻译,可以使用Translator.load("qt_" + QLocale::system().name(),QLibraryInfo::location(QLibraryInfo::TranslationsPath))之类的东西。

第二点,我找到了一个解决方案,但是它要求我在发布/调试文件夹中放置一个名称为translation的文件夹(在这种情况下),在其中放置单个.qm文件。

我将提供一个到目前为止我发现的简单示例:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QFontDatabase>
#include <QFont>
#include <QtQml>
#include "trans.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QTranslator Translator;
    Translator.load(":/translations/translating-qml_ru.qm");
    app.installTranslator(&Translator);
    QQmlApplicationEngine engine;
    // object of our class with "magic" property for translation
    Trans trans(&engine);
    // make this object available from QML side
    engine.rootContext()->setContextProperty("trans", &trans);
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    return app.exec();
}

main.qml

import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
ApplicationWindow {
    id: root
    width: 800
    minimumWidth: 500
    height: 600
    minimumHeight: 600
    visible: true
    title: "Translating QML application"

    Column {
        width: parent.width * 0.95
        spacing: 15
        padding: 15

        RowLayout {
            anchors.horizontalCenter: parent.horizontalCenter

            Button {
                Layout.preferredWidth: 76
                Layout.preferredHeight: 53
                text:"EN"
                onClicked: {
                    onClicked: trans.selectLanguage("en");
                }
            }
            Rectangle
            {
                Layout.preferredWidth: 2
                Layout.fillHeight: true
                Layout.margins: 10
                color: "black"
            }
            Button {
                text: "RU"
                Layout.preferredWidth: 76
                Layout.preferredHeight: 53
                onClicked: {
                    onClicked: trans.selectLanguage("ru");
                }
            }
            Rectangle
            {
                Layout.preferredWidth: 2
                Layout.fillHeight: true
                Layout.margins: 10
                color: "black"
            }
            Button {
                text: "NO"
                Layout.preferredWidth: 76
                Layout.preferredHeight: 53
                onClicked: {
                    onClicked: trans.selectLanguage("no");
                }
            }
            Rectangle
            {
                Layout.preferredWidth: 2
                Layout.fillHeight: true
                Layout.margins: 10
                color: "black"
            }
            Button {
                text: "DE"
                Layout.preferredWidth: 76
                Layout.preferredHeight: 53
                onClicked: {
                    onClicked: trans.selectLanguage("de");
                }
            }
        }

        Label {
            font.pixelSize: 16
            text: qsTr("I woke up after midnight and realised - <b>IT DOES</b>!<br/>"
                       + "Everything goes according to the plan.")
        }

    }
}

trans.cpp

#include "trans.h"

Trans::Trans(QQmlEngine *engine)
{
    _translator = new QTranslator(this);
    _engine = engine;
}

void Trans::selectLanguage(QString language)
{
    QString languagesArray[] = { "en", "pt", "es", "br", "de", "dk", "fi", "fr", "it", "lt", "no", "ro", "tr", "hu" };
    QDir dir = QDir(qApp->applicationDirPath()).absolutePath();
    for(int i=0;i<languagesArray->length();i++){
        if(languagesArray[i] != language){
            _translator->load(QString("Lang-%1").arg(languagesArray[i]),QString("%1/translation").arg(dir.path()));
            qApp->removeTranslator(_translator);
        }
    }
    if (!_translator->load(
                QString("translating-qml_%1").arg(language),
                // look for the file in translations folder within working directory
                QString("%1/translations").arg(dir.path())
                )
            )
    {
        qDebug() << "Failed to load translation file, falling back to English";
    }
    // it's a global thing, we can use it anywhere (after #including <QGuiApplication>)
    qApp->installTranslator(_translator);
    _engine->retranslate();

    emit languageChanged();
}

trans.h

#ifndef TRANS_H
#define TRANS_H

#include <QObject>
#include <QTranslator>
#include <QDebug>
#include <QGuiApplication>
#include <QDir>
#include <QQmlEngine>

class Trans : public QObject
{
    Q_OBJECT

public:
    Trans(QQmlEngine *engine);

    Q_INVOKABLE void selectLanguage(QString language);

signals:
    void languageChanged();

private:
    QTranslator *_translator;
    QQmlEngine *_engine;
};

#endif // TRANS_H

我想逐步了解要使该系统完全正常运行所需要做的事情,因为我发现网上的信息(包括qt docs)使我感到困惑。

1 个答案:

答案 0 :(得分:1)

  • 首先,仅需要通过QSettings将标识语言的信息保存在硬盘上。启动应用程序时,应阅读QSettings并相应地进行翻译,并在修改语言后将其保存。

  • 您的第二点不是很清楚,但是我想您想要使用Qt Internationalization的步骤是什么,有几种方法,因为有些任务可以手动完成,而另一些可以自动化。

首先将以下指令添加到.pro:

TRANSLATIONS = /path/of/some_name1.ts \
               /path/of/some_name2.ts \
               /path/of/some_name3.ts 

在我的示例中,我使用以下结构:

TARGET = AppTranslations

# ...

TRANSLATIONS = i18n/$${TARGET}_en.ts \
               i18n/$${TARGET}_de.ts \
               i18n/$${TARGET}_no.ts \
               i18n/$${TARGET}_ru.ts

然后,您必须在.pro所在的文件夹中打开终端或CMD并执行以下命令:

lupdate your_project.pro

这会在您指定的位置生成.ts,然后您必须使用Qt语言学家来编辑该文件进行翻译。

enter image description here

然后使用以下命令将.ts转换为.qm:

lrelease your_project.pro

然后,您可以将.qm添加到嵌入应用程序中的qresource中,但就我而言,我更喜欢将其放在可执行文件侧面的文件夹中,这样可执行文件不会占太大空间,并且可以添加更多翻译而无需重新编译项目,并使其自动化,将下一个命令复制到可执行文件的一侧。

COPY_CONFIG = $$files(i18n/*.qm, true)
copy_cmd.input = COPY_CONFIG
copy_cmd.output = i18n/${QMAKE_FILE_IN_BASE}${QMAKE_FILE_EXT}
copy_cmd.commands = $$QMAKE_COPY_DIR ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
copy_cmd.CONFIG += no_link_no_clean
copy_cmd.variable_out = PRE_TARGETDEPS
QMAKE_EXTRA_COMPILERS += copy_cmd

因此,构建文件夹最终将具有以下结构:

├── AppTranslations
├── i18n
│   ├── AppTranslations_de.qm
│   ├── AppTranslations_en.qm
│   ├── AppTranslations_no.qm
│   └── AppTranslations_ru.qm
│   ...

现在您有了.qm,将实现在应用程序中使用它的逻辑。在Qt 5.10之前,您必须技巧一下,添加一个空字符串以使翻译正常工作,但是最新版本不需要。

在我的情况下,我实现了获取.qm的逻辑,因此由于我使用默认格式,所以可用的语言为:

{Name_Of_Application}_{lang}.qm

该逻辑的另一部分与您的相似,因此我将不做过多详细介绍,而是向您展示代码:

translator.h

#ifndef TRANSLATOR_H
#define TRANSLATOR_H

#include <QDir>
#include <QObject>
#include <QQmlEngine>
#include <QTranslator>

class Translator : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList languages READ languages NOTIFY languagesChanged)
    Q_PROPERTY(QString currentLanguage READ currentLanguage NOTIFY currentLanguageChanged)
public:
    explicit Translator(QQmlEngine *engine, QObject *parent = nullptr);
    Q_INVOKABLE void selectLanguage(const QString & language);
    QStringList languages() const;
    QString currentLanguage() const;
    Q_INVOKABLE static QString languageByCode(const QString & code);
signals:
    void languageChanged();
    void languagesChanged();
    void currentLanguageChanged();
private:
    const QString extension = ".qm";
    QQmlEngine *m_engine;
    QTranslator *m_translator;
    QStringList m_languages;
    QString m_currentLanguage;
    QDir m_dir;
};

#endif // TRANSLATOR_H

translator.cpp

#include "translator.h"
#include <QGuiApplication>
#include <QDirIterator>
#include <QSettings>

Translator::Translator(QQmlEngine *engine, QObject *parent) :
    QObject(parent),
    m_engine(engine)
{
    m_translator = new QTranslator(this);
    m_dir = QDir(QGuiApplication::applicationDirPath(),
                 "*"+extension,
                 QDir::Name|QDir::IgnoreCase,
                 QDir::Files);
    m_dir.cd("i18n");
    m_languages.clear();
    for(QString entry: m_dir.entryList()){
        entry.remove(0, QGuiApplication::applicationName().length()+1);
        entry.chop(extension.length());
        m_languages.append(entry);
    }
    emit languagesChanged();
    QSettings settings;
    QString lang =settings.value("Language/current", QLocale::system().bcp47Name()).toString();
    selectLanguage(lang);
}

QStringList Translator::languages() const
{
    return m_languages;
}

QString Translator::currentLanguage() const
{
    return m_currentLanguage;
}

QString Translator::languageByCode(const QString &code)
{
    QLocale lo(code);
    return QLocale::languageToString(lo.language());
}

void Translator::selectLanguage(const QString &language)
{
    qApp->removeTranslator(m_translator);
    if(m_languages.contains(language)){
        QString file = QString("%1_%2%3").arg(QGuiApplication::applicationName()).arg(language).arg(extension);
        if(m_translator->load(m_dir.absoluteFilePath(file))){
           m_currentLanguage = language;
           QSettings settings;
           settings.setValue("Language/current", language);
           emit currentLanguageChanged();
        }
    }
    qApp->installTranslator(m_translator);
    m_engine->retranslate();
    emit languageChanged();
}

然后将其应用于您的项目:

main.cpp

#include "translator.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QCoreApplication::setOrganizationName("Translations INC");
    QCoreApplication::setOrganizationDomain("translations.com");

    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    Translator trans(&engine);
    engine.rootContext()->setContextProperty("trans", &trans);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
ApplicationWindow {
    id: root
    width: 800
    minimumWidth: 500
    height: 600
    minimumHeight: 600
    visible: true
    title: "Translating QML application"

    Column {
        width: parent.width * 0.95
        spacing: 15
        padding: 15
        RowLayout {
            anchors.horizontalCenter: parent.horizontalCenter
            Repeater{
                model: trans.languages
                Button{
                    id: btn
                    property string code: modelData
                    text: trans.languageByCode(code)
                    onClicked: trans.selectLanguage(btn.code)
                    Layout.preferredWidth: 100
                    Layout.preferredHeight: 50
                    highlighted: code == trans.currentLanguage
                }
            }
        }
        Label {
            font.pixelSize: 16
            text: qsTr("I woke up after midnight and realised - <b>IT DOES</b>!<br/>"
                       + "Everything goes according to the plan.")
        }
    }
}

找到完整的示例here