QQmlEngine 重新翻译不翻译其他 StackView 项目

QQmlEngine retranslate not translating other StackView items

我有一个自定义 class,我需要在其中保存新选择的语言并同时更改应用语言。基于QtCreator中StackView示例工程的示例:

//main.cpp
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);

    qmlRegisterType<CustomClass>("io.qt.CustomClass", 1, 0, "CustomClass");

    QTranslator translator;
    translator.load(":/EN.qm");
    app.installTranslator(&translator);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}



//customclass.h
class CustomClass : public QObject
{
    Q_OBJECT
public:
    explicit CustomClass(QObject *parent = nullptr) : QObject(parent) {}
    Q_INVOKABLE void change(){
        QTranslator translator;
        QApplication::removeTranslator(&translator);
        translator.load(":/CZ.qm");
        QApplication::installTranslator(&translator);
        //QQmlApplicationEngine * engine = qobject_cast<QQmlApplicationEngine *>(qmlEngine(this));
        QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
        engine->retranslate();
    }
};



//main.qml
...
CustomClass{id:test}
...
 ItemDelegate {
                text: qsTr("Page 1")
                width: parent.width
                onClicked: {
                    test.change()
                    drawer.close()
                }
            }...



//.pro file
QT += quick gui core
...
TRANSLATIONS = EN.ts CZ.ts
...
HEADERS += \
    customclass.h

在此示例中,单击第 1 页按钮应该会更改语言。

我的应用程序基于 StackView,当我使用此代码调用该函数时,一切似乎都正常。字符串已翻译。然而,当我将一个新项目推入堆栈时(比如从菜单中打开一个新部分),那里的字符串会在更改之前恢复为原始语言。就像重新翻译仅更改当前可见的字符串一样。

有人知道问题出在哪里吗?我怀疑没有正确获取引擎。这是一个自定义 class 我需要注册 (qmlRegisterType) 才能在 qml 中使用,我不确定如何在那里正确地获取引擎(因为引擎是在 main 函数中创建的)。

我使用了一个肮脏的技巧来实现整个应用程序的重新翻译,而无需在 class 中获取引擎。它不是完美的,但它有效。我在 main 中添加了一个循环,如下所示:

    int returnValue = 0;
    do
    {
        QApplication app(argc, argv);
        QTranslator translator;
        translator.load(":/translation/"+langString+".qm"); //langString might be the "CZ" as in the question example
        app.installTranslator(&translator);

        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/src/qml/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;

        returnValue = app.exec();

        langString = settings.value("language").toString();
    }
    while(returnValue == TRANSLATION_RESTART);


    return returnValue;

所以在我的习惯 class 中,我只需使用以下命令退出应用程序:

    qApp->exit(TRANSLATION_RESTART);

而且我还保存了 langString 值。这样应用程序基本上就用新语言重新启动了。

更新:虽然这可行,但最好将引擎和应用程序存储到使用问题中提到的方法处理翻译的单例 class 中。

我运行陷入同样的​​问题。我找到的解决方案是在创建 QT运行slator 对象时使用 new 运算符。这导致在堆内存而不是堆栈中创建对象。如果它在堆栈内存中,QT运行slator 将在函数完成后被删除(至少,我是这么理解的。我相信有更多 C++ 经验的人可能会更好地解释它) .

那么您的自定义类代码将如下所示:

//customclass.h
class CustomClass : public QObject
{
    Q_OBJECT
public:
    explicit CustomClass(QObject *parent = nullptr) : QObject(parent) {}
    Q_INVOKABLE void change(){
        QTranslator *translator = new QTranslator(qApp);
        if (m_previousTranslator) {
            QApplication::removeTranslator(m_previousTranslator);
            m_previousTranslator->deleteLater();
            m_previousTranslator = nullptr;
        }
        translator->load(":/CZ.qm");
        m_previousTranslator = translator;
        QApplication::installTranslator(translator);
        QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
        engine->retranslate();
    }
private:
    QTranslator *m_previousTranslator = nullptr;
};

请注意,我添加了一个私有变量 m_previousTranslator 来进行一些内存管理。我没有测试这个示例代码,但我在我的项目中使用了非常相似的代码并且它有效