qt - 如何使用QT国际化

标签 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 文档)让我感到困惑。

最佳答案

  • 对于第一点,只需通过QSettings将标识语言的信息保存在硬盘上即可。当应用程序启动时,应读取 QSettings,并相应地完成翻译,并在修改语言时保存它。

  • 您的第二点不是很清楚,但我想您想知道使用 Qt 国际化的步骤是什么,有多种方法,因为有些任务可以手动完成,有些任务可以自动化。

首先将以下指令添加到.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 Linguist 编辑该文件来进行翻译。

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

逻辑的其他部分与您的类似,因此我不会详细介绍,我将向您展示代码:

翻译器.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

翻译器.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();
}

然后它适用于您的项目:

ma​​in.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();
}

ma​​in.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 .

关于qt - 如何使用QT国际化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53673924/

相关文章:

c++ - Qt 样式表 - 未应用背景属性

javascript - 使用 Javascript 从 Qt WebView 获取文本

c++ - 在 QtQuick 中自定义样式

c++ - Qt:如何在选择项目时显示图标

c++ - 覆盆子 : Qt issue connecting device because SSH client-server capabilities don't match

c++ - 从 QML 访问 C++ 函数

qt - 布局 2 block 元素的正确方法

c++ - 从 C++ 更改 QML 对象值

c++ - 使用 QQmlContext::setContextObject 使 C++ 对象对 QML 可见

c++ - 如何在 C++ 中定义扩展为条件语句的宏?