Load translations
AbandonedPublic

Authored by broulik on Dec 14 2019, 10:59 AM.

Details

Reviewers
kossebau
aacid
Group Reviewers
Kirigami
Frameworks
Summary

The ECM QM Loader uses Q_COREAPP_STARTUP_FUNCTION which doesn't work for things loaded as plugins like QML modules.
This copies the logic over to the plugin so the translations are loaded when the QML plugin is loaded.
Not really like it, so I'm open to suggestions how to do that better in ECM or I don't know?

BUG: 413900

Test Plan
  • The Search field in Kirigami is translated now
  • The AboutPage in Kirigami is translated now

Diff Detail

Repository
R169 Kirigami
Lint
Lint Skipped
Unit
Unit Tests Skipped
broulik created this revision.Dec 14 2019, 10:59 AM
Restricted Application added a project: Kirigami. · View Herald TranscriptDec 14 2019, 10:59 AM
Restricted Application added a subscriber: plasma-devel. · View Herald Transcript
broulik requested review of this revision.Dec 14 2019, 10:59 AM
broulik added a reviewer: sitter.
broulik edited the summary of this revision. (Show Details)Dec 14 2019, 11:09 AM

Seems a bit meh to have a verbatim copy of the auto generated functions. Perhaps it'd be better to add an option to the ECM generator to export a loader function for use in plugins?
Then we could just call that from the plugin init instead of having to copy it.

Sounds good to me lol

The ECM QM Loader uses Q_COREAPP_STARTUP_FUNCTION which doesn't work for things loaded as plugins like QML modules.

Curious, where it exactly does it fail to work? Q_COREAPP_STARTUP_FUNCTION being nvoked during lib loading after the QApp instance exists still should result in the startup function to be executed from what I remember and just looked at again in the code (https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp.html#286), see the

if (QCoreApplication::instance())
    p();

So, what am I missing? :)

broulik added a comment.EditedDec 15 2019, 3:55 PM

Qt docs say "Adds a global function that will be called from the QCoreApplication constructor. " but when we at runtime somewhere load a QML plugin we're too late with that. Apps don't *link* to Kirigami.

Qt docs say "Adds a global function that will be called from the QCoreApplication constructor. " but when we at runtime somewhere load a QML plugin we're too late with that.

Q_COREAPP_STARTUP_FUNCTION creates code using qAddPreRoutine(), which does directly execute the registered method though when the QApp already exists, as I tried to hint before, and has since Qt 5.6 at least. (see the above link :) ). The API dox is missing to define that, indeed, but thinking about it one would expect it to happen.

Things might fail though if there is static linking involved perhaps with the plugins somehow?

We don't link against Kirigami, so the startup routine stuff doesn't apply? And we're way after the QCoreApp constructor at this point.

We don't link against Kirigami, so the startup routine stuff doesn't apply?

Q_COREAPP_STARTUP_FUNCTION generates a static struct in the compiled code, whose constructor will be invoked on loading the lib which bundles that obect code, and the constructor does the registration call (which then also cares for directly executing the method if already passed QApp construction phase). See below for how exactly.

So at least to what I "know" being loaded in a lib only later at runtime still should result in the call being triggered, as also at that time any static objects will be constructed/init during lib load.

And we're way after the QCoreApp constructor at this point.

Yes, but that is something qAddPreRoutine deals with, by in that case then also executing the method itself:

void qAddPreRoutine(QtStartUpFunction p)
{
    QStartUpFuncList *list = preRList();
    if (!list)
        return;
    if (QCoreApplication::instance())
        p();
    // Due to C++11 parallel dynamic initialization, this can be called
    // from multiple threads.
    QMutexLocker locker(&globalRoutinesMutex);
    list->prepend(p); // in case QCoreApplication is re-created, see qt_call_pre_routines
}

See how qAddPreRoutine code is generated by Q_COREAPP_STARTUP_FUNCTION:

#define Q_COREAPP_STARTUP_FUNCTION(AFUNC) \
    static void AFUNC ## _ctor_function() {  \
        qAddPreRoutine(AFUNC);        \
    }                                 \
    Q_CONSTRUCTOR_FUNCTION(AFUNC ## _ctor_function)

with Q_CONSTRUCTOR_FUNCTION being:

#ifndef Q_CONSTRUCTOR_FUNCTION
# define Q_CONSTRUCTOR_FUNCTION0(AFUNC) \
    namespace { \
    static const struct AFUNC ## _ctor_class_ { \
        inline AFUNC ## _ctor_class_() { AFUNC(); } \
    } AFUNC ## _ctor_instance_; \
    }
# define Q_CONSTRUCTOR_FUNCTION(AFUNC) Q_CONSTRUCTOR_FUNCTION0(AFUNC)
#endif

Well, whatever it is, it doesn't work. My search field isn't translated and I put breakpoints and I only get it load translations for kcoreaddons and kjobwidgets.

Ok, so turns out, it does call it when the plugin is loaded, but the translations are only installed *after* the QML has loaded and processed.

Well, whatever it is, it doesn't work. My search field isn't translated and I put breakpoints and I only get it load translations for kcoreaddons and kjobwidgets.

Okay. Which app did you test with? Does it link kcoreaddons? Would poke then as well a bit, as I happen to have a related rant blog post lying around ;) ).

Okay. Which app did you test with? Does it link kcoreaddons? Would poke then as well a bit, as I happen to have a related rant blog post lying around ;) ).

systemsettings5 exhibits this situation

kossebau added a comment.EditedDec 15 2019, 4:26 PM

Ok, so turns out, it does call it when the plugin is loaded, but the translations are only installed *after* the QML has loaded and processed.

Uh, okay, that seems like things need indeed another approach. Actually, any librarries using the hook and linked to only from qml plugins would then be prone to fail? (Edit: fail WRT having translations in time)

Hm, though now I am confused why calling this from KirigamiPlugin::initializeEngine fixes things for you, the static struct constructor of that startup hook technology in the lib should be invoked before during loading, no?

Time to go playing with the actual code myself.

I guess it builds the QML tree and evaluates the qsTr calls and then finds it needs an item from a plugin and loads the import and only then translates it. Subsequent controls are translated, only the ones on the initial item are not. Perhaps if we shoehorn a QQmlEngine::retranslate() call in the ecm qm loader thing (or rather have a ecm qm loader for qml plugin) it should force re-evaluation of those things. Not pretty either :/

kossebau added a comment.EditedDec 15 2019, 5:02 PM

Hm, though now I am confused why calling this from KirigamiPlugin::initializeEngine fixes things for you, the static struct constructor of that startup hook technology in the lib should be invoked before during loading, no?

Looking at the ECM generated code, that one sees to do the catalog loading in the main thread, and if not in the main thread already using a timer event to trigger the loading there.
While the plugin is loaded in another thread (called "QQmlThread" by what my debug output told me). (Edit: I added debug output to the generated catalog loading code as well as added KirigamiPlugin::initializeEngine with a log call)

INIT CATALOG HOOKUP QThread(0x564b8c8c6fb0, name = "QQmlThread")
INIT ENGINE QThread(0x564b8c3a28d0)
LOADING FROM CATALOG HOOKUP QThread(0x564b8c3a28d0)

Which explains to me why your patch then fixes things.

No idea/proposal about/for a proper solution, but at least my curiousity is satisfied for now for what is broken here :/ (EDIT: well, "fix" as in that it "solves" things, but results in 2x translator instances added now, as the hook still also does it, so not a recommended fix).

mart added a subscriber: mart.Jan 7 2020, 9:37 AM

ping, what's the current status of this?

sitter removed a reviewer: sitter.Mar 19 2020, 12:49 PM
In D25984#589426, @mart wrote:

ping, what's the current status of this?

There's also https://phabricator.kde.org/D27595, which might address the same/a similar issue.

broulik abandoned this revision.May 18 2020, 3:18 PM

Looks like D27595 fixes the issue