美文网首页
Qt多语言基于CMake的自动化转换脚本

Qt多语言基于CMake的自动化转换脚本

作者: 仙人掌__ | 来源:发表于2024-02-22 15:23 被阅读0次

1、背景

Qt的多语言文件是xml格式,且需要包含源文件名,行数等等信息才可以被正确识别(有点奇怪),如下为一段标准的Qt多语言格式

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ts_ZA">
<context>
    <name>HomeView</name>
    <message>
        <location filename="../../../src/UI/Home/HomeView.cpp" line="90"/>
        <source>homepage_create</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>MacWindowHelper</name>
    <message>
        <location filename="../../../native/Mac/Mainwindow_Mac.mm" line="56"/>
        <source>About</source>
        <translation type="unfinished"></translation>
    </message>
</context>
</TS>

上述source字段即为key,translation对应的即为具体的多语言文案。

官方提供了工具将源文件名及行数信息写入xml中,也提供了一个GUI工具填写翻译文案(需要一个语言一个字段去填写),所以当项目中新增多语言,则需要调用工具更新多语言文件,然后再一个个更新对应多语言,非常麻烦。这里希望实现如下目标:编译期自动调用工具生成xml,自动调用脚本将多余文案填入translation字段。

2、Qt多语言实现流程

有两种运行机制。1、将xml多语言编译为一个cpp文件最终直接链接到二进制包中。2、程序运行期间动态加载解析xml。官方推荐第一种方式如下为第一种方式流程:

image.png

3、自动转换脚本实现流程

实现思路为当调用lupdate生成的多语言xml文件(空文案)后,调用填词脚本将多语言文案填入字段中。流程如下:


image.png

1、填词脚本

填词脚本代码为c++,它首先读解析现有项目ABS中(ios格式,也可以是其他格式,需自行实现)多语言文案文件,然后填入多语言文件.ts对应字段中。具体实现代码位于地址的tools/tsconvert目录下

2、多语言文案

上述填词脚本自动转换iOS多语言格式为Qt的xml格式。只需要将iOS多语言放入项目中即可

image.png

3、qrc文件

要实现从多语言文件.qm到多语言文件.cpp的转换,还需要借助qrc文件,它告诉cmake宏如找到qm文件和生成几种多语言。格式如下:

<RCC>
    <qresource prefix="/">
        <file>en.qm</file>
        <file>es.qm</file>
        <file>pt.qm</file>
        <file>ru.qm</file>
    </qresource>
</RCC>

file字段是qm文件与qrc文件的相对路径。

4、cmake配置

还需要cmake配置才能自动完成上述整个流程

  1. 添加填词脚本子任务
add_subdirectory(tools/tsconvert)
  1. 自动调用lupdate、-lrelease、填词脚本
set(languagesDir "${CMAKE_CURRENT_BINARY_DIR}/resources/languages")
file(MAKE_DIRECTORY ${languagesDir})
# 将qrc文件拷贝到指定目录;由于qrc指定了qm文件与其为同一目录,所以这里拷贝一下,不然会找不到
configure_file(resources/languages/language.qrc ${languagesDir} COPYONLY)
set(TS_FILES_DIR ${CMAKE_CURRENT_BINARY_DIR}/resources/languages)
set(TMP_TS_FILES
        ${TS_FILES_DIR}/en.ts.0.ts
        ${TS_FILES_DIR}/es.ts.0.ts
        ${TS_FILES_DIR}/pt.ts.0.ts
        ${TS_FILES_DIR}/ru.ts.0.ts
)
set(TS_FILES
        ${TS_FILES_DIR}/en.ts
        ${TS_FILES_DIR}/es.ts
        ${TS_FILES_DIR}/pt.ts
        ${TS_FILES_DIR}/ru.ts
)
# 该语句实际上通过add_custom_command调用lupdate指令;
qt5_add_lupdate("" ${TMP_TS_FILES} ${PROJECT_SOURCES})
foreach (lan_file tmp_ts_file ts_file IN ZIP_LISTS LAN_FILES TMP_TS_FILES TS_FILES)
    add_custom_command(
            OUTPUT ${ts_file}
            COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tools/tsconvert/tsconvert "${lan_file}" "${tmp_ts_file}" "${ts_file}"
            DEPENDS tsconvert ${lan_file} ${tmp_ts_file}
            VERBATIM
    )
endforeach ()
# 将源文件(ts文件)的编译结果输出到指定目录(默认为可执行文件路径)
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${languagesDir})
# 该语句将会构建出lrease指令,在执行build时调用这些指令
qt5_add_translation(QM_FILES ${TS_FILES})
add_custom_target(qmTranslations DEPENDS ${QM_FILES})
add_executable(CrossPlatform
        ${PROJECT_SOURCES}
        ${ICONS_SOURCES}
        ${CMAKE_CURRENT_BINARY_DIR}/resources/languages/language.qrc
)
add_dependencies(CrossPlatform qmTranslations)

4、使用

1、tr()

所有要实现多语言的字符串需要用QObject::tr()或者tr()(该类需继承于QObject且添加Q_OBJECT关键字),它是实现多语言的前提条件。

createButton->setText(QObject::tr("homepage_create"));
class MyClass:public QObject {
Q_OBJECT
public:
    void func(){
        // 如果所在类承于QObject且添加了Q_OBJECT关键字,可简写
        createButton->setText(tr("homepage_create"));
    }
}

2、多语言文案

直接将iOS格式的多语言文件放在resources/languages下(如果是其它格式也放在这个目录下,不过需要自行实现前面的填词脚本)

2、切换为对应语言

代码如下:

QTranslator translator;
// :/代表相对路径。相对路径默认构成为 前缀(qrc文件中prefix字段)+qm相对于qrc的路径
translator->load(":/es.qm");
qApp->installTranslator(mTranslator);

5、问题

由于lupdate指令是针对源文件的,所以每次源文件发生改变,即使没有产生新的多语言文案代码,最终都会调用填词脚本,它会对整个所有的key-value进行遍历,这样就产生了编译期间不必要的时间消耗。经过测试,自己电脑有一万条多语言文案,花费时间大概100ms,应该在可接受范围内。

改进方案:
增加一个宏定义,只有需要进行多语言翻译的时候在进行转换

相关文章

网友评论

      本文标题:Qt多语言基于CMake的自动化转换脚本

      本文链接:https://www.haomeiwen.com/subject/oqqgadtx.html