在SQLiteStudio中,我开始使用CONFIG += lrelease embed_translations
将所有翻译自动嵌入到应用程序的资源中。我宣布:
CONFIG += lrelease embed_translations
QM_FILES_RESOURCE_PREFIX = /msg/translations
TRANSLATIONS += $$files(translations/*.ts)
对所有模块(在其pro
文件中(都执行此操作。模块被编译成共享库(如coreSQLiteStudio
、guiSQLiteStudio
(,然后有一个可执行模块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.qm
、guiSQLiteStudio_pl_PL.qm
(。
我已经调试了TRANSLATIONS += $$files(translations/*.ts)
,它对所有模块都得到了正确的解决(在Linux下也是如此(。然后我调试了:/msg/translations
的运行时内容,并确认在Linux下只有sqlitestudio
qm文件可见,而在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下却是如此。