配置CLion管理Qt項(xiàng)目國際化支持的方法
隨著Qt 6的發(fā)布,cmake也正式宣告接管qmake的工作了。
在之前的一篇博客里我介紹了如何使用cmake管理你的qt項(xiàng)目,不過有一點(diǎn)我沒有講,那就是對國際化(i18n)的處理。
今天我們就來介紹下如何使用cmake+clion配置管理一個(gè)包含了國際化支持的項(xiàng)目。
準(zhǔn)備工作
你需要準(zhǔn)備下面的工具
- Qt 5.13+(我使用的是Qt 5.15.2)
- CLion 2020.3+
- GCC 9.0+ (最好支持c++17,最低要求是支持c++11)
其中GCC一般自己安裝的Qt會(huì)有附帶,否則在Windows上使用vs2019的編譯器也是可以的。
在Linux上如果不想自己下載安裝Qt的話也可以使用系統(tǒng)倉庫打包好的:
# ubuntu sudo apt-get install build-essential libglu1-mesa-dev libpulse-dev libglib2.0-dev sudo apt-get --no-install-recommends install libqt*5-dev qt*5-dev qml-module-qtquick-* qt*5-doc-html # Arch/Manjato sudo pacman -S base-devel sudo pacman -S --needed qt5
選擇CLion的2020.3及以上版本是因?yàn)樗峁┝俗詭У腝t項(xiàng)目模板,省去了我們自己搭框架的麻煩。
當(dāng)然如果你還在使用舊版CLion的話可以參考這篇文章配置Qt項(xiàng)目。
Qt 6在cmake的配置上是類似的,只需要修改幾個(gè)函數(shù)的名稱即可,后面會(huì)提及。
創(chuàng)建項(xiàng)目
前置工作完成之后就可以創(chuàng)建項(xiàng)目了,如下圖所示:

默認(rèn)是c++14標(biāo)準(zhǔn),我個(gè)人更喜歡用c++17,不過今天的例子使用c++14也是可以的。
創(chuàng)建完成后你會(huì)得到如下的CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.17)
project(untitled1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(QT_VERSION 5)
# 設(shè)置需要用到的Qt modules
set(REQUIRED_LIBS Core Gui Widgets)
set(REQUIRED_LIBS_QUALIFIED Qt5::Core Qt5::Gui Qt5::Widgets)
add_executable(${PROJECT_NAME} main.cpp)
# 提示你應(yīng)該指定qt的cmake模塊的路徑,使用系統(tǒng)默認(rèn)配置時(shí)無需關(guān)心
# 嫌這個(gè)警告啰嗦的話完全可以注釋掉或者刪除
if (NOT CMAKE_PREFIX_PATH)
message(WARNING "CMAKE_PREFIX_PATH is not defined, you may need to set it "
"(-DCMAKE_PREFIX_PATH=\"path/to/Qt/lib/cmake\" or -DCMAKE_PREFIX_PATH=/usr/include/{host}/qt{version}/ on Ubuntu)")
endif ()
# 引入并鏈接用到的Qt modules
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBS_QUALIFIED})
CLion就是靠cmake來組織項(xiàng)目的,對于cmake的配置自然是必不可少的。
項(xiàng)目下還有一個(gè)提前寫入了Hello World示例的main.cpp。點(diǎn)擊編譯運(yùn)行你就會(huì)看到程序創(chuàng)建的窗口了。
下面我們就該進(jìn)入正題了。
配置國際化支持
為了能更好地展示國際化,我們需要把例子代碼改成下面這樣:
#include <QApplication>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QPushButton>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QWidget window;
auto btn1 = new QPushButton{QObject::tr("click left button")};
QObject::connect(btn1, &QPushButton::clicked, [w = &window]() {
QMessageBox::information(w,
QObject::tr("clicked left button"),
QObject::tr("you clicked left button"));
});
auto btn2 = new QPushButton{QObject::tr("click right button")};
QObject::connect(btn2, &QPushButton::clicked, [w = &window]() {
QMessageBox::information(w,
QObject::tr("clicked right button"),
QObject::tr("you clicked right button"));
});
auto mainLayout = new QHBoxLayout;
mainLayout->addWidget(btn1);
mainLayout->addWidget(btn2);
window.setLayout(mainLayout);
window.show();
return QApplication::exec();
}
對于國際化的細(xì)節(jié)我們不過多介紹,這里只要知道需要翻譯的文字要用QObject::tr處理即可。
點(diǎn)擊運(yùn)行,你會(huì)看到界面上都是英文,因?yàn)楝F(xiàn)在我們還沒添加國際化支持:

Qt的翻譯文件由ts文件和qm文件組成,ts文件用于人類進(jìn)行翻譯工作,而Qt會(huì)根據(jù)ts文件生成qm文件,這是供程序使用的二進(jìn)制文件,人類無法直接閱讀。
所以在項(xiàng)目中我們只需要關(guān)心ts文件即可,下面我們創(chuàng)建一個(gè)lang子目錄,我們要在其中進(jìn)行英語到漢語和日語的翻譯工作:
mkdir lang
不過我們不用自己創(chuàng)建ts文件,因?yàn)檫@是Qt能自動(dòng)完成的。
下面我們修改一下cmake,讓他能支持國際化:
cmake_minimum_required(VERSION 3.17)
project(untitled1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(QT_VERSION 5)
set(REQUIRED_LIBS Core Gui Widgets)
set(REQUIRED_LIBS_QUALIFIED Qt5::Core Qt5::Gui Qt5::Widgets)
set(TS_FILES
${CMAKE_SOURCE_DIR}/lang/zh_CN.ts
${CMAKE_SOURCE_DIR}/lang/ja_JP.ts)
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} LinguistTools REQUIRED)
qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES})
add_executable(${PROJECT_NAME} main.cpp ${TS_FILES})
if (NOT CMAKE_PREFIX_PATH)
message(WARNING "CMAKE_PREFIX_PATH is not defined, you may need to set it "
"(-DCMAKE_PREFIX_PATH=\"path/to/Qt/lib/cmake\" or -DCMAKE_PREFIX_PATH=/usr/include/{host}/qt{version}/ on Ubuntu)")
endif ()
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBS_QUALIFIED})
哇,配置變得更長更嚇人了,其實(shí)核心內(nèi)容一共只有這幾行:
set(TS_FILES
${CMAKE_SOURCE_DIR}/lang/zh_CN.ts
${CMAKE_SOURCE_DIR}/lang/ja_JP.ts)
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} LinguistTools REQUIRED)
qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES})
add_executable(${PROJECT_NAME} main.cpp ${TS_FILES} ${QM_FILES})
第一行很好理解,把我們的需要的ts文件的名字先設(shè)置到變量里。
接著我們引入Qt5::LinguistTools,這不是c++庫,只是一個(gè)幫助生成ts文件和qm文件的cmake模塊,所以不能鏈接到程序里。
最后一行也很簡單,把ts文件加入編譯程序的依賴項(xiàng)目里,一旦發(fā)生改變就重新構(gòu)建我們的程序。
關(guān)鍵在于qt5_create_translation這里,這個(gè)函數(shù)會(huì)幫我們創(chuàng)建ts文件,如果ts文件已經(jīng)存在就會(huì)更新ts文件把新添加的翻譯追加進(jìn)去;
到這步還沒結(jié)束,在更新完ts文件后它會(huì)檢查ts文件中是否有有效的翻譯信息,如果有就在cmake的編譯目錄下生成和ts文件同名的qm文件。
中間的${CMAKE_CURRENT_SOURCE_DIR}就是指定從哪個(gè)目錄下的源文件里獲得需要翻譯的文本的。
注意,如果qm文件最終沒被用到的話,那么實(shí)際上不會(huì)被生成。為了能生成qm文件所以我們把它加入了依賴,還有更好的辦法,后面介紹。
在Qt 6中我們只需要把函數(shù)名改成qt_create_translation就行了。
如果你想自己創(chuàng)建和更新ts文件,只需要把函數(shù)換成qt5_add_translation,它會(huì)自動(dòng)根據(jù)ts文件生成qm文件,不過要是沒有ts文件存在他就會(huì)報(bào)錯(cuò)。在Qt 6中它的名字會(huì)變?yōu)?code>qt_add_translation。
上述的工作會(huì)在make的時(shí)候進(jìn)行,比如這樣:

添加翻譯
添加翻譯沒什么好講的,你可以直接編輯ts文件,因?yàn)樗莤ml格式的,編輯起來還是很容易的。
不過有時(shí)候翻譯需要參考文本和代碼的上下文,這時(shí)候就需要用到Qt Linguist了:

具體的使用細(xì)節(jié)不再贅述,你可以參考園內(nèi)和網(wǎng)上的其他優(yōu)質(zhì)文章。
編譯運(yùn)行后你就會(huì)在構(gòu)建目錄看到兩個(gè)qm文件,這時(shí)候我們的程序還沒有完成國際化支持,在代碼中我們需要使用這些qm文件:
#include <QLocale>
#include <QTranslator>
int main()
{
QApplication a(argc, argv);
QTranslator trans;
if (trans.load("./" + QLocale().name() + ".qm")) {
QCoreApplication::installTranslator(&trans);
}
...
return a.exec();
}
我們用QTranslator加載本地的qm文件,QLocale的name方法正好可以返回諸如“ja_JP”的名字。
我的系統(tǒng)默認(rèn)設(shè)置是日語,因此運(yùn)行程序會(huì)看到這樣的界面:

如果你的環(huán)境是中文的,那么顯示的界面也是中文的,這就是Qt的i18n國際化支持。
將多語言資源綁定進(jìn)程序
到上一節(jié)結(jié)束我們其實(shí)就把i18n講完了,你完全可以打包程序的時(shí)候把qm文件和程序放在一起,安裝的時(shí)候也放在同一目錄。
但這種方案還是有些缺點(diǎn)的:
- 如果支持的語言比較多,那么就會(huì)有大量的小文件需要處理,難免會(huì)出錯(cuò);
- 需要把qm這種無關(guān)的文件放進(jìn)編譯依賴?yán)?/li>
對于有代碼潔癖的我來說第二點(diǎn)尤其忍不了,但是如果不用這些qm文件的話最終是不會(huì)生成他們的,怎么辦呢?
其實(shí)還有辦法,我們可以把這些qm文件都集成到qrc里。
首先在目錄下創(chuàng)建一個(gè)translations.qrc文件:
<RCC>
<qresource>
<file>zh_CN.qm</file>
<file>ja_JP.qm</file>
</qresource>
</RCC>
這里不用管資源文件的路徑,因?yàn)槲覀冞€要對CMakeLists.txt做些修改處理這些問題:
set(CMAKE_AUTORCC ON) # 一定得開啟rcc
# 注意這行
configure_file(translations.qrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
...
add_executable(${PROJECT_NAME} main.cpp ${TS_FILES} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
需要注意的是configure_file那行,我們把qrc文件原樣復(fù)制到了編譯目錄里,因?yàn)閝m文件也是在那里生成的。
現(xiàn)在qrc會(huì)被自動(dòng)處理,然后我們的qm文件作為其依賴項(xiàng)也能被自動(dòng)生成了。
再次編譯項(xiàng)目,這次我們就能發(fā)現(xiàn)qm被生成了:

因?yàn)槭褂昧薗t的rcc把資源嵌入了程序,所以cpp代碼也得做一些調(diào)整:
QTranslator trans;
-if (trans.load("./" + QLocale().name() + ".qm")) {
+if (trans.load(":/" + QLocale().name() + ".qm")) {
QCoreApplication::installTranslator(&trans);
}
注意.變成了:,這代表我們指定的路徑是嵌入資源的。
這樣國際化支持就徹底完成了,通過修改Linux的LANG環(huán)境變量我們可以自由設(shè)置程序的語言,效果如下:


總結(jié)
現(xiàn)在我把完整的CMakeLists.txt貼上來作為參考,對于你自己的項(xiàng)目當(dāng)然是要做調(diào)整的:
cmake_minimum_required(VERSION 3.17)
project(untitled1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(QT_VERSION 5)
set(REQUIRED_LIBS Core Gui Widgets)
set(REQUIRED_LIBS_QUALIFIED Qt5::Core Qt5::Gui Qt5::Widgets)
set(TS_FILES
${CMAKE_SOURCE_DIR}/lang/zh_CN.ts
${CMAKE_SOURCE_DIR}/lang/ja_JP.ts)
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} LinguistTools REQUIRED)
configure_file(translations.qrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES})
add_executable(${PROJECT_NAME} main.cpp ${TS_FILES} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
message(${QM_FILES})
target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBS_QUALIFIED})
更進(jìn)一步
現(xiàn)在你已經(jīng)能用clion管理自己的多語言支持項(xiàng)目了,然而目前的方案仍稱不上完美。
因?yàn)閷s文件的更新和qm文件的創(chuàng)建必須在編譯期間進(jìn)行,無法單獨(dú)進(jìn)行上述的工作。根據(jù)文檔的說法來看,對于多語言的支持通常是在軟件本身功能基本完善之后進(jìn)行的,ts文件和qm文件不會(huì)經(jīng)常進(jìn)行變更,所以在編譯期間一并處理是可以接受的。
不過事實(shí)上軟件的功能往往會(huì)增量更新,翻譯也會(huì)進(jìn)行訂正和改進(jìn),為此需要重新編譯整個(gè)項(xiàng)目作為代價(jià)顯然太過高昂。
那么能不能把i18n的處理獨(dú)立出來呢,答案是可以的,不過我們不能再借助LinguistTools了。因?yàn)長inguistTools在內(nèi)部使用的是add_custom_command,無法獨(dú)立構(gòu)成一個(gè)編譯目標(biāo),所以得另尋出路。
下面來看看修改后的代碼:
# 去掉了LinguistTools
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
# 創(chuàng)建生成ts文件和qm文件的目標(biāo)
# ALL指定加入make all
add_custom_target(update_all_ts_files ALL)
add_custom_target(create_all_qm_files ALL)
# 找到$PATH里的lupdate和lrelease,你也可以自己設(shè)置他們的安裝路徑
find_file(LUPDATE_PATH lupdate)
find_file(LRELEASE_PATH lrelease)
# 對于每一個(gè)ts文件,都生成一個(gè)update_ts_file_<NAME>和create_qm_file_<NAME>目標(biāo)
foreach(TS_FILE ${TS_FILES})
# 把zh_CN.ts中的zh_CN提取出來
get_filename_component(I18N_NAME ${TS_FILE} NAME_WE)
set(TS_TARGET_NAME "update_ts_file_${I18N_NAME}")
add_custom_target(${TS_TARGET_NAME}
COMMAND ${LUPDATE_PATH} ${CMAKE_CURRENT_SOURCE_DIR} -ts ${TS_FILE}
VERBATIM)
# 將update_ts_file_<NAME>添加為update_all_ts_files的依賴,下同
add_dependencies(update_all_ts_files ${TS_TARGET_NAME})
set(QM_TARGET_NAME "create_qm_file_${I18N_NAME}")
set(QM_FILE "${CMAKE_CURRENT_BINARY_DIR}/${I18N_NAME}.qm")
add_custom_target(${QM_TARGET_NAME}
COMMAND ${LRELEASE_PATH} ${TS_FILE} -qm ${QM_FILE}
VERBATIM)
# 因?yàn)榈孟扔衪s文件才能生成qm文件,所以把構(gòu)建ts文件的目標(biāo)作為自己的依賴
add_dependencies(${QM_TARGET_NAME} ${TS_TARGET_NAME})
add_dependencies(create_all_qm_files ${QM_TARGET_NAME})
endforeach()
configure_file(translations.qrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
add_executable(${PROJECT_NAME} main.cpp ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
# 因?yàn)閝rc依賴qm文件,所以需要先讓qm文件創(chuàng)建完成
add_dependencies(${PROJECT_NAME} create_all_qm_files)
看上去很復(fù)雜,然而實(shí)際上上面的代碼只做了一件事,生成了如下的依賴鏈:

現(xiàn)在更新ts文件和生成qm文件都可以作為單獨(dú)的步驟而存在了,這是qt5_create_translation和qt5_add_translation做不到的:

很好,我們可以任意更改翻譯而不用重新編譯整個(gè)項(xiàng)目了,自己動(dòng)手豐衣足食。
如果想要看更具體的項(xiàng)目是如何配置i18n的,我這也有一個(gè)例子,如果不嫌棄覺得有幫助的話可以star一下。
到此這篇關(guān)于配置CLion管理Qt項(xiàng)目國際化支持的方法的文章就介紹到這了,更多相關(guān)CLion Qt國際化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- clion最新激活碼+漢化的步驟詳解(親測可用激活到2089)
- Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置教程詳解
- Clion、IEDA、pycharm的一些簡單設(shè)置步驟(設(shè)置中文菜單、輸出中文、字體大小、背景顏色主題)
- CLion安裝、漢化、配置圖文詳解
- JetBrains(IEDA、CLion、Pycharm) 學(xué)生獲得免費(fèi)使用資格
- 如何使用clion中配置ROS工程
- Clion配置C語言環(huán)境的步驟詳解
- Clion下載安裝使用的詳細(xì)教程(Win+MinGW)
- Clion ROS開發(fā)環(huán)境設(shè)置技巧
相關(guān)文章
Matlab實(shí)現(xiàn)繪制雷達(dá)圖(蜘蛛圖)
這篇文章主要為大家詳細(xì)介紹了如何利用Matlab實(shí)現(xiàn)雷達(dá)圖(蜘蛛圖)的繪制,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下2022-09-09
C語言動(dòng)態(tài)內(nèi)存規(guī)劃詳解
這篇文章主要介紹了C語言動(dòng)態(tài)內(nèi)存的規(guī)劃,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-10-10
C++解決業(yè)務(wù)辦理時(shí)間問題示例解析
這篇文章主要為大家介紹了C++解決業(yè)務(wù)辦理時(shí)間問題示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12

