摘要:執(zhí)行完畢,目錄下會(huì)多出一個(gè)文件,這個(gè)文件就是最終需要放在應(yīng)用程序中分發(fā)給用戶的。問題使用上面的流程就完成了一次基本的程序國際化的流程。
Qt 是一個(gè)很方便的 C++ 應(yīng)用開發(fā)框架(或許現(xiàn)在要加上 Qt Quick 開發(fā)框架?),不僅僅是程序編寫方便面,它提供了很多方便的類庫,而且它也提供了很方便的國際化方案(也就是翻譯成各國語言的方案)。
基本流程 編寫代碼階段我們先來說說在 Qt 中實(shí)現(xiàn)多國語言翻譯需要使用的基本流程。首先我們需要在編寫代碼的時(shí)候就要使用 Qt 提供的翻譯相關(guān)的函數(shù)來"包裹"住所有的需要翻譯的字符串。
你說哪些才是需要翻譯的字符串呢?就是任何會(huì)在用戶界面上顯示的字符串,如果不會(huì)顯示自然就不需要翻譯了。
如果你使用的是 C++ 代碼,那么翻譯用的函數(shù)就是QObject::tr函數(shù)。大多數(shù)時(shí)候,我們看到用到這個(gè)函數(shù)的時(shí)候可能都只是一個(gè)tr,因?yàn)槎际窃谝粋€(gè)繼承自 QObject 的類中,所以可以直接調(diào)用父類的成員函數(shù)了。如果是在自由函數(shù)中想使用的話就要把完整的函數(shù)名QObject::tr寫全了。
如果你寫的是 Qt Quick 的程序,這個(gè)函數(shù)就變成了 qsTr 或者是 qsTranslate 、qsTranslateNoOp ...
代碼寫完之后,需要在工程文件 (.pro 文件) 中添加需要翻譯的源代碼文件。
SOURCES += main.cpp mainwindow.cpp TRANSLATIONS = English.ts Japanese.ts使用 lupdate 檢索源代碼生成翻譯源文件
在工程目錄下運(yùn)行以下命令
lupdate project.pro
執(zhí)行完后,目錄下會(huì)出現(xiàn) English.ts 和 Japanese.ts 兩個(gè)文件,這兩個(gè)文件就是由上文中工程文件中制定的文件名。
使用 linguist 進(jìn)行翻譯然后就可以使用 Qt 提供的 lingust 工具打開上文生成的 .ts 文件,將對(duì)應(yīng)的詞條翻譯成目標(biāo)語言就好了。
使用 lrelease 生成最終程序使用的翻譯文件當(dāng) linguist 翻譯完所有的詞條之后,就需要生成最終給應(yīng)用程序使用的二進(jìn)制翻譯文件了。
使用如下命令即可生成。
lrelease English.ts
執(zhí)行完畢,目錄下會(huì)多出一個(gè) English.qm 文件,這個(gè)文件就是最終需要放在應(yīng)用程序中分發(fā)給用戶的。
問題使用上面的流程就完成了一次基本的程序國際化的流程。一般來說程序的翻譯工作和編碼工作是由不同人來完成的,可能實(shí)際完成翻譯的人不熟悉或者不愿去熟悉使用 linguist 的使用方法,他們提供給程序員的詞條翻譯可能就是一個(gè) Excel 文件,這個(gè) Excel 文件通常一列是待翻譯的詞條,另一列是相應(yīng)的譯文。
解決方法于是我們可能需要一個(gè)將 Qt 的翻譯文件與 Excel 文件互相轉(zhuǎn)換的小工具,這樣我們可以把 Qt 翻譯文件轉(zhuǎn)換成 Excel 文件交給翻譯人員,然后將翻譯人員翻譯好的 Excel 文件再轉(zhuǎn)換為 Qt 的翻譯文件。
要做文件格式轉(zhuǎn)換,那么我們首先得了解一下兩種文件格式有什么特點(diǎn)。
Qt TS 文件格式分析Qt 的 TS 翻譯文件其實(shí)就是一個(gè) XML 文件。我們先來看一個(gè)翻譯文件的例子。
QPushButton
這是一個(gè)還未翻譯的文件,詞條原文是"Hello world!"。在 ts 文件中,每個(gè)需要翻譯的詞條都是一個(gè) message,message 包含需要翻譯的原文和已翻譯的譯文。
翻譯完成后需要去除 translation 的 type="unfinished" 屬性。
Excel 文件格式分析Excel 的文件格式是 Microsoft ? 的私有格式,Excel 2007 之前的格式是二進(jìn)制格式, Excel 2007 之后的是 OOXML 格式。
在這里我們不用太細(xì)的追究它的內(nèi)部細(xì)節(jié),因?yàn)樗膬?nèi)部細(xì)節(jié)非常復(fù)雜,不像 ts 文件就是一個(gè)簡單的文本文件。現(xiàn)在有許多的可以用來讀寫 Excel 文件的庫,我們只需調(diào)用這些庫的讀寫函數(shù)就能完成我們所需的功能了。
在本文中,我將使用 C# 語言以及 NPOI 庫來讀寫 Excel 文件。
private void convertQtFile2ExcelFile(string qtFileName, string excelFileName) { XmlDocument xmlDoc = new XmlDocument(); XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreComments = true; settings.DtdProcessing = DtdProcessing.Ignore; IWorkbook workbook = new XSSFWorkbook(); ISheet sheet = workbook.CreateSheet("worksheet"); int rowCnt = 0; IRow headRow = sheet.CreateRow(rowCnt); rowCnt++; ICell chCell = headRow.CreateCell(0); chCell.SetCellValue("源語言"); ICell enCell = headRow.CreateCell(1); enCell.SetCellValue("目標(biāo)語言"); XmlReader reader = XmlReader.Create(qtFileName, settings); xmlDoc.Load(reader); XmlNode rootNode = xmlDoc.SelectSingleNode("TS"); XmlNodeList xnl = rootNode.ChildNodes; foreach (XmlNode node in xnl) { XmlNodeList nodeList = node.ChildNodes; string src = ""; string dst = ""; foreach (XmlNode n in nodeList) { foreach (XmlNode cn in n.ChildNodes) { if (cn.Name == "source") { src = cn.InnerText; } if (cn.Name == "translation") { dst = cn.InnerText; IRow row = sheet.CreateRow(rowCnt); rowCnt++; ICell firstCell = row.CreateCell(0); firstCell.SetCellValue(src); ICell secondCell = row.CreateCell(1); secondCell.SetCellValue(dst); //Console.WriteLine ("Src = " + src + " dst = " + dst); } } } } reader.Close(); using (FileStream fs = File.Create(excelFileName)) { workbook.Write(fs); } }Excel 轉(zhuǎn) TS 文件
private bool convertExcelFile2QtFile(string excelFileName, string qtFileName) { try { using (var fs = File.OpenRead(excelFileName)) { var workBook = new XSSFWorkbook(fs); var sheet = workBook.GetSheetAt(0); var translateMap = new Dictionary自動(dòng)翻譯詞條(); for (int i = 1; i < sheet.LastRowNum; i++) { IRow row = sheet.GetRow(i); if (row == null) { continue; } var srcCell = row.GetCell(0); var dstCell = row.GetCell(1); if (srcCell == null) { continue; } if (dstCell == null) { continue; } string src = srcCell.ToString(); string translated = dstCell.ToString(); if (translateMap.ContainsKey(src) == false) { translateMap.Add(src, translated); } } var document = new XmlDocument(); document.Load(qtFileName); XmlNodeList xnl = document.SelectNodes("/TS/context"); if (xnl != null) { foreach (XmlNode ctxNode in xnl) { var msgList = ctxNode.SelectNodes("message"); foreach (XmlNode msg in msgList) { string src = ""; foreach (XmlNode cn in msg.ChildNodes) { if (cn.Name == "source") { src = cn.InnerText; } else if (cn.Name == "translation") { if (translateMap.ContainsKey(src)) { cn.InnerText = translateMap[src]; var attrs = cn.Attributes; attrs.Remove(attrs["type"]); } } } } } } document.Save(qtFileName); } return true; } catch (Exception e) { MessageBox.Show("Exception:" + e.Message); return false; } }
其實(shí)了解了 TS 文件的結(jié)構(gòu)之后,我們還能做一件事,那就是直接調(diào)用網(wǎng)上的翻譯接口,自動(dòng)將所有的詞條翻譯成對(duì)應(yīng)的語言,下面就是一個(gè)簡單的例子。
import xml.etree.ElementTree as ET import os import httplib import md5 import urllib import random import json import threading import requests from PyQt4.QtCore import * from PyQt4.QtGui import * import sys reload(sys) sys.setdefaultencoding("utf-8") ## 下面填寫你自己的百度翻譯 API 的 appid 和 secretKey appid = "" secretKey = "" myurl = "/api/trans/vip/translate" def translate(string, targetLanguage): if string is None: return "" salt = random.randint(32768, 65536) sign = appid + string + str(salt) + secretKey m1 = md5.new() m1.update(sign) sign = m1.hexdigest() encoded_str = urllib.quote(str(string)) localurl = myurl + "?appid=" + appid + "&q=" + encoded_str + "&from=auto&to=" + targetLanguage + "&salt=" + str(salt) + "&sign=" + sign try: r = requests.get("http://api.fanyi.baidu.com/" + localurl) if r.status_code == 200: response = r.text objResponse = json.loads(response) return objResponse["trans_result"][0]["dst"] except Exception, e: print e return string class MainWidget(QWidget): def __init__(self, parent=None): super(QWidget, self).__init__(parent) self.setWindowTitle(u"UI Auto Translator") self.labelTargetLanguage = QLabel(u"目標(biāo)語言:") self.comboTargetLanguage = QComboBox() self.comboTargetLanguage.addItem(u"中文", u"zh") self.comboTargetLanguage.addItem(u"英語", u"en") self.comboTargetLanguage.addItem(u"粵語", u"yue") self.comboTargetLanguage.addItem(u"文言文", u"wyw") self.comboTargetLanguage.addItem(u"日語", u"jp") self.comboTargetLanguage.addItem(u"韓語", u"kor") self.comboTargetLanguage.addItem(u"法語", u"fra") self.comboTargetLanguage.addItem(u"西班牙語", u"spa") self.comboTargetLanguage.addItem(u"泰語", u"th") self.comboTargetLanguage.addItem(u"阿拉伯語", u"ara") self.comboTargetLanguage.addItem(u"俄語", u"ru") self.comboTargetLanguage.addItem(u"葡萄牙語", u"pt") self.comboTargetLanguage.addItem(u"德語", u"de") self.comboTargetLanguage.addItem(u"意大利語", u"it") self.comboTargetLanguage.addItem(u"希臘語", u"el") self.comboTargetLanguage.addItem(u"荷蘭語", u"nl") self.comboTargetLanguage.addItem(u"波蘭語", u"pl") self.comboTargetLanguage.addItem(u"保加利亞語", u"bul") self.comboTargetLanguage.addItem(u"愛沙尼亞語", u"est") self.comboTargetLanguage.addItem(u"丹麥語", u"dan") self.comboTargetLanguage.addItem(u"芬蘭語", u"fin") self.comboTargetLanguage.addItem(u"捷克語", u"cs") self.comboTargetLanguage.addItem(u"羅馬尼亞語", u"rom") self.comboTargetLanguage.addItem(u"斯洛文尼亞語", u"slo") self.comboTargetLanguage.addItem(u"瑞典語", u"swe") self.comboTargetLanguage.addItem(u"匈牙利語", u"hu") self.comboTargetLanguage.addItem(u"繁體中文", u"cht") self.comboTargetLanguage.addItem(u"越南語", u"vie") self.labelSrcFile = QLabel(u"源文件") self.inputSrcFile = QLineEdit() self.inputSrcBtn = QPushButton(u"打開文件") self.connect(self.inputSrcBtn, SIGNAL( "clicked()"), self.onInputSrcBtnClicked) self.labelTargetFile = QLabel(u"保存文件") self.inputTargetFile = QLineEdit() self.inputTargetBtn = QPushButton(u"選擇文件名") self.connect(self.inputTargetBtn, SIGNAL( "clicked()"), self.onInputTargetBtnClicked) self.cvtBtn = QPushButton(u"開始翻譯") self.connect(self.cvtBtn, SIGNAL("clicked()"), self.onCvtBtnClicked) self.gridLayout = QGridLayout() self.gridLayout.addWidget(self.labelTargetLanguage, 0, 0) self.gridLayout.addWidget(self.comboTargetLanguage, 0, 1) self.gridLayout.addWidget(self.labelSrcFile, 1, 0) self.gridLayout.addWidget(self.inputSrcFile, 1, 1) self.gridLayout.addWidget(self.inputSrcBtn, 1, 2) self.gridLayout.addWidget(self.labelTargetFile, 2, 0) self.gridLayout.addWidget(self.inputTargetFile, 2, 1) self.gridLayout.addWidget(self.inputTargetBtn, 2, 2) self.vLayout = QVBoxLayout() self.vLayout.addLayout(self.gridLayout) self.vLayout.addWidget(self.cvtBtn) self.setLayout(self.vLayout) @pyqtSlot() def onInputSrcBtnClicked(self): fileName = QFileDialog.getOpenFileName( self, u"打開要翻譯的文件", u".", u"*.ts") if fileName.isEmpty(): QMessageBox.warning(self, u"警告", u"未選擇要翻譯的文件", QMessageBox.Ok) return self.inputSrcFile.setText(fileName) @pyqtSlot() def onInputTargetBtnClicked(self): fileName = QFileDialog.getSaveFileName( self, u"選擇另存為的文件名", u".", u"*.ts") if fileName.isEmpty(): QMessageBox.warning(self, u"警告", u"未選擇要保存為的文明名", QMessageBox.Ok) return self.inputTargetFile.setText(fileName) def process_file(self, src, dst, lang): self.cvtBtn.setText(u"正在翻譯中...") tree = ET.parse(src) root = tree.getroot() source = "" for ctx in root: for msg in ctx: if msg.tag == "message": for tag in msg: if tag.tag == "source": source = tag.text if tag.tag == "translation": tag.text = translate(source, lang) print("source = {0}, translate = {1}".format(source, tag.text)) tag.set("type", "") tree.write(dst) self.cvtBtn.setText(u"開始翻譯") @pyqtSlot() def onCvtBtnClicked(self): targetLang = self.comboTargetLanguage.itemData( self.comboTargetLanguage.currentIndex()).toString() srcFileName = self.inputSrcFile.text() if srcFileName.isEmpty(): QMessageBox.warning(self, u"警告", u"未選擇要翻譯的文件", QMessageBox.Ok) return targetFileName = self.inputTargetFile.text() if targetFileName.isEmpty(): QMessageBox.warning(self, u"警告", u"未選擇要保存為的文明名", QMessageBox.Ok) return t = threading.Thread(target=self.process_file, args=(srcFileName, targetFileName, str(targetLang))) t.setDaemon(True) t.start() if __name__ == "__main__": app = QApplication(sys.argv) widget = MainWidget() widget.show() app.exec_()
https://huzhenyu.me/qt/2018/0...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/41581.html
摘要:友情提示先關(guān)注收藏,再查看,萬字保姆級(jí)語言從入門到精通教程。及大牛出天地開始有隨之乃有萬種語年英國劍橋大學(xué)推出了語言。 友情提示:先關(guān)注收藏,再查看,13 萬字保...
摘要:可暫停顯示收發(fā)數(shù)據(jù)。定時(shí)器自動(dòng)發(fā)送。同時(shí)支持嵌入式樹莓派等。三效果圖四開源主頁以上作品完整源碼下載都在開源主頁,會(huì)持續(xù)不斷更新作品數(shù)量和質(zhì)量,歡迎各位關(guān)注。本開源項(xiàng)目已經(jīng)成功升級(jí)到版本,分門別類,圖文并茂,保你爽到爆。 ...
摘要:作者逆向驛站微信公眾號(hào)逆向驛站知乎逆向驛站一款開發(fā)的國外軟件,大概率是沒有做中文支持的,所以你漢化中,不論怎么設(shè)置編碼都一定是亂碼。 作者:逆向驛站微信公眾號(hào):逆向驛站知乎:逆向驛站showImg(https://segmentfault.com/img/bVbnE98?w=1100&h=731); 一款QT開發(fā)的國外軟件,大概率是沒有做中文支持的,所以你漢化中,不論怎么設(shè)置編碼都一定...
閱讀 2875·2021-11-11 10:58
閱讀 1931·2021-10-11 10:59
閱讀 3499·2019-08-29 16:23
閱讀 2347·2019-08-29 11:11
閱讀 2793·2019-08-28 17:59
閱讀 3845·2019-08-27 10:56
閱讀 2087·2019-08-23 18:37
閱讀 3121·2019-08-23 16:53