Можно ли динамически переводить приложения Qt без дублирования кода?

Я интегрировал QTranslator класс в моем проекте. Пока все работает и при перезапуске программы все текстовые поля переводятся. Теперь я хотел бы обеспечить динамический перевод, чтобы пользователям не нужно было перезапускать приложение.

В моих исследованиях я обнаружил, что необходимо переопределить changeEvent() функционировать так:

void MyWidget::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::LanguageChange) {
        titleLabel->setText(tr("Document Title"));
        ...
        okPushButton->setText(tr("&OK"));
    } else
        QWidget::changeEvent(event);
}

(Источник: http://doc.qt.io/qt-5/internationalization.html)

Для приложений, написанных с помощью Qt designer, кажется, что можно просто вызвать

ui->retranslateUi(this);

в пределах changeEvent() функция и все текстовые поля будут переведены. Но для всех других текстов в приложении текст должен быть установлен как в примере выше. Что мне больно, потому что мне всегда нужно обновлять текст в двух местах, когда я что-то меняю (в changeEvent функция и в основной части моей программы). С большим количеством текстовых полей может легко что-то пропустить.

Есть ли способ обновить эти текстовые поля без необходимости дублировать "text-setting-method"?

2 ответа

Я не уверен, зачем вам нужно дублировать текстовые сеттеры.

Основная идея состоит в том, чтобы установить переводимые тексты один раз в changeEvent() обработчик и вручную отправить LanguageChange событие, как указано в документах. Это также вызовет событие для дочерних виджетов.

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
    titleLabel = new QLabel(this);
    okPushButton = new QPushButton(this);
    // Fire the LanguageChange event - the event handler will set the texts:
    QEvent languageChangeEvent(QEvent::LanguageChange);
    QCoreApplication::sendEvent(this, &languageChangeEvent);
}

void MyWidget::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::LanguageChange) {
        titleLabel->setText(tr("Document Title"));
        okPushButton->setText(tr("&OK"));
    } else {
        QWidget::changeEvent(event);
    }
}

Вы также можете использовать некоторые начальные QCoreApplication::installTranslator(), Это уволит LanguageChange событие и не нужно будет публиковать его вручную.


Другой подход - использовать свои собственные функции вместо событий. Этот подход, как правило, тот же, за исключением того, что вам нужно вызывать свою функцию вручную для дочерних виджетов.

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
    titleLabel = new QLabel(this);
    okPushButton = new QPushButton(this);
    myChildWidget = new MyChildWidget(this);
    retranslate();
}

void MyWidget::retranslate()
{
    titleLabel->setText(tr("Document Title"));
    okPushButton->setText(tr("&OK"));
    myChildWidget->retranslate();
}

В общем случае нет, вы не можете избежать этого.

Один вариант - вместо того, чтобы код приложения непосредственно устанавливал текст, подключите сигнал к лямбда-выражению, устанавливающему текст, а затем запустите сигнал. Затем обработчик событий просто должен запустить сигнал.

Пример:

MyWidget::someCalculation() {
    // Some stuff
    disconnect(this, &MyWidget::updateText, button, Q_NULLPTR);
    connect(this, &MyWidget::updateText, button, [someLocalString](){ button->setText(tr("Button Text %1").arg(someLocalString)); });
    // More stuff
    emit updateText();
}

// Other methods

void MyWidget::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::LanguageChange) {
        emit updateText();
    } else {
        QWidget::changeEvent(event);
    }
}
Другие вопросы по тегам