成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

一種國(guó)際化Qt應(yīng)用程序的方法

劉福 / 1380人閱讀

摘要:執(zhí)行完畢,目錄下會(huì)多出一個(gè)文件,這個(gè)文件就是最終需要放在應(yīng)用程序中分發(fā)給用戶(hù)的。問(wèn)題使用上面的流程就完成了一次基本的程序國(guó)際化的流程。

Qt 是一個(gè)很方便的 C++ 應(yīng)用開(kāi)發(fā)框架(或許現(xiàn)在要加上 Qt Quick 開(kāi)發(fā)框架?),不僅僅是程序編寫(xiě)方便面,它提供了很多方便的類(lèi)庫(kù),而且它也提供了很方便的國(guó)際化方案(也就是翻譯成各國(guó)語(yǔ)言的方案)。

基本流程 編寫(xiě)代碼階段

我們先來(lái)說(shuō)說(shuō)在 Qt 中實(shí)現(xiàn)多國(guó)語(yǔ)言翻譯需要使用的基本流程。首先我們需要在編寫(xiě)代碼的時(shí)候就要使用 Qt 提供的翻譯相關(guān)的函數(shù)來(lái)"包裹"住所有的需要翻譯的字符串。

你說(shuō)哪些才是需要翻譯的字符串呢?就是任何會(huì)在用戶(hù)界面上顯示的字符串,如果不會(huì)顯示自然就不需要翻譯了。

如果你使用的是 C++ 代碼,那么翻譯用的函數(shù)就是QObject::tr函數(shù)。大多數(shù)時(shí)候,我們看到用到這個(gè)函數(shù)的時(shí)候可能都只是一個(gè)tr,因?yàn)槎际窃谝粋€(gè)繼承自 QObject 的類(lèi)中,所以可以直接調(diào)用父類(lèi)的成員函數(shù)了。如果是在自由函數(shù)中想使用的話就要把完整的函數(shù)名QObject::tr寫(xiě)全了。

如果你寫(xiě)的是 Qt Quick 的程序,這個(gè)函數(shù)就變成了 qsTr 或者是 qsTranslate 、qsTranslateNoOp ...

代碼寫(xiě)完之后,需要在工程文件 (.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 工具打開(kāi)上文生成的 .ts 文件,將對(duì)應(yīng)的詞條翻譯成目標(biāo)語(yǔ)言就好了。

使用 lrelease 生成最終程序使用的翻譯文件

當(dāng) linguist 翻譯完所有的詞條之后,就需要生成最終給應(yīng)用程序使用的二進(jìn)制翻譯文件了。
使用如下命令即可生成。

lrelease English.ts

執(zhí)行完畢,目錄下會(huì)多出一個(gè) English.qm 文件,這個(gè)文件就是最終需要放在應(yīng)用程序中分發(fā)給用戶(hù)的。

問(wèn)題

使用上面的流程就完成了一次基本的程序國(guó)際化的流程。一般來(lái)說(shuō)程序的翻譯工作和編碼工作是由不同人來(lái)完成的,可能實(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 文件。我們先來(lái)看一個(gè)翻譯文件的例子。



    
        QPushButton
        
            Hello world!
            
        
    


這是一個(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è)簡(jiǎn)單的文本文件?,F(xiàn)在有許多的可以用來(lái)讀寫(xiě) Excel 文件的庫(kù),我們只需調(diào)用這些庫(kù)的讀寫(xiě)函數(shù)就能完成我們所需的功能了。
在本文中,我將使用 C# 語(yǔ)言以及 NPOI 庫(kù)來(lái)讀寫(xiě) Excel 文件。

TS 文件轉(zhuǎn) 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("源語(yǔ)言");
    ICell enCell = headRow.CreateCell(1);
    enCell.SetCellValue("目標(biāo)語(yǔ)言");

    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();

            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;
    }
}

     
自動(dòng)翻譯詞條

其實(shí)了解了 TS 文件的結(jié)構(gòu)之后,我們還能做一件事,那就是直接調(diào)用網(wǎng)上的翻譯接口,自動(dòng)將所有的詞條翻譯成對(duì)應(yīng)的語(yǔ)言,下面就是一個(gè)簡(jiǎn)單的例子。

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")


## 下面填寫(xiě)你自己的百度翻譯 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)語(yǔ)言:")
        self.comboTargetLanguage = QComboBox()
        self.comboTargetLanguage.addItem(u"中文", u"zh")
        self.comboTargetLanguage.addItem(u"英語(yǔ)", u"en")
        self.comboTargetLanguage.addItem(u"粵語(yǔ)", u"yue")
        self.comboTargetLanguage.addItem(u"文言文", u"wyw")
        self.comboTargetLanguage.addItem(u"日語(yǔ)", u"jp")
        self.comboTargetLanguage.addItem(u"韓語(yǔ)", u"kor")
        self.comboTargetLanguage.addItem(u"法語(yǔ)", u"fra")
        self.comboTargetLanguage.addItem(u"西班牙語(yǔ)", u"spa")
        self.comboTargetLanguage.addItem(u"泰語(yǔ)", u"th")
        self.comboTargetLanguage.addItem(u"阿拉伯語(yǔ)", u"ara")
        self.comboTargetLanguage.addItem(u"俄語(yǔ)", u"ru")
        self.comboTargetLanguage.addItem(u"葡萄牙語(yǔ)", u"pt")
        self.comboTargetLanguage.addItem(u"德語(yǔ)", u"de")
        self.comboTargetLanguage.addItem(u"意大利語(yǔ)", u"it")
        self.comboTargetLanguage.addItem(u"希臘語(yǔ)", u"el")
        self.comboTargetLanguage.addItem(u"荷蘭語(yǔ)", u"nl")
        self.comboTargetLanguage.addItem(u"波蘭語(yǔ)", u"pl")
        self.comboTargetLanguage.addItem(u"保加利亞語(yǔ)", u"bul")
        self.comboTargetLanguage.addItem(u"愛(ài)沙尼亞語(yǔ)", u"est")
        self.comboTargetLanguage.addItem(u"丹麥語(yǔ)", u"dan")
        self.comboTargetLanguage.addItem(u"芬蘭語(yǔ)", u"fin")
        self.comboTargetLanguage.addItem(u"捷克語(yǔ)", u"cs")
        self.comboTargetLanguage.addItem(u"羅馬尼亞語(yǔ)", u"rom")
        self.comboTargetLanguage.addItem(u"斯洛文尼亞語(yǔ)", u"slo")
        self.comboTargetLanguage.addItem(u"瑞典語(yǔ)", u"swe")
        self.comboTargetLanguage.addItem(u"匈牙利語(yǔ)", u"hu")
        self.comboTargetLanguage.addItem(u"繁體中文", u"cht")
        self.comboTargetLanguage.addItem(u"越南語(yǔ)", u"vie")

        self.labelSrcFile = QLabel(u"源文件")
        self.inputSrcFile = QLineEdit()
        self.inputSrcBtn = QPushButton(u"打開(kāi)文件")

        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"開(kāi)始翻譯")
        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"打開(kāi)要翻譯的文件", 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"開(kāi)始翻譯")

    @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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41581.html

相關(guān)文章

  • 13 萬(wàn)字 C 語(yǔ)言從入門(mén)到精通保姆級(jí)教程2021 年版 (建議收藏)

    摘要:友情提示先關(guān)注收藏,再查看,萬(wàn)字保姆級(jí)語(yǔ)言從入門(mén)到精通教程。及大牛出天地開(kāi)始有隨之乃有萬(wàn)種語(yǔ)年英國(guó)劍橋大學(xué)推出了語(yǔ)言。 友情提示:先關(guān)注收藏,再查看,13 萬(wàn)字保...

    zombieda 評(píng)論0 收藏0
  • Qt開(kāi)源作品41-網(wǎng)絡(luò)調(diào)試助手增強(qiáng)版V2022

    摘要:可暫停顯示收發(fā)數(shù)據(jù)。定時(shí)器自動(dòng)發(fā)送。同時(shí)支持嵌入式樹(shù)莓派等。三效果圖四開(kāi)源主頁(yè)以上作品完整源碼下載都在開(kāi)源主頁(yè),會(huì)持續(xù)不斷更新作品數(shù)量和質(zhì)量,歡迎各位關(guān)注。本開(kāi)源項(xiàng)目已經(jīng)成功升級(jí)到版本,分門(mén)別類(lèi),圖文并茂,保你爽到爆。 ...

    pepperwang 評(píng)論0 收藏0
  • 干貨 - 如何逆向解決QT程序漢化中亂碼問(wèn)題

    摘要:作者逆向驛站微信公眾號(hào)逆向驛站知乎逆向驛站一款開(kāi)發(fā)的國(guó)外軟件,大概率是沒(méi)有做中文支持的,所以你漢化中,不論怎么設(shè)置編碼都一定是亂碼。 作者:逆向驛站微信公眾號(hào):逆向驛站知乎:逆向驛站showImg(https://segmentfault.com/img/bVbnE98?w=1100&h=731); 一款QT開(kāi)發(fā)的國(guó)外軟件,大概率是沒(méi)有做中文支持的,所以你漢化中,不論怎么設(shè)置編碼都一定...

    smartlion 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<