QT嵌入翻译在Windows上有效,而不是在Linux上



在SQLiteStudio中,我开始使用CONFIG += lrelease embed_translations将所有翻译自动嵌入到应用程序的资源中。我宣布:

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

对所有模块(在其pro文件中(都执行此操作。模块被编译成共享库(如coreSQLiteStudioguiSQLiteStudio(,然后有一个可执行模块sqlitestudio,它是要运行的应用程序,并动态链接到其他应用程序,因此看起来像:

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

然后在运行时,我将在Qt的资源系统中使用翻译文件(通过使用:/msg/translations/coreSQLiteStudio_pl_PL.qm:/msg/translations/sqlitestudio_pl_PL.qm等调用QTranslator::load()(。

这在Windows下运行良好,但由于某种原因,在Linux下不起作用。问题是,在Linux下,只有来自sqlitestudio模块(即sqlitestudio_pl_PL.qm(的文件在:/msg/translations前缀下可见,而在Windows下,在相同前缀下也可以看到其他模块翻译(即coreSQLiteStudio_pl_PL.qmguiSQLiteStudio_pl_PL.qm(。

我已经调试了TRANSLATIONS += $$files(translations/*.ts),它对所有模块都得到了正确的解决(在Linux下也是如此(。然后我调试了:/msg/translations的运行时内容,并确认在Linux下只有sqlitestudioqm文件可见,而在Windows下所有qm文件(来自所有模块(都可见。

是什么导致了这种奇怪的行为?

(对于更广泛的代码上下文,你可以参考SQLiteStudio的代码库——它是开源的,可以在GitHub上获得(

编辑-进一步分析:

Qt正确生成了一个qrc文件,我可以看到它,它有预期的内容。我还看到rcc将其编译到cpp文件,make将其编译成对象文件,然后我看到对象文件链接到最终的共享库中。我可以在构建目录中看到所有这些中间文件。

问题似乎出在运行时。我已经列出了所有使用功能可见的资源:

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);
}
}
}

然后调用printResources(":/", 0);,它打印了各种资源,但它不包含来自共享库资源的QM文件,而它确实包含来自可执行资源的QM文件。它还拥有显式添加到共享库中另一个资源文件中的所有资源(一些静态资源,而不是自动生成的qm文件(。

为什么Qt在从共享库访问QM自动生成的资源时会出现问题,而且只能在Linux下访问?

我得到了解决方案。

简短回答

QMAKE_RESOURCE_FLAGS += -name coreSQLiteStudio_qm_files添加到所有pro文件中(并在每种情况下将coreSQLiteStudio_qm_files替换为唯一名称(。

如果项目中有其他(显式(资源文件,则需要具有动态但可预测的名称,如:QMAKE_RESOURCE_FLAGS += -name ${QMAKE_TARGET}_${QMAKE_FILE_BASE},以便将其传递给Q_INIT_RESOURCE()宏。

答案很长

自动生成(由qmake生成(的资源文件(其中包含qm文件(由rcc编译为具有默认初始化函数qInitResources_qmake_qmake_qm_files()的cpp文件,然后在所有其他模块(共享库(上重复该函数,并导致在运行时仅使用其中一个模块。解决方案是使初始化函数对每个模块都是唯一的,因此您需要将资源初始化函数的唯一名称传递给rcc。通过使用上面的语句(在简短的回答中(,您将获得初始化函数qInitResources_coreSQLiteStudio_qm_files()

在Windows下,函数名称的冲突似乎无关紧要,但在Linux下却是如此。

最新更新