PDA

View Full Version : translation loading / execution order / QObject magic(?)



zaphod.b
6th January 2014, 16:37
(Sry made a mistake while editing the post. This is a reconstruction.)

My app loads modules which themselves are responsible to load their translations. I wanted to delegate translation loading to a translatable module's parent class ctor in order to share code and, more importantly, ensure they are loaded before any widgets are created.

The following doesn't work - _action's text is untranslated "Welcome":


class Translatee
{
public:
Translatee(const QString &libname)
{
QString path("/path/to/qm/files/");
QTranslator translator;
bool ok = translator.load(libname + "_fr", path);
ok &= qApp->installTranslator(&translator);
//ok == true
}
}


class FooModule : public QObject
, public Translatee
{
Q_OBJECT
QAction *_action;
public:
FooModule(QObject *parent)
: QObject(parent)
, Translatee(metaObject()->className().toLower())
{
_action = new QAction(tr("Welcome"), this);
}
}


This does work - _action's text is "Bienvenue" as expected:


class FooModule : public QObject
{
Q_OBJECT
QAction *_action;
public:
FooModule(QObject *parent)
: QObject(parent)
{
QString libname(metaObject()->className().toLower());
QString path("/path/to/qm/files/");
QTranslator translator;
bool ok = translator.load(libname + "_fr", path);
ok &= qApp->installTranslator(&translator);

_action = new QAction(tr("Welcome"), this);
}
}


Supplement:
Must be a scope issue rather than an execution order issue:


class Translatee
{
public:
static bool load(const QString &libname)
{
QString path("/path/to/qm/files/");
QTranslator translator;
bool ok = translator.load(libname + "_fr", path);
ok &= qApp->installTranslator(&translator);
return ok;
}
}


class FooModule : public QObject
{
Q_OBJECT
QAction *_action;
public:
FooModule(QObject *parent)
: QObject(parent)
{
bool ok = Translatee::load(metaObject()->className().toLower());

_action = new QAction(tr("Welcome"), this);
}
}

This doesn't work either.

Why is this? Is there a way to delegate translation loading to before the module's ctor body is executed?

ChrisW67
6th January 2014, 23:03
The first examples fails because your QTranslator instance goes out of scope and is destroyed at the end of the constructor.
The second works because the QTranslator is still in-scope at the time tr() is called for the action's text. It then goes out of scope and is destroyed so subsequent translations will not work.
Supplement: See first and second example regarding scope

You avoid this problem but ensuring the translator stays in scope for at least as long as you need to use it. The examples all allocate it on the stack in main() so that the translator exists for the entire program lifetime. You do not have the luxury of stack allocation in main() but you can heap allocate your QTranslator with an appropriate QObject parent.

zaphod.b
7th January 2014, 12:19
I checked the sources before posting:


bool QCoreApplication::installTranslator(QTranslator *translationFile)
{
if (!translationFile)
return false;

if (!QCoreApplicationPrivate::checkInstance("installTranslator"))
return false;
QCoreApplicationPrivate *d = self->d_func();
d->translators.prepend(translationFile);

#ifndef QT_NO_TRANSLATION_BUILDER
if (translationFile->isEmpty())
return false;
#endif

#ifndef QT_NO_QOBJECT
QEvent ev(QEvent::LanguageChange);
QCoreApplication::sendEvent(self, &ev);
#endif

return true;
}

So QCoreApplication::installTranslator() basically adds the QTranslator to an internal list.

I always was under the impression that it is a copy that is added to a list. Also I assumed (but couldn't verify so far) that the translations are taken from the (list of) installed translators. In this case the original QTranslator instance going out of scope shouldn't matter, should it?

Anything wrong with my train of thought?

Edit:
Oops, a copy of the pointer... Shame on me :o
Sometimes I get lost in a mental deadlock...