Qt多語(yǔ)言基于CMake的自動(dòng)化轉(zhuǎn)換腳本

1、背景

Qt的多語(yǔ)言文件是xml格式,且需要包含源文件名,行數(shù)等等信息才可以被正確識(shí)別(有點(diǎn)奇怪),如下為一段標(biāo)準(zhǔn)的Qt多語(yǔ)言格式

<?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對(duì)應(yīng)的即為具體的多語(yǔ)言文案。

官方提供了工具將源文件名及行數(shù)信息寫(xiě)入xml中,也提供了一個(gè)GUI工具填寫(xiě)翻譯文案(需要一個(gè)語(yǔ)言一個(gè)字段去填寫(xiě)),所以當(dāng)項(xiàng)目中新增多語(yǔ)言,則需要調(diào)用工具更新多語(yǔ)言文件,然后再一個(gè)個(gè)更新對(duì)應(yīng)多語(yǔ)言,非常麻煩。這里希望實(shí)現(xiàn)如下目標(biāo):編譯期自動(dòng)調(diào)用工具生成xml,自動(dòng)調(diào)用腳本將多余文案填入translation字段。

2、Qt多語(yǔ)言實(shí)現(xiàn)流程

有兩種運(yùn)行機(jī)制。1、將xml多語(yǔ)言編譯為一個(gè)cpp文件最終直接鏈接到二進(jìn)制包中。2、程序運(yùn)行期間動(dòng)態(tài)加載解析xml。官方推薦第一種方式如下為第一種方式流程:

image.png

3、自動(dòng)轉(zhuǎn)換腳本實(shí)現(xiàn)流程

實(shí)現(xiàn)思路為當(dāng)調(diào)用lupdate生成的多語(yǔ)言xml文件(空文案)后,調(diào)用填詞腳本將多語(yǔ)言文案填入字段中。流程如下:


image.png

1、填詞腳本

填詞腳本代碼為c++,它首先讀解析現(xiàn)有項(xiàng)目ABS中(ios格式,也可以是其他格式,需自行實(shí)現(xiàn))多語(yǔ)言文案文件,然后填入多語(yǔ)言文件.ts對(duì)應(yīng)字段中。具體實(shí)現(xiàn)代碼位于地址的tools/tsconvert目錄下

2、多語(yǔ)言文案

上述填詞腳本自動(dòng)轉(zhuǎn)換iOS多語(yǔ)言格式為Qt的xml格式。只需要將iOS多語(yǔ)言放入項(xiàng)目中即可

image.png

3、qrc文件

要實(shí)現(xiàn)從多語(yǔ)言文件.qm到多語(yǔ)言文件.cpp的轉(zhuǎn)換,還需要借助qrc文件,它告訴cmake宏如找到qm文件和生成幾種多語(yǔ)言。格式如下:

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

file字段是qm文件與qrc文件的相對(duì)路徑。

4、cmake配置

還需要cmake配置才能自動(dòng)完成上述整個(gè)流程

  1. 添加填詞腳本子任務(wù)
add_subdirectory(tools/tsconvert)
  1. 自動(dòng)調(diào)用lupdate、-lrelease、填詞腳本
set(languagesDir "${CMAKE_CURRENT_BINARY_DIR}/resources/languages")
file(MAKE_DIRECTORY ${languagesDir})
# 將qrc文件拷貝到指定目錄;由于qrc指定了qm文件與其為同一目錄,所以這里拷貝一下,不然會(huì)找不到
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
)
# 該語(yǔ)句實(shí)際上通過(guò)add_custom_command調(diào)用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文件)的編譯結(jié)果輸出到指定目錄(默認(rèn)為可執(zhí)行文件路徑)
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${languagesDir})
# 該語(yǔ)句將會(huì)構(gòu)建出lrease指令,在執(zhí)行build時(shí)調(diào)用這些指令
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()

所有要實(shí)現(xiàn)多語(yǔ)言的字符串需要用QObject::tr()或者tr()(該類需繼承于QObject且添加Q_OBJECT關(guān)鍵字),它是實(shí)現(xiàn)多語(yǔ)言的前提條件。

createButton->setText(QObject::tr("homepage_create"));
class MyClass:public QObject {
Q_OBJECT
public:
    void func(){
        // 如果所在類承于QObject且添加了Q_OBJECT關(guān)鍵字,可簡(jiǎn)寫(xiě)
        createButton->setText(tr("homepage_create"));
    }
}

2、多語(yǔ)言文案

直接將iOS格式的多語(yǔ)言文件放在resources/languages下(如果是其它格式也放在這個(gè)目錄下,不過(guò)需要自行實(shí)現(xiàn)前面的填詞腳本)

2、切換為對(duì)應(yīng)語(yǔ)言

代碼如下:

QTranslator translator;
// :/代表相對(duì)路徑。相對(duì)路徑默認(rèn)構(gòu)成為 前綴(qrc文件中prefix字段)+qm相對(duì)于qrc的路徑
translator->load(":/es.qm");
qApp->installTranslator(mTranslator);

5、問(wèn)題

由于lupdate指令是針對(duì)源文件的,所以每次源文件發(fā)生改變,即使沒(méi)有產(chǎn)生新的多語(yǔ)言文案代碼,最終都會(huì)調(diào)用填詞腳本,它會(huì)對(duì)整個(gè)所有的key-value進(jìn)行遍歷,這樣就產(chǎn)生了編譯期間不必要的時(shí)間消耗。經(jīng)過(guò)測(cè)試,自己電腦有一萬(wàn)條多語(yǔ)言文案,花費(fèi)時(shí)間大概100ms,應(yīng)該在可接受范圍內(nèi)。

改進(jìn)方案:
增加一個(gè)宏定義,只有需要進(jìn)行多語(yǔ)言翻譯的時(shí)候在進(jìn)行轉(zhuǎn)換

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容