一文詳解如何實(shí)現(xiàn)QT的多語(yǔ)言切換(靜態(tài)+動(dòng)態(tài))
背景:
1.項(xiàng)目開發(fā)上:多人多模塊同時(shí)開發(fā),需要考慮如何便于管理共同開發(fā)
2.文本有兩類:界面上固定不變的文本(靜態(tài));在程序運(yùn)行時(shí)才能獲得的文本(動(dòng)態(tài))
任務(wù):
實(shí)現(xiàn)軟件的多語(yǔ)言切換功能。
接下來(lái)會(huì)介紹兩個(gè)實(shí)現(xiàn)途徑,分別是QT語(yǔ)言家工具,以及.ts文件的手動(dòng)編寫(推薦第二種)。
一、QT語(yǔ)言家
Qt Linguist(Qt 語(yǔ)言家)是 Qt 開發(fā)環(huán)境中用于國(guó)際化和本地化的工具。它會(huì)提供翻譯支持,將應(yīng)用程序的用戶界面和其他文本元素翻譯成不同的語(yǔ)言,是一種可視化工具。
如果安裝了的話,可以在這里找到:
1、.pro文件增加TRANSLATIONS
TRANSLATIONS += resource/language/lang_zh_CN.ts\ resource/language/lang_en.ts 說(shuō)明: lang_zh_CN.ts為中文部分,lang_en.ts為英文部分, 此處我的這兩個(gè).ts文件是放在resource/language目錄下,需要照自己的具體路徑進(jìn)行更改
2、更新翻譯(lupdate)
之后出現(xiàn)信息:
3、通過(guò)QT語(yǔ)言家打開.ts文件
由于我使用的是MSVC 2017 64-bit,所以我是使用對(duì)應(yīng)的Linguist打開兩個(gè).ts文件:
在這兩項(xiàng)中分別寫入英文文本和中文文本,編輯完成后保存并發(fā)布(lrelease):
發(fā)布(lrelease)的目的是將.ts文件編譯為.qm文件,.qm文件是二進(jìn)制文件,可以看到同目錄下已經(jīng)生成.qm文件:
4、代碼中使用.qm文件進(jìn)行翻譯
將生成的.qm文件加入到資源文件中。
在啟動(dòng)時(shí)根據(jù)不同的系統(tǒng)語(yǔ)言顯示不同的翻譯:
void MainWindow::initLanguage() { QTranslator translator; QLocale::Language lab = QLocale::system().language(); if(QLocale::Chinese == lab) { translator.load(":/language/lang_zh_CN.qm"); hApp->installTranslator(&translator); Q_EMIT hApp->m_sigmanager->translateLanguage(LANGUAGE::CHINESE); }else if(QLocale::English== lab){ translator.load(":/language/lang_en.qm"); hApp->installTranslator(&translator); Q_EMIT hApp->m_sigmanager->translateLanguage(LANGUAGE::ENGLISH); } } 說(shuō)明: 注意.qm文件的路徑要寫對(duì),不然無(wú)法翻譯,如果找不到可以在.pro文件中增加 INCLUDEPATH 這里我自定義了translateLanguage信號(hào)去觸發(fā)語(yǔ)言的切換,各個(gè)模塊負(fù)責(zé)分別連接該信號(hào),編寫槽函數(shù),舉例: 某模塊: connect(hApp->m_sigmanager,&SignalManager::translateLanguage,this,&SampleMainWidget::retranslate); void SampleMainWidget::retranslate() { ui->retranslateUi(this); }
5、需要注意的問(wèn)題
QT語(yǔ)言家不止可以展示.ui文件中我們給控件預(yù)先編輯的文本內(nèi)容,還有代碼中定義的文本內(nèi)容,只是需要在QT語(yǔ)言家展示代碼內(nèi)待翻譯文本,要使用宏 QT_TR_NOOP ,它通常用于標(biāo)記那些在運(yùn)行時(shí)不需要翻譯,但需要在翻譯文件中保留的字符串。
QString test = QT_TR_NOOP("test1") 說(shuō)明: test的值仍然是原文本,而非翻譯后的文本
在需要翻譯時(shí),使用以下方式(在retranslateui后需要重新設(shè)置控件文本):
void SampleMainWidget::retranslate() { ui->retranslateUi(this); QString text = ui->rackBtn->text(); ui->rackBtn->setText(hApp->translate("SampleApply",text.toStdString().c_str())); } 說(shuō)明: hApp->translate中的第一個(gè)參數(shù),其實(shí)對(duì)應(yīng).ts文件中的<name>元素,和作用域的作用類似 如果使用QT語(yǔ)言家,一般是QT_TR_NOOP定義文本所在的類名 第二個(gè)參數(shù),其實(shí)對(duì)應(yīng).ts文件中的<source>元素,這里的類型是char*
二、.ts文件的手動(dòng)編寫
首先需要簡(jiǎn)單了解.ts文件和.qm文件:
.ts文件(翻譯源文件):.ts文件是Qt中的翻譯源文件,XML格式。它包含了源代碼中的所有可翻譯文本,以及它們的上下文信息。
.qm文件(翻譯目標(biāo)文件):.qm文件是Qt中的翻譯目標(biāo)文件,二進(jìn)制格式。.qm文件包含了已經(jīng)翻譯好的文本,以及與之對(duì)應(yīng)的源代碼中的文本。通過(guò)將.ts文件編譯成.qm文件,可以提高程序的執(zhí)行效率,因?yàn)槌绦蛟谶\(yùn)行時(shí)直接加載.qm文件,而無(wú)需解析和處理XML格式的.ts文件。
1、.ts的格式說(shuō)明
打開.ts文件:
如圖中標(biāo)號(hào)所示:
1、文件頭部信息。指定了翻譯文件的版本(2.1),目標(biāo)語(yǔ)言(zh_CN,即中文)等信息。
2、劃分的作用域名字。
3、每個(gè)待翻譯的字符串都有一個(gè) message 元素,其中l(wèi)ocation元素指定了源代碼中字符串的位置;source 元素包含了原始的文本;translation元素用于存儲(chǔ)翻譯后的文本。
其中,location沒(méi)有也可以,只是QT語(yǔ)言家打開.ts文件時(shí)定位不到字符串位置而已,主要還是source 元素和translation元素,source元素相當(dāng)于字符串的id,翻譯家通過(guò)source在lang_zh_CN.ts找中文文本,在lang_en.ts找英文文本。
2、多人管理開發(fā)
創(chuàng)建language.xlsx,language.xlsx中包含多個(gè)模塊sheet,每個(gè)sheet的表頭為 id Chinese English
其中id為文本項(xiàng)唯一標(biāo)識(shí)符,Chinese為中文文本,English為英文文本。
使用python,將excel轉(zhuǎn)換為.ts文件,并編譯為.qm文件:
import openpyxl import subprocess from xml.dom.minidom import Document def read_excel(file_path): # 打開 Excel 文件 wb = openpyxl.load_workbook(file_path) # 讀取所有 sheet 的數(shù)據(jù) all_rows = [] for sheet_name in wb.sheetnames: sheet = wb[sheet_name] all_rows.extend([ tuple(sheet.cell(row=row, column=col).value for col in range(1, sheet.max_column + 1)) for row in range(2, sheet.max_row + 1) ]) return all_rows def create_ts_file(language, rows): # 創(chuàng)建 XML 文檔 doc = Document() ts = doc.createElement('TS') ts.setAttribute('version', '2.1') ts.setAttribute('language', language) doc.appendChild(ts) # 創(chuàng)建 <context> 元素 context = doc.createElement('context') ts.appendChild(context) for row in rows: source, chinese, english = row # 創(chuàng)建 <message> 元素 message = doc.createElement('message') # 創(chuàng)建 <source> 元素 source_element = doc.createElement('source') source_element.appendChild(doc.createTextNode(source)) message.appendChild(source_element) # 創(chuàng)建 <translation> 元素 translation_element = doc.createElement('translation') translation_element.appendChild(doc.createTextNode(chinese if language == 'zh_CN' else english)) message.appendChild(translation_element) context.appendChild(message) # 將 XML 寫入文件,設(shè)置縮進(jìn)和換行 xml_str = doc.toprettyxml(indent=" ", encoding='utf-8').decode('utf-8') ts_file_path = f'lang_{language}.ts' with open(ts_file_path, 'w', encoding='utf-8') as file: file.write(xml_str) # 調(diào)用 lrelease 命令編譯 .ts 文件為 .qm 文件 subprocess.run(['lrelease', ts_file_path]) if __name__ == "__main__": # 讀取 Excel 文件數(shù)據(jù) excel_data = read_excel("language.xlsx") for language in ["zh_CN", "en"]: # 生成每個(gè)語(yǔ)言的 .ts 文件 create_ts_file(language, excel_data)
以下為生成的內(nèi)容格式:
思路:
將工程所有文本都集中在一個(gè)excel中,需要給專業(yè)翻譯人員翻譯時(shí),只需要提供這樣一份excel,在指定位置補(bǔ)充翻譯后文本就可以。
這里是簡(jiǎn)單通過(guò)id的數(shù)值范圍使各模塊獨(dú)立,即每個(gè)sheet的文本容量為1萬(wàn),從左到右:main(0到9999),scheme(10000到19999),sample(20000到29999)…以此類推。
也可以通過(guò)sheet名稱作為作用域名稱,在.ts文件中增加name元素,只要能保證source唯一不重復(fù),這些方式都是可以的。
3、代碼中如何使用
在代碼中的使用(可以不使用ui->retranslateUi(this);了):
在連接語(yǔ)言切換信號(hào)的槽函數(shù)中設(shè)置待翻譯的文本信息,如:
void SampleMainWidget::retranslate() { ui->rackBtn->setText(hApp->translate(0,"0_main_voice")); }
translate參數(shù)中0代表全局范圍,"0_main_voice"即文本id。
總結(jié)
到此這篇關(guān)于如何實(shí)現(xiàn)QT的多語(yǔ)言切換(靜態(tài)+動(dòng)態(tài))的文章就介紹到這了,更多相關(guān)QT多語(yǔ)言切換實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++學(xué)習(xí)筆記std::vector底層原理及擴(kuò)容
這篇文章主要為大家介紹了C++學(xué)習(xí)之std::vector底層原理及擴(kuò)容詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10Cocos2d-x UI開發(fā)之菜單類使用實(shí)例
這篇文章主要介紹了Cocos2d-x UI開發(fā)之菜單類使用實(shí)例,本文的代碼中含有詳細(xì)注釋,需要的朋友可以參考下2014-09-09C語(yǔ)言通過(guò)深度優(yōu)先搜索來(lái)解電梯問(wèn)題和N皇后問(wèn)題的示例
深度優(yōu)先搜索即是對(duì)一個(gè)新發(fā)現(xiàn)的節(jié)點(diǎn)上如果還關(guān)聯(lián)未探測(cè)到的邊,就沿此邊探測(cè)下去,直到發(fā)現(xiàn)從原點(diǎn)可達(dá)的所有點(diǎn)為止,這里我們就來(lái)展示C語(yǔ)言通過(guò)深度優(yōu)先搜索來(lái)解電梯問(wèn)題和N皇后問(wèn)題的示例2016-06-06通過(guò)先序遍歷和中序遍歷后的序列還原二叉樹(實(shí)現(xiàn)方法)
下面小編就為大家?guī)?lái)一篇通過(guò)先序遍歷和中序遍歷后的序列還原二叉樹(實(shí)現(xiàn)方法)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之中綴樹轉(zhuǎn)后綴樹的實(shí)例
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之中綴樹轉(zhuǎn)后綴樹的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-08-08C++深入分析內(nèi)聯(lián)函數(shù)的使用
為了消除函數(shù)調(diào)用的時(shí)空開銷,C++ 提供一種提高效率的方法,即在編譯時(shí)將函數(shù)調(diào)用處用函數(shù)體替換,類似于C語(yǔ)言中的宏展開。這種在函數(shù)調(diào)用處直接嵌入函數(shù)體的函數(shù)稱為內(nèi)聯(lián)函數(shù)(Inline Function),又稱內(nèi)嵌函數(shù)或者內(nèi)置函數(shù)2022-04-04