如果想支持多语言,也就是添加翻译,需要使用qlinguist相关的内容。
在qt中实现的大体流程为:根据源代码生成.ts
文件,根据添加翻译后的.ts
文件生成.qm
文件,在源文件中setupUi
之前使用QTranslator
加载.qm
文件(翻译文件)。
源码中所有希望添加进翻译文件的字符串都需要使用tr()
括起来,.ui
文件中的不需要,qml文件中使用qsTr()
包裹。
由于与涉及到不同的build system以及.qm
文件的加载方式,具体的实现方法非常乱。
梳理花了很大一番功夫。
以下学习过程基于flameshot 和qBittorrent 两个项目。
由于缺包等原因,我本地的环境没法编译qBittorrent工程,仅看源码来学习。
实现方式
翻译文件的加载方式
在翻译文件.qm
的加载方式上,有两个选择:
- 可以选择把文件单独放到一个文件夹(如
/translations
),程序加载时使用相对路径加载(如/translation/appname_zh_CN.qm
)。 - 也可以选择放进资源文件
.qrc
里,使用qrc的路径加载(如:/translation/app_name_zh_CN.qm
)。
前者的好处是翻译文件独立,修改翻译文件时不需要重新编译程序,坏处是翻译文件暴露在外,可能会遇到丢失、乱码等情况。更常见的情况是修改并生成文件后,忘了把新版的文件放到translation
文件夹里。
后者的好处是可以使用qrc资源系统控制,不暴露在外,只要重新生成即可不需要手动放到translation文件夹,坏处是一旦修改文件就需要重新编译程序,而且包含所有翻译语言的翻译文件的话程序体积会略微大一点。
两套构建系统对翻译文件的处理
CMake
在CMake里,如果想加载翻译文件,需要LinguistTools
模块:
|
|
幸运的是LinguistTools
模块不是一个单独的动态库,应该是包含在Qt5Core内的。
生成并加载翻译文件需要使用qt5_add_translation
或者qt5_create_translation
两个function,且以来qrc系统,即要求CMake的AUTORCC
打开。
QMake
QMake需要使用Qt的lrelease
工具生成ts文件,人工填写ts文件内的翻译,再使用lrelease
生成.qm
文件,其实CMake底层也是调用的这个工具。
加载翻译文件需要用INSTALLATIONS变量 += 上所有的.ts
文件。
希望尽可能的自动化
编译过程需要手动操作的话非常恶星,总是希望整个构建过程能自动化就自动化。
需要自动化的点有:
- 自动根据
.ts
文件生成.qm
文件,这个步骤尽量每次都做,以保证翻译最新。至少在手动修改了.ts
文件后下一次编译时能自动生成.qm
。 - 自动加载
.qm
文件,这个既是指上一步中生成的.qm
能自动放在需要它的位置上,同时还包括程序加载翻译文件时选择当前系统语言。当然也可以加一个选择语言的配置,但能够选择性的加载翻译文件同样是必须的。
两个示例项目做了什么
flameshot
flameshot 只支持CMake构建,对翻译文件的整个处理也比较简单。
在
src/CMakeLists.txt
中包含进.ts
:1 2 3 4 5
set(FLAMESHOT_TS_FILES ${CMAKE_SOURCE_DIR}/data/translations/Internationalization_ca.ts ${CMAKE_SOURCE_DIR}/data/translations/Internationalization_cs.ts ... ${CMAKE_SOURCE_DIR}/data/translations/Internationalization_zh_TW.ts)
紧接着生成翻译文件:
1 2 3 4 5
if (GENERATE_TS) qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${FLAMESHOT_TS_FILES}) else () qt5_add_translation(QM_FILES ${FLAMESHOT_TS_FILES}) endif ()
根据
GENERATE_TS
状态的不同分别调用qt5_create_translation
和qt5_add_translation
,GENERATE_TS
本身只是一个手动控制的开关:1
option(GENERATE_TS "Regenerate translation source files" OFF)
最后安装翻译文件到指定位置:
1
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/flameshot/translations)
加载翻译文件的方式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
QTranslator translator, qtTranslator; QStringList trPaths = PathInfo::translationsPaths(); for (const QString& path : trPaths) { bool match = translator.load(QLocale(), QStringLiteral("Internationalization"), QStringLiteral("_"), path); if (match) { break; } } qtTranslator.load( QLocale::system(), "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath)); app.installTranslator(&translator); app.installTranslator(&qtTranslator);
用了两个translator,一个加载Qt自带语句的翻译,一个是加载项目自己加入的需要的翻译。
qBittorrent
qBittorrent 同时支持使用QMake和Cmake构建,对翻译的处理较为复杂。
CMake
在
app/CMakeLists.txt
中包含.ts
文件并生成翻译文件:1 2 3 4 5
# translations include(QbtTranslations) file(GLOB QBT_TS_FILES ../lang/*.ts) qbt_add_translations(qBittorrent QRC_FILE "../lang/lang.qrc" TS_FILES ${QBT_TS_FILES})
qbt_add_translations
是qBittorrent自定义的一个函数,反正非常复杂就对了,杀鸡焉用牛刀,撤。
QMake
在src.pro
中,仅有以下几行代码即可:
|
|
最前面的一个大的if来设定生成翻译文件所用的lrelease
工具,中间lrelease
这个target用来配置生成翻译文件的动作,最后两行定义好TRANSLATIONS
和TS_SOURCES
两个变量。
非常简单明了。
最终实现
选择的实现方法
- 尽量想同时用QMake和CMake支持加载翻译文件,毕竟QMake有时候还挺好用,你Qt6的QMake停止更新关我Qt5的用户什么事。
- 选择将翻译文件放到
.qrc
里,原因嘛,单独放外面太蠢,QMake似乎没法通过在.pro
文件里写自定义命令的方式安装到translation文件夹里,调用起来也麻烦。
预备工作
首次生成翻译文件时,我们是连.ts
都没有的,所有需要先生成.ts
和.qm
:
- 在源码里配置好想加入翻译文件的文本,包括
.ui
文件内英文的控件文字、源码中所有可能显示在界面上的文字用tr()
包起来,qml文件中使用qsTr()
包裹。 - 在
.pro
文件里加上qBittorrent里翻译文件相关的配置 - 打开Qt自带的命令行,在这个命令行里才能用
lrelease
命令(仅限Windows,Linux大概直接find
一下就行)。 - 使用
lupdate app.pro -ts appname_zh_CN.ts
即可生成.ts
。 - 用文本编辑器打开
.ts
,添加翻译,添加后去掉type="unfinished"
。 - 在打开刚出的命令行,用
lrelease appname_zh_CN.ts -qm appname_zh_CN.qm
生成.qm
。 - 新建一个qrc文件(如
translation.qrc
),添加进刚才生成的.qm
,.ts
也可以加进去,不加也行但要记得加进git仓库。
CMake
在有
add_executable
命令的CMakeLists内加入以下代码,必须在这个CMakeLists内添加的原因是翻译文件无法使用target_sources
添加进编译的目标程序内(格式不支持):1 2 3 4 5 6
# Generate translations set(APPNAME_TS_FILES ${CMAKE_SOURCE_DIR}/src/resource/translation/appname_en.ts ${CMAKE_SOURCE_DIR}/src/resource/translation/appname_zh_CN.ts) set_source_files_properties(${APPNAME_TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_SOURCE_DIR}/src/resource/translation") qt5_add_translation(QM_FILES ${APPNAME_TS_FILES})
注意:
- 以上语句需要在
add_subdirctory
添加了qrc文件之前。 set_source_files_properties
设置的输出目录必须是qrc文件内记录的qm文件目录,否则生成时无法更新qrc文件内包含的翻译。
- 以上语句需要在
之后在
add_executable
时加上生成的翻译文件:1
add_executable(appname ${QM_FILES})
别忘了讲qrc文件加进来,并且打开AUTORCC开关:
1 2 3
# 打开AUTORCC需要在顶层的CMakeLists中尽早开启 set(AUTORCC ON) target_sources(appname PRIVATE translation.qrc)
QMake
.pro
文件里加入以下配置:
|
|
完事了,非常简单。
加载翻译文件
在setupUi
之前,一般在main.cpp里:
|
|
- 我只制作了中文和英文两种翻译所以switch只有两条分支。
QTranslator
需要在声明application之后。