Как заставить перевод работать вне класса?

#qt #translation

#qt #перевод

Вопрос:

Я пишу API, который будет использоваться при создании рабочих интерфейсов. API позволяет пользователю выбирать из набора готовых виджетов и макетов, чтобы за короткий промежуток времени можно было создать несколько интерфейсов для разных модулей. Будет два файла перевода; один для виджетов API (которые поставляются с библиотекой), а другой, который разработчик создаст для пользовательских данных в интерфейсе. Чтобы упростить работу разработчика, я хотел, чтобы API обрабатывал весь перевод, передавая имя данных в API, но я столкнулся с камнем преткновения; я не могу заставить переводчик распознавать переведенный текст, отправленный ему, но он распознает локальные литеральные строки.

Вот краткий пример того, о чем я говорю.

 class Object
{
    public:
        Object(QString name) { m_Name = name; };
        QString name() { return m_Name; };
    private:
        QString m_Name;
};

class MyWidget : public QPushButton, public Object
{
    Q_OBJECT

    public:
        MyWidget(QString name);
        ~MyWidget();
        void retranslate();

    protected slots:
        void buttonPressed();
        void changeEvent(QEvent* event);

    private:
        enum Language { ENGLISH, JAPANESE };
        Language m_Language;
        QTranslator* m_pTranslator;
};

MyWidget::MyWidget(QString name)
:Object(name) // this does not work, but :Object(tr("TEST")) does
{
    m_pTranslator = new QTranslator();
    m_Language = ENGLISH;
    connect(this, SIGNAL(pressed()), this, SLOT(buttonPressed()));
    retranslate();
}

MyWidget::~MyWidget()
{
    delete m_pTranslator();
}

void MyWidget::buttonPressed()
{
    std::string qm;

    m_Language == ENGLISH ? m_Language = JAPANESE : m_Language = ENGLISH;
    m_Language == ENGLISH ? qm = "lang_en" : qm = "lang_jp";

    qApp->removeTranslator(m_pTranslator);

    if(!m_pTranslator->load(qm.c_str()))
        std::cout << "Error loading translation filen";

    qApp->installTranslator(m_pTranslator);
}

void MyWidget::retranslate()
{
    setText(tr(name().toStdString().c_str()));
}

void MyWidget::changeEvent(QEvent* event)
{
    if(event->type() == QEvent::LanguageChange)
        retranslate();
    else
        QWidget::changeEvent(event);
}


class MainWindow : public QMainWindow
{
    Q_OBJECT

    public:
        MainWindow();
        ~MainWindow();

    private:
        MyWidget* m_pButton;
};

MainWindow::MainWindow()
{
    m_pButton = new MyWidget(tr("TEST")); // this is what I want to do, but this will not translate
    setCentralWidget(m_pButton);
}

MainWindow::~MainWindow()
{
    delete m_pButton;
}

// main.cpp
int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
 }
  

Я напечатал это вручную, поэтому может быть несколько опечаток, но концепция остается верной — вы должны вызвать setText в том же классе, в котором вы задаете свою буквальную строку. Если вы передадите литерал классу, как я делаю здесь, он будет проигнорирован. Если я создаю литерал в классе, он работает нормально. Это проблема, потому что я хочу, чтобы разработчик передал литерал классу, а затем позволил ему выполнить перевод. Разработчику все равно нужно будет создавать свои собственные переводы, но я не хочу, чтобы они беспокоились об обработке переводов.

Я делаю что-то не так или это ограничение Qt?

Ответ №1:

Я подозреваю, что это связано с тем, что:

 m_pButton = new MyWidget(tr("TEST"));
  

определяет строку в контексте MainWindow , и вы пытаетесь перевести TEST в контексте MyWidget . Вы можете обойти это, используя статический tr() метод on QObject . Это будет определяться TEST как перевод в глобальном QObject контексте. Это можно сделать, адаптировав код создания виджета кнопки следующим образом:

 m_pButton = new MyWidget(QObject::tr("TEST"));
  

и в MyWidget::retranslate() :

 setText(QObject::tr(name().toStdString().c_str()));
  

Обратите внимание, что для этого вам нужно повторно создать файлы перевода!

Комментарии:

1. Да, это исправлено! Linguist теперь помещает все переводы в QObject, вместо того, чтобы разделять их по классам, как раньше, но это не очень важная проблема, и я более чем доволен этим решением.