运用XML去除QT语言包文件中失效项,同时召回已有的翻译

QT多语言包机制是个好东西,但是往往代码的修改,伴随着已有的翻译失效问题很头疼,急需一个工具能够召回已翻译的但是失效的项,本工具应运而生。

核心技术QT XML操作类QDomDocument


直接上代码:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QCheckBox>
#include <QTreeWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDomDocument>

//去除语言文件中的失效项
class MainWindow : public QWidget
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
public:
signals:
public slots:
    void onSlotChooseLangFileFunc();//选择语言文件
    void onSlotRecallRepeatTranslationFunc();//召回重复的翻译
    void onSlotTrimLangFileContextFunc();//输出过滤文件
    void onSlotSelectedRightItemFunc(QModelIndex);//选择右边对应翻译项
protected:
    void resizeEvent(QResizeEvent *);
private:
    void recallItemTranslation(QTreeWidgetItem* item);
    void readAndSave();
private:
    void prepareRepeatXml();//左边重复项
    void prepareOutputXml();//右边输出项
private:
    void initControl();
    void bindEvent();
private:
    QVBoxLayout* main_layout;
    QHBoxLayout* tool_layout;
    QVBoxLayout* repeat_title_layout;
    QVBoxLayout* output_title_layout;
    QHBoxLayout* content_layout;
    QHBoxLayout* save_layout;

    QLabel* url_label;//语言文件
    QLineEdit* url_linedit;
    QPushButton* url_button;//选择文件
    QPushButton* recall_button;//回收翻译
    QCheckBox* doall_chkbox;//全部替换
    QPushButton* trim_button;//清理操作
    QPushButton* cancel_button;

    QLabel* repeat_title_label;
    QTreeWidget* repeat_treewidget;//重复树
    QLabel* output_title_label;
    QTreeWidget* output_treewidget;//输出树

private:
    QDomDocument output_doc;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include <QHeaderView>
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{    
    main_layout = new QVBoxLayout(this);
    tool_layout = new QHBoxLayout(this);
    repeat_title_layout = new QVBoxLayout(this);
    output_title_layout = new QVBoxLayout(this);
    content_layout = new QHBoxLayout(this);
    save_layout = new QHBoxLayout(this);

    url_label = new QLabel(this);//语言文件
    url_linedit = new QLineEdit(this);//语言文件
    url_button = new QPushButton(this);//选择文件
    recall_button = new QPushButton(this);//回收翻译
    doall_chkbox = new QCheckBox(this);//全部替换
    trim_button = new QPushButton(this);//清理操作
    cancel_button = new QPushButton(this);

    repeat_title_label = new QLabel(this);
    repeat_treewidget = new QTreeWidget(this);//重复树
    output_title_label = new QLabel(this);
    output_treewidget = new QTreeWidget(this);//输出树

    tool_layout->setContentsMargins(0,0);
    tool_layout->addWidget(url_label);
    tool_layout->addWidget(url_linedit);
    tool_layout->addWidget(url_button);

    repeat_title_layout->setContentsMargins(0,0);
    repeat_title_layout->addWidget(repeat_title_label);
    repeat_title_layout->addWidget(repeat_treewidget);

    output_title_layout->setContentsMargins(0,0);
    output_title_layout->addWidget(output_title_label);
    output_title_layout->addWidget(output_treewidget);

    content_layout->setContentsMargins(0,0);
    content_layout->addLayout(repeat_title_layout);
    content_layout->addWidget(recall_button);
    content_layout->addLayout(output_title_layout);

    save_layout->setContentsMargins(0,0);
    save_layout->addWidget(doall_chkbox);
    save_layout->addStretch(0);
    save_layout->addWidget(trim_button);
    save_layout->addWidget(cancel_button);

    main_layout->setContentsMargins(20,20,20);
    main_layout->addLayout(tool_layout);
    main_layout->addSpacing(10);
    main_layout->addLayout(content_layout);
    main_layout->addSpacing(10);
    main_layout->addLayout(save_layout);

    this->setLayout(main_layout);
    this->initControl();
    this->bindEvent();
    this->resize(640,480);
}

void MainWindow::initControl()
{
    url_label->setText(tr("language file:"));//语言文件
    url_button->setText(tr("choose..."));//选择文件
    recall_button->setText(">>");
    recall_button->setToolTip(tr("recall translation"));//回收翻译
    doall_chkbox->setText(tr("recall all"));//全部替换
    trim_button->setText(tr("save"));//清理重复
    cancel_button->setText(tr("cancel"));

    repeat_title_label->setText(tr("repeat items"));//重复的数据
    repeat_title_label->setAlignment(Qt::AlignCenter);
    output_title_label->setText(tr("output items"));//输出的数据
    output_title_label->setAlignment(Qt::AlignCenter);

    QStringList headLabels;
    headLabels<<tr("source language")<<tr("target language");

    repeat_treewidget->setColumnCount(2);
    repeat_treewidget->setHeaderLabels(headLabels);
    //repeat_treewidget->header()->setSectionResizeMode(QHeaderView::Interactive);
    repeat_treewidget->headerItem()->setTextAlignment(0,Qt::AlignCenter);
    repeat_treewidget->headerItem()->setTextAlignment(1,Qt::AlignCenter);
    repeat_treewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    repeat_treewidget->setSelectionMode(QAbstractItemView::SingleSelection);
    repeat_treewidget->setFocusPolicy(Qt::NoFocus);

    output_treewidget->setColumnCount(2);
    output_treewidget->setHeaderLabels(headLabels);
    //output_treewidget->header()->setSectionResizeMode(QHeaderView::Interactive);
    output_treewidget->headerItem()->setTextAlignment(0,Qt::AlignCenter);
    output_treewidget->headerItem()->setTextAlignment(0,Qt::AlignCenter);
    output_treewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    output_treewidget->setSelectionMode(QAbstractItemView::SingleSelection);
    output_treewidget->setFocusPolicy(Qt::NoFocus);

    QString style =
            "QTreeView{ background:#ffffff;color:#202020; }"
            "QTreeView::item{ height:30px; }"
            "QTreeView::item:disabled{ color:#cccccc; }"
            "QTreeView::item:hover{ background-color:rgb(0,255,30); }"
            "QTreeView::item:selected{ background-color:rgb(30,80,80); }";
    repeat_treewidget->setStyleSheet(style);
    output_treewidget->setStyleSheet(style);
}

void MainWindow::bindEvent()
{
    connect( url_button,SIGNAL(clicked()),this,SLOT(onSlotChooseLangFileFunc()) );

    connect( recall_button,SLOT(onSlotRecallRepeatTranslationFunc()) );
    connect( trim_button,SLOT(onSlotTrimLangFileContextFunc()) );

    connect( cancel_button,SLOT(close()) );

    connect( repeat_treewidget,SIGNAL(clicked(QModelIndex)),SLOT(onSlotSelectedRightItemFunc(QModelIndex)) );
}

void MainWindow::onSlotChooseLangFileFunc()
{
    QString langFile = QFileDialog::getOpenFileName(0,tr("choose language file"),tr("."),"qt ts language(*.ts)");
    if( langFile.length()<=0 )
    {
        return ;
    }

    url_linedit->setText(langFile);

    this->prepareRepeatXml();
    this->prepareOutputXml();
}

//召回重复的翻译选项
void MainWindow::onSlotRecallRepeatTranslationFunc()
{
    QTreeWidgetItem* item = repeat_treewidget->currentItem();
    if( !item )//没有选中
    {
        if( doall_chkbox->isChecked() )
        {
            if( QMessageBox::Yes==QMessageBox::question(0,tr("notice"),tr("will replace all the existing translation! continue?")) )
            {
                QTreeWidgetItemIterator it(repeat_treewidget);
                while( *it )//召回全部项
                {
                    this->recallItemTranslation(*it);
                    ++it;
                }
            }
        }
        else
        {
            QMessageBox::warning(0,tr("select an repeat translation!"));
        }
        return ;
    }

    //召回选中项
    this->recallItemTranslation(item);
}

//保存召回的翻译XML
void MainWindow::onSlotTrimLangFileContextFunc()
{
    QString langUrl = url_linedit->text();
    if( langUrl.length()<=0 )
    {
        QMessageBox::warning(0,tr("language url is null!"));
        return ;
    }

    //保存修改后的
    langUrl += ".mod.ts";
    QFile ofile(langUrl);
    if( !ofile.open(QIODevice::WriteOnly | QIODevice::Truncate |QIODevice::Text) )
    {
        return ;
    }
    QTextStream out(&ofile);
    out.setCodec("UTF-8");
    output_doc.save(out,4,QDomNode::EncodingFromTextStream);
    ofile.close();
}

void MainWindow::onSlotSelectedRightItemFunc(QModelIndex)
{
    QTreeWidgetItem* item = repeat_treewidget->currentItem();
    if( !item )
    {
        return ;
    }

    output_treewidget->setCurrentItem(NULL);//取消选择

    //选择节点的父节点
    QTreeWidgetItem* itemparent = item->parent();
    if( !itemparent )
    {
        return ;
    }
    //qDebug()<<"当前节点——"<<item->text(0)<<"其父节点——"<<itemparent->text(0);

    //遍历右边树
    QTreeWidgetItemIterator it(output_treewidget);
    while( *it )
    {
        if( (*it)->text(0).compare(item->text(0),Qt::CaseSensitive)==0 && !(*it)->text(1).isEmpty() )//节点关键字
        {
            QTreeWidgetItem* itemcmp = (*it)->parent();//父节点关键字
            if( itemcmp && itemcmp->text(0).compare(itemparent->text(0),Qt::CaseSensitive)==0 )
            {
                //qDebug()<<"右边当前节点——"<<(*it)->text(0)<<"其父节点——"<<itemcmp->text(0);
                output_treewidget->setCurrentItem(*it);//选中对应项
                break;
            }
        }
        ++it;
    }

}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    QWidget::resizeEvent(e);

    repeat_treewidget->setColumnWidth(0,repeat_treewidget->width()*0.5);
    output_treewidget->setColumnWidth(0,output_treewidget->width()*0.5);
}

void MainWindow::recallItemTranslation(QTreeWidgetItem *item)
{
    if( !item )//重复选项
    {
        return ;
    }

    //选中对应的右边选项,替换其翻译
    repeat_treewidget->setCurrentItem(item);
    repeat_treewidget->clicked(repeat_treewidget->currentIndex());
    if( output_treewidget->currentItem() )
    {
        output_treewidget->currentItem()->setText(1,item->text(1));
        output_treewidget->currentItem()->setToolTip(0,item->text(1));
    }

    //获取父节点名称
    QTreeWidgetItem* itemparent = item->parent();
    if( !itemparent )
    {
        qDebug()<<"节点父节点未找到——"<<item->text(0);
        return ;
    }

    //修改去重后的翻译XML
    if( output_doc.isNull() )
    {
        qDebug()<<"XML----"<<output_doc.isNull();
        return ;
    }

    QDomElement root = output_doc.documentElement();//根节点
    QDomNode node = root.firstChild();
    while( !node.isNull() )
    {
        QDomElement ele = node.toElement();
        if( !ele.isNull() && ele.tagName().compare("context",Qt::CaseInsensitive)==0 )
        {
            //qDebug()<<"遍历节点——"<<ele.tagName();
            QDomElement e = ele.firstChildElement();//子节点
            while( !e.isNull() )
            {
                if( e.tagName().compare("name",Qt::CaseInsensitive)==0 )
                {
                    if( e.text().compare(itemparent->text(0),Qt::CaseSensitive)!=0 )
                    {
                        break;
                    }
                    //qDebug()<<"XML中找到节点——"<<e.text()<<itemparent->text(0);
                }
                if( e.tagName().compare("message",Qt::CaseInsensitive)==0 )
                {
                    QDomElement eTran = e.firstChildElement();
                    while( !eTran.isNull() )
                    {
                        //qDebug()<<"1111XML中找到翻译——"<<eTran.tagName()<<item->text(0);
                        if( eTran.tagName().compare("source",Qt::CaseSensitive)==0 )
                        {
                            if( eTran.text().compare(item->text(0),Qt::CaseSensitive)==0 )
                            {
                                //qDebug()<<"2222XML中找到翻译——"<<eTran.text()<<item->text(0);
                                eTran = eTran.nextSiblingElement("translation");
                                if( !eTran.isNull() )
                                {
                                    //eTran.setNodeValue(item->text(1));//设置节点数据,没作用
                                    eTran.firstChild().setNodeValue(item->text(1));//修改节点数据,可以
                                    qDebug()<<"3333XML中写入翻译——"<<eTran.tagName()<<eTran.text();
                                }
                                break;
                            }
                        }
                        eTran = eTran.nextSiblingElement();
                    }
                }
                e = e.nextSiblingElement();
            }//
        }
        node = node.nextSibling();
    }

}

void MainWindow::readAndSave()
{
    QString langUrl = url_linedit->text();
    if( langUrl.length()<=0 )
    {
        QMessageBox::warning(0,tr("language url is null!"));
        return ;
    }

    QFile file(langUrl);
    if( !file.open(QFile::ReadOnly|QFile::Text) )
    {
        QMessageBox::warning(0,tr("language file open failed!"));
        return ;
    }

    QDomDocument doc;
    if( !doc.setContent(&file) )
    {
        file.close();
        return ;
    }
    file.close();

    if( doc.isNull() )
    {
        qDebug()<<"XML----"<<doc.isNull();
        return ;
    }

    QDomElement root = doc.documentElement();
    QString rootName = root.tagName();
    if( rootName.compare("ts",Qt::CaseInsensitive)==0 )
    {
        //qDebug()<<"version---"<<rootName<<root.hasAttribute("version");
    }

    QDomNode node = root.firstChild();
    while( !node.isNull() )
    {
        QDomElement ele = node.toElement();
        if( !ele.isNull() && ele.tagName().compare("context",Qt::CaseInsensitive)==0 )
                {
                    //qDebug()<<"to translate file----"<<e.tagName()<<e.text();
                }
                if( e.tagName().compare("message",Qt::CaseInsensitive)==0 )
                {
                    QDomElement eLoc = e.firstChildElement("location");
                    if( eLoc.isNull() )
                    {
                        //qDebug()<<"找不到location节点,就是应该删除的message项!";
                        QDomElement temp = e;
                        e = e.nextSiblingElement();
                        ele.removeChild(temp);
                        continue;
                    }
                    else
                    {
                        //qDebug()<<"find lang file location----"<<eLoc.attribute("filename")
                        //       <<eLoc.attribute("line");
                    }
                }
                e = e.nextSiblingElement();
            }//
        }
        node = node.nextSibling();
    }

    //保存修改后的
    langUrl += ".mod.ts";
    QFile ofile(langUrl);
    if( !ofile.open(QIODevice::WriteOnly | QIODevice::Truncate |QIODevice::Text) )
    {
        return ;
    }
    QTextStream out(&ofile);
    out.setCodec("UTF-8");
    doc.save(out,QDomNode::EncodingFromTextStream);
    ofile.close();
}

void MainWindow::prepareRepeatXml()
{
    QString langUrl = url_linedit->text();
    if( langUrl.length()<=0 )
    {
        QMessageBox::warning(0,tr("language url is null!"));
        return ;
    }

    repeat_treewidget->clear();

    QFile file(langUrl);
    if( !file.open(QFile::ReadOnly|QFile::Text) )
    {
        QMessageBox::warning(0,tr("language file open failed!"));
        return ;
    }

    QDomDocument doc;
    if( !doc.setContent(&file) )
    {
        file.close();
        return ;
    }
    file.close();

    if( doc.isNull() )
    {
        qDebug()<<"XML----"<<doc.isNull();
        return ;
    }

    QTreeWidgetItem* itemRoot = NULL;//树根节点

    QDomElement root = doc.documentElement();
    if( root.tagName().compare("ts",Qt::CaseInsensitive)==0 )
    {
        itemRoot = new QTreeWidgetItem(0);//根节点
        itemRoot->setText(0,root.tagName());
        repeat_treewidget->addTopLevelItem(itemRoot);
    }

    QDomNode node = root.firstChild();
    while( !node.isNull() )
    {
        QDomElement ele = node.toElement();
        if( !ele.isNull() && ele.tagName().compare("context",Qt::CaseInsensitive)==0 )
        {
            //qDebug()<<"遍历节点——"<<ele.tagName();
            QTreeWidgetItem* itemFile = NULL;//文件节点
            QString nodeName;//文件节点名称

            QDomElement e = ele.firstChildElement();//子节点
            while( !e.isNull() )
            {
                if( e.tagName().compare("name",Qt::CaseInsensitive)==0 )
                {
                    nodeName = e.text();
                }
                if( e.tagName().compare("message",Qt::CaseInsensitive)==0 )
                {
                    QDomElement eLoc = e.firstChildElement("location");//文中位置
                    if( eLoc.isNull() )
                    {
                        itemFile = new QTreeWidgetItem(0);//context name节点
                        itemFile->setText(0,nodeName);
                        itemRoot->addChild(itemFile);

                        QStringList stringLang;//语言翻译数据
                        eLoc = e.firstChildElement();//再次取值
                        while( !eLoc.isNull() )
                        {
                            //qDebug()<<eLoc.tagName()<<eLoc.text();
                            if( eLoc.tagName().compare("source",Qt::CaseInsensitive)==0 ||
                                eLoc.tagName().compare("translation",Qt::CaseInsensitive)==0 )
                            {
                                stringLang<<eLoc.text();
                            }
                            eLoc = eLoc.nextSiblingElement();
                        }

                        if( itemFile )//添加语言翻译
                        {
                            QTreeWidgetItem* itemLang = new QTreeWidgetItem(0);//context message location节点
                            itemLang->setText(0,stringLang.first());
                            itemLang->setToolTip(0,stringLang.last());
                            itemLang->setText(1,stringLang.last());
                            itemFile->addChild(itemLang);
                        }

                        //移除失效的节点
                        //QDomElement temp = e; e = e.nextSiblingElement();
                        //ele.removeChild(temp);
                        //continue;
                    }
                }
                e = e.nextSiblingElement();
            }//
        }
        node = node.nextSibling();
    }

    //展开所有项
    repeat_treewidget->expandAll();
}

void MainWindow::prepareOutputXml()
{
    QString langUrl = url_linedit->text();
    if( langUrl.length()<=0 )
    {
        QMessageBox::warning(0,tr("language url is null!"));
        return ;
    }

    output_treewidget->clear();

    QFile file(langUrl);
    if( !file.open(QFile::ReadOnly|QFile::Text) )
    {
        QMessageBox::warning(0,root.tagName());
        output_treewidget->addTopLevelItem(itemRoot);
    }

    QDomNode node = root.firstChild();
    while( !node.isNull() )
    {
        QDomElement ele = node.toElement();
        if( !ele.isNull() && ele.tagName().compare("context",Qt::CaseInsensitive)==0 )//文件名节点
                {
                    nodeName = e.text();
                }
                if( e.tagName().compare("message",Qt::CaseInsensitive)==0 )//翻译节点
                {
                    QDomElement eLoc = e.firstChildElement("location");//文中位置
                    if( eLoc.isNull() )
                    {
                        //移除失效的节点
                        QDomElement temp = e; e = e.nextSiblingElement();
                        ele.removeChild(temp);
                        continue;
                    }
                    else
                    {
                        itemFile = new QTreeWidgetItem(0);//context name节点
                        itemFile->setText(0,nodeName);
                        itemRoot->addChild(itemFile);

                        QStringList stringLang;//语言翻译数据
                        while( !eLoc.isNull() )
                        {
                            //qDebug()<<eLoc.tagName()<<eLoc.text();
                            if( eLoc.tagName().compare("source",Qt::CaseInsensitive)==0 )
                            {
                                stringLang<<eLoc.text();
                            }
                            eLoc = eLoc.nextSiblingElement();
                        }
                        if( itemFile )//添加语言翻译
                        {
                            QTreeWidgetItem* itemLang = new QTreeWidgetItem(0);//context message location节点
                            itemLang->setText(0,stringLang.last());
                            itemFile->addChild(itemLang);
                        }
                    }
                }//end message
                e = e.nextSiblingElement();
            }//
        }
        node = node.nextSibling();
    }

    //保存修改后的
    output_doc = doc;

    //langUrl += ".mod.ts";
    //QFile ofile(langUrl);
    //if( !ofile.open(QIODevice::WriteOnly | QIODevice::Truncate |QIODevice::Text) )
    //{
    //    return ;
    //}
    //QTextStream out(&ofile);
    //out.setCodec("UTF-8");
    //doc.save(out,QDomNode::EncodingFromTextStream);
    //file.close();

    //展开所有项
    output_treewidget->expandAll();
}


by houwenbin1986@gmail.com(http://blog.csdn.net/houwenbin1986) TrimTSFile是一个去除QT语言文件失效项的小工具,同时,可以针对失效项已有的翻译进行召回,可以单条选中召回,也可以全部匹配召回。最后保存为纯净的语言包TS文件。再导入Linguist编辑!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇