I'm writing a API to be used in the creation of Interfaces at work. The API allows the user to pick from a set of pre-built widgets and layouts so that multiple interfaces can be created for different units in a short period of time. There will be two translation files; one for the API widgets (which come with the library) and another one that the developer will create for custom data in the interface. To make it easier on the developer I wanted the API to handle all translation by passing the name of the data to the API, but I've come to a stumbling block; I can't get the translator to recognize translated text sent to it, but it will recognize local literal strings.
Here's a short example of what I'm talking about.
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 file\n";
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();
}
I typed this out by hand so there might be a couple of typos, but the concept still holds true - you have to call setText in the same class your set your literal string. If you pass a literal to the class, like I'm doing here, it will be ignored. If I make the literal in the class it works fine. This is a problem because I want the developer to pass a literal to the class and then let it do the translation. The developer will still need to make their own translations, but I don't want them to worry about handling the translations.
Am I doing something wrong or is this a Qt limitation?
I suspect this is due to the fact that:
m_pButton = new MyWidget(tr("TEST"));
defines a string in the context of MainWindow
, and you try to translate TEST
in the context of MyWidget
. You can circumvent this by using the static tr()
method on QObject
. This will define TEST
as a translation in the global QObject
context. This can be done by adapting the button widget creation code as follows:
m_pButton = new MyWidget(QObject::tr("TEST"));
and in MyWidget::retranslate()
:
setText(QObject::tr(name().toStdString().c_str()));
Note that you need to regenerate your translation files for this to work!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With