#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, вместо того, чтобы разделять их по классам, как раньше, но это не очень важная проблема, и я более чем доволен этим решением.