QtLingo 1
QtLingo is an Application to make Qt Computer Translations easier
MyTranlatorParser.cpp
Go to the documentation of this file.
1#include "MyTranlatorParser.h"
2
3
7MyTranlatorParser::MyTranlatorParser(MyLanguageModel *thisLanguageModel, QObject *parent) : QObject(parent), myLanguageModel(thisLanguageModel)
8{
9
10}
11
16{
17 QFile iFile(inputFile);
18 iFile.open(QIODevice::ReadOnly);
19
20 QXmlStreamReader xmlReader(&iFile);
21
22 base_node::base_node_ptr root, current;
23 QString text;
24
25 enum EStates
26 {
27 st_Unstate = 0,
28 st_WaitForStartElement = 0x01,
29 st_WaitForText = 0x02,
30 st_WaitForEndElement = 0x04
31 };
32
33 int states = st_WaitForStartElement;
34
35 while(!xmlReader.atEnd())
36 {
37 QXmlStreamReader::TokenType tt = xmlReader.readNext();
38 switch(tt)
39 {
40 case QXmlStreamReader::StartDocument:
41 {
42 root = std::make_shared<document_node>();
43 current = root;
44 } break;
45 case QXmlStreamReader::DTD:
46 {
47 current->add_child(std::make_shared<DTD_node>("<!DOCTYPE TS>"));
48 } break;
49 case QXmlStreamReader::StartElement:
50 {
51 assert(states & st_WaitForStartElement);
52
53 QString name = xmlReader.name().toString();
54 QXmlStreamAttributes attrs = xmlReader.attributes();
55
56 if("message" == name)
57 {
58 current = current->add_child(std::make_shared<element_node>(element_node::ent_message, name, attrs));
59 }
60 else if("source" == name)
61 {
62 current = current->add_child(std::make_shared<element_node>(element_node::ent_source, name, attrs));
63 }
64 else if("translation" == name)
65 {
66 current = current->add_child(std::make_shared<element_node>(element_node::ent_translation, name, attrs));
67 }
68 else if("TS" == name)
69 {
70 current = current->add_child(std::make_shared<TS_node>(name, attrs));
71 }
72 else
73 {
74 current = current->add_child(std::make_shared<element_node>(element_node::ent_element, name, attrs));
75 }
76
77 states = st_WaitForText|st_WaitForStartElement|st_WaitForEndElement;
78 } break;
79 case QXmlStreamReader::Characters:
80 {
81 if(states & st_WaitForText)
82 {
83 text = xmlReader.text().toString();
84 states = st_WaitForEndElement|st_WaitForStartElement;
85 }
86 } break;
87 case QXmlStreamReader::EndElement:
88 {
89 assert(states & st_WaitForEndElement);
90 assert(current->kind() & base_node::nt_Element);
91 //((element_node*)current.get())->set_text(text);
92
93 reinterpret_cast<element_node*>(current.get())->set_text(text);
94
95 text.clear();
96 states = st_WaitForStartElement|st_WaitForEndElement;
97 current = current->parent();
98 } break;
99 case QXmlStreamReader::Invalid: { break; }
100 case QXmlStreamReader::EndDocument: { break; }
101 case QXmlStreamReader::Comment: { break; }
102 case QXmlStreamReader::EntityReference: { break; }
103 case QXmlStreamReader::ProcessingInstruction: { break; }
104 case QXmlStreamReader::NoToken: { break; }
105 }
106 }
107
108 return root;
109}
110
115{
116 QFile iFile(inputFile);
117 iFile.open(QFile::ReadOnly|QFile::Text);
118 QTextStream txts(&iFile);
119 txts.setCodec("UTF-8");
120
121 const QString rgxp("^(?<id>\\[\\[\\[[A-F0-9]{8}\\]\\]\\])\\s*[\\\",“,”](?<text>.*)[\\\",“,”]$");
122 QRegularExpression rxp(rgxp);
123
124 unsigned int line_counter = 0;
125
126 while(!txts.atEnd())
127 {
128 QString str = txts.readLine();
129 QRegularExpressionMatch rm = rxp.match(str);
130
131 QString id = rm.captured("id");
132 QString text = rm.captured("text");
133
134 if(id.isEmpty() || text.isEmpty())
135 {
136 std::cout << "Error in line: " << line_counter << " , file: " << inputFile.toUtf8().constData() << " , source line: " << str.toUtf8().constData() << std::endl;
137 return false;
138 }
139
140 strings.insert(visitors::map_QStringQString::value_type(id, text));
141 line_counter++;
142 }
143
144 return true;
145}
146
150void MyTranlatorParser::toTXT(const QString &inputFile, const QString &outputDir, bool with_unfinished, bool with_vanished, bool unfinished_only)
151{
152 using namespace visitors;
153
154 QFileInfo fiI(inputFile);
155 if(!fiI.exists())
156 {
157 myLanguageModel->mySetting->showMessageBox(QObject::tr("Input does file not exist!").toLocal8Bit(), QString("%1: %2").arg(tr("Unable to find Input file"), inputFile).toLocal8Bit(), myLanguageModel->mySetting->Critical);
158 return;
159 }
160
161 QFileInfo fiO(outputDir);
162 if(!fiO.exists())
163 {
164 QDir().mkdir(outputDir);
165 }
166
167 QString outputXmlFileName = QDir(outputDir).path() + QDir::separator() + fiI.fileName();
168 QString outputTextFile = QDir(outputDir).path() + QDir::separator() + fiI.baseName() + ".txt";
169
170 unsigned int files_in_out_dir = QDir(outputDir).entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries).count();
171
172 if( !fiO.exists() || 2 < files_in_out_dir || (2 == files_in_out_dir && !QFileInfo::exists(outputXmlFileName) && !QFileInfo::exists(outputTextFile)) )
173 {
174 // FIXME question delete
175 myLanguageModel->mySetting->showMessageBox(QObject::tr("Check output Folder").toLocal8Bit(), QString("%1!: %2").arg(tr("Can not create output directory OR directory is not empty"), inputFile).toLocal8Bit(), myLanguageModel->mySetting->Critical);
176 return;
177 }
178
179 QFile oFile(outputXmlFileName);
180 oFile.open(QIODevice::WriteOnly);
181
182 //pares ts file
183 base_node::base_node_ptr root = parse_ts_file(inputFile);
184
185 //replace strings
186 map_hashQString strings;
187 string_extractor_replacer ser(strings, with_unfinished, with_vanished, unfinished_only);
188 root->visit(ser);
189
190 //write text file
191 QFile sFile(outputTextFile);
192 sFile.open(QIODevice::WriteOnly|QIODevice::Text);
193 QTextStream txts(&sFile);
194 txts.setCodec("UTF-8");
195
196 std::for_each(strings.begin(), strings.end(), [&txts](const map_hashQString::value_type &vt){ txts << vt.second << "\n"; });
197
198 //write modified ts file
199 QXmlStreamWriter xmlWriter(&oFile);
200 xmlWriter.setAutoFormatting(true);
201
202 document_dump ddv(xmlWriter);
203 root->visit(ddv);
204}
205
209void MyTranlatorParser::toTS(const QString &inputDir, const QString &outputFile, const QString &langid)
210{
211 using namespace visitors;
212
213 QFileInfo fiI(inputDir);
214 if(!fiI.exists())
215 {
216 myLanguageModel->mySetting->showMessageBox(QObject::tr("Input directory not exist!").toLocal8Bit(), QString("%1: %2").arg(tr("Unable to find Input folder"), inputDir).toLocal8Bit(), myLanguageModel->mySetting->Critical);
217 return;
218 // FIXME Error
219 }
220
221 const QFileInfoList &fil = QDir(inputDir).entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries);
222 unsigned int files_in_input_dir = fil.count();
223
224 QString tsFile, txtFile;
225
226 if(2 == files_in_input_dir)
227 {
228 QFileInfo if0(QDir(inputDir).path() + QDir::separator() + fil[0].baseName() + ".ts");
229 QFileInfo if1(QDir(inputDir).path() + QDir::separator() + fil[0].baseName() + ".txt");
230
231 if(if0.isFile() && if1.isFile())
232 {
233 tsFile = if0.filePath();
234 txtFile = if1.filePath();
235 }
236 }
237
238 if(2 < files_in_input_dir || 0 == files_in_input_dir || tsFile.isEmpty() || txtFile.isEmpty())
239 {
240 myLanguageModel->mySetting->showMessageBox(QObject::tr("Check Input Folder").toLocal8Bit(), QString("%1!: %2").arg(tr("Input directory should contain only txt and ts file with same name"), tsFile).toLocal8Bit(), myLanguageModel->mySetting->Critical);
241 return;
242 // FIXME Error
243 }
244
245 // pares ts file
247
248 // parse txt file
249 map_QStringQString strings;
250 if(!parse_txt_file(txtFile, strings))
251 {
252 std::cout << "Parsing error: " << txtFile.toUtf8().constData() << " !" << std::endl;
253 myLanguageModel->mySetting->showMessageBox(QObject::tr("Parsing errorr").toLocal8Bit(), QString("%1: %2").arg(tr("Parsing errorr"), txtFile.toUtf8().constData()).toLocal8Bit(), myLanguageModel->mySetting->Critical);
254 return;
255 // FIXME Error
256 }
257
258 // replace strings
259 back_string_replacer bsr(strings, langid);
260 root->visit(bsr);
261
262 // dump to file
263 QFile oFile(outputFile);
264 oFile.open(QIODevice::WriteOnly);
265
266 QXmlStreamWriter xmlWriter(&oFile);
267 xmlWriter.setAutoFormatting(true);
268 xmlWriter.setCodec("UTF-8");
269
270 document_dump ddv(xmlWriter);
271 root->visit(ddv);
272}
273
277void MyTranlatorParser::setDebugMessage(bool thisState)
278{
279 isDebugMessage = thisState;
280}
281
286{
287 return isDebugMessage;
288}
289
293void MyTranlatorParser::setMessage(const QString &thisMessage)
294{
295 if (isDebugMessage)
296 {
297 qDebug() << thisMessage;
298 //std::cout << thisMessage.toStdString() << std::endl;
299 }
300}
301
Abstact Model used for ComboBox. /class MyLanguageModel.
MyOrgSettings * mySetting
mySetting
@ Critical
Critical
Definition: MyOrgSettings.h:75
QVariant showMessageBox(const QString &thisTitle, const QString &thisMessage, MyMessageTypes thisMessageType) const
show Message Box information, question, warning, critica
void toTS(const QString &inputDir, const QString &outputFile, const QString &langid)
toTS
void setDebugMessage(bool thisState)
set Debug Message
bool getDebugMessage()
get Debug Message
MyTranlatorParser(MyLanguageModel *thisLanguageModel=nullptr, QObject *parent=nullptr)
Translation Files Constructor. MyTranslationFiles.
bool parse_txt_file(const QString &inputFile, visitors::map_QStringQString &strings)
parse_txt_file
void setMessage(const QString &thisMessage)
set Message
base_node::base_node_ptr parse_ts_file(const QString &inputFile)
parse_ts_file
void toTXT(const QString &inputFile, const QString &outputDir, bool with_unfinished, bool with_vanished, bool unfinished_only)
toTXT
visitors/
std::map< QString, QString > map_QStringQString
Definition: ts_model.h:54
std::map< hash_t, QString > map_hashQString
map hashQString.
Definition: ts_model.h:53
std::shared_ptr< base_node > base_node_ptr
Definition: ts_model.h:116
@ nt_Element
Definition: ts_model.h:113
base_node_ptr parent() const
Definition: ts_model.h:133
element node.
Definition: ts_model.h:172
@ ent_translation
Definition: ts_model.h:173
back string replacer.
Definition: ts_model.h:81
document dump.
Definition: ts_model.h:38
string extractor replacer.
Definition: ts_model.h:60