Home > Net >  QT - embedding translations works on Windows, not on Linux
QT - embedding translations works on Windows, not on Linux

Time:07-30

In the SQLiteStudio I started using CONFIG = lrelease embed_translations for automatically embedding all translations into the app's resources. I did so by declaring:

CONFIG   = lrelease embed_translations
QM_FILES_RESOURCE_PREFIX = /msg/translations
TRANSLATIONS  = $$files(translations/*.ts)

This is done for all modules (in their pro files). Modules are compiled into shared libraries (such as coreSQLiteStudio, guiSQLiteStudio and then there is a executable module sqlitestudio, which is the application to run and it's dynamically linked to others, so it looks like:

sqlitestudio                    <- executable (contains *.qm files)
  `- guiSQLiteStudio.so                       (contains *.qm files)
       `- coreSQLiteStudio.so                 (contains *.qm files)

Then in runtime I'm using translation files with Qt's resources system (by call to QTranslator::load() with :/msg/translations/coreSQLiteStudio_pl_PL.qm, :/msg/translations/sqlitestudio_pl_PL.qm, etc).

This works well under Windows, but - for some reason - not under Linux. The problem is that under Linux only files from sqlitestudio module (i.e. sqlitestudio_pl_PL.qm) are visible under the :/msg/translations prefix, while under Windows also other module translations (i.e. coreSQLiteStudio_pl_PL.qm, guiSQLiteStudio_pl_PL.qm) are visible under the same prefix.

I've debugged TRANSLATIONS = $$files(translations/*.ts) and it is resolved properly for all modules (under Linux too). Then I have debugged runtime contents of :/msg/translations and confirmed that only sqlitestudio qm files are visible under Linux, while under Windows all qm files (from all modules) are visible.

What could be causing this weird behavior?

(For wider code context you may refer to SQLiteStudio's code base - it's open source and available at GitHub)

EDIT - Further analysis:

A qrc file is generated properly by Qt, I can see it and it has expected contents. I also see the rcc to compile it to the cpp file and make to compile it to the object file, then I see the object file linked into the final shared library. I can see all these intermediate files in the build directory.

It seems that the problem is in runtime. I've listed all resources visible using function:

void printResources(const QString& path, int indent)
{
    QDir d;
    d.setPath(path);
    for (QString& f : d.entryList(QStringList({"*"})))
    {
        qDebug() << QString(" ").repeated(indent) << f;
        if (!f.contains(".")) {
            printResources(path   "/"   f, indent   4);
        }
    }
}

and then calling printResources(":/", 0);, which printed various resources, but it DID NOT contain QM files from the shared library resources, while it does contain QM files from the executable resources. It also has all resources that were explicitly added to another resources file in the shared library (some static resources, not auto generated qm files).

Why does Qt have problems accessing QM auto-generated resources from shared library and only under Linux?

CodePudding user response:

I got the solution.

Short answer

Add QMAKE_RESOURCE_FLAGS = -name coreSQLiteStudio_qm_files to all pro files (and replace the coreSQLiteStudio_qm_files to unique name in each case).

If you have other (explicit) resource files in the project, you will need to have dynamic, but predictible names, like: QMAKE_RESOURCE_FLAGS = -name ${QMAKE_TARGET}_${QMAKE_FILE_BASE}, so you can pass it to the Q_INIT_RESOURCE() macro.

Long answer

The auto-generated (by qmake) resource file with qm files inside is compiled by the rcc into cpp file with a default initialization function qInitResources_qmake_qmake_qm_files(), which then is repeated over all other modules (shared libraries) and causes only one of those to be used in the runtime. Solution is to make initialization functions unique for each module, therefore you need to pass unique name of the resource initialization function to the rcc. By using statement like above (in the short answer) you will get initialization function qInitResources_coreSQLiteStudio_qm_files().

It seems like conflicting name of the function doesn't matter under Windows, but it does under Linux.

  • Related