163 static const QString strcatalog = u"catalog"_s;
164 static const QString strcomment = u"comment"_s;
165 static const QString strcontext = u"context"_s;
166 static const QString strdependencies = u"dependencies"_s;
167 static const QString strdependency = u"dependency"_s;
168 static const QString strextracomment = u"extracomment"_s;
169 static const QString strlabel = u"label"_s;
170 static const QString strfilename = u"filename"_s;
171 static const QString strid = u"id"_s;
172 static const QString strlanguage = u"language"_s;
173 static const QString strline = u"line"_s;
174 static const QString strlocation = u"location"_s;
175 static const QString strmessage = u"message"_s;
176 static const QString strname = u"name"_s;
177 static const QString strnumerus = u"numerus"_s;
178 static const QString strnumerusform = u"numerusform"_s;
179 static const QString strobsolete = u"obsolete"_s;
180 static const QString stroldcomment = u"oldcomment"_s;
181 static const QString stroldsource = u"oldsource"_s;
182 static const QString strsource = u"source"_s;
183 static const QString strsourcelanguage = u"sourcelanguage"_s;
184 static const QString strtranslation = u"translation"_s;
185 static const QString strtranslatorcomment = u"translatorcomment"_s;
186 static const QString strTS = u"TS"_s;
187 static const QString strtype = u"type"_s;
188 static const QString strunfinished = u"unfinished"_s;
189 static const QString struserdata = u"userdata"_s;
190 static const QString strvanished = u"vanished"_s;
192 static const QString stryes = u"yes"_s;
194 static const QString strextrans(
"extra-"_L1);
198 if (isStartDocument()) {
201 }
else if (isEndDocument()) {
204 }
else if (isDTD()) {
207 }
else if (elementStarts(strTS)) {
210 QHash<QString,
int> currentLine;
212 bool maybeRelative =
false, maybeAbsolute =
false;
214 QXmlStreamAttributes atts = attributes();
216 translator.setLanguageCode(atts.value(strlanguage).toString());
217 translator.setSourceLanguageCode(atts.value(strsourcelanguage).toString());
220 if (isEndElement()) {
223 }
else if (isWhiteSpace()) {
225 }
else if (isStartElement()
226 && name().toString().startsWith(strextrans)) {
228 QString tag = name().toString();
229 translator.setExtra(tag.mid(6), readContents());
231 }
else if (elementStarts(strdependencies)) {
233
234
235
236
237
238 QStringList dependencies;
241 if (isEndElement()) {
244 }
else if (elementStarts(strdependency)) {
246 QXmlStreamAttributes atts = attributes();
247 dependencies.append(atts.value(strcatalog).toString());
250 if (isEndElement()) {
257 translator.setDependencies(dependencies);
258 }
else if (elementStarts(strcontext)) {
263 if (isEndElement()) {
266 }
else if (isWhiteSpace()) {
268 }
else if (elementStarts(strname)) {
270 context = readElementText();
272 }
else if (elementStarts(strmessage)) {
275 QString currentMsgFile = currentFile;
278 msg.setId(attributes().value(strid).toString());
279 msg.setContext(context);
281 msg
.setPlural(attributes().value(strnumerus) == stryes
);
285 if (isEndElement()) {
290 }
else if (isWhiteSpace()) {
292 }
else if (elementStarts(strsource)) {
294 msg.setSourceText(readContents());
295 }
else if (elementStarts(stroldsource)) {
297 msg.setOldSourceText(readContents());
298 }
else if (elementStarts(stroldcomment)) {
300 msg.setOldComment(readContents());
301 }
else if (elementStarts(strextracomment)) {
303 msg.setExtraComment(readContents());
304 }
else if (elementStarts(strlabel)) {
306 msg.setLabel(readContents());
307 }
else if (elementStarts(strtranslatorcomment)) {
309 msg.setTranslatorComment(readContents());
310 }
else if (elementStarts(strlocation)) {
312 maybeAbsolute =
true;
313 QXmlStreamAttributes atts = attributes();
314 QString fileName = atts.value(strfilename).toString();
315 if (fileName.isEmpty()) {
316 fileName = currentMsgFile;
317 maybeRelative =
true;
320 currentFile = fileName;
321 currentMsgFile = fileName;
323 const QString lin = atts.value(strline).toString();
328 int lineNo = lin.toInt(&bOK);
330 if (lin.startsWith(u'+') || lin.startsWith(u'-')) {
331 lineNo = (currentLine[fileName] += lineNo);
332 maybeRelative =
true;
338 }
else if (elementStarts(strcomment)) {
340 msg.setComment(readContents());
341 }
else if (elementStarts(struserdata)) {
343 msg.setUserData(readContents());
344 }
else if (elementStarts(strtranslation)) {
346 QXmlStreamAttributes atts = attributes();
347 QStringView type = atts.value(strtype);
348 if (type == strunfinished)
350 else if (type == strvanished)
352 else if (type == strobsolete)
355 QStringList translations;
358 if (isEndElement()) {
360 }
else if (isWhiteSpace()) {
362 }
else if (elementStarts(strnumerusform)) {
363 translations.append(readTransContents());
369 msg.setTranslations(translations);
371 msg.setTranslation(readTransContents());
374 }
else if (isStartElement()
375 && name().toString().startsWith(strextrans)) {
377 QString tag = name().toString();
378 msg.setExtra(tag.mid(6), readContents());
395 maybeAbsolute =
true;
405 m_cd.appendError(errorString());
494 t <<
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE TS>\n";
496 t <<
"<TS version=\"2.1\"";
498 QString languageCode = translator.languageCode();
499 if (!languageCode.isEmpty() && languageCode !=
"C"_L1)
500 t <<
" language=\"" << languageCode <<
"\"";
501 languageCode = translator.sourceLanguageCode();
502 if (!languageCode.isEmpty() && languageCode !=
"C"_L1)
503 t <<
" sourcelanguage=\"" << languageCode <<
"\"";
506 const QStringList deps = translator.dependencies();
507 if (!deps.isEmpty()) {
508 t <<
"<dependencies>\n";
509 for (
const QString &dep : deps)
510 t <<
" <dependency catalog=\"" << dep <<
"\"/>\n";
511 t <<
"</dependencies>\n";
514 QRegularExpression drops(QRegularExpression::anchoredPattern(cd.dropTags().join(u'|')));
516 writeExtras(t,
" ", translator
.extras(), drops);
518 QHash<QString, QList<TranslatorMessage> > messageOrder;
519 QList<QString> contextOrder;
520 for (
const TranslatorMessage &msg : translator.messages()) {
522 if ((msg.type() == TranslatorMessage::Obsolete || msg.type() == TranslatorMessage::Vanished)
523 && msg.translation().isEmpty()) {
527 QList<TranslatorMessage> &context = messageOrder[msg.context()];
528 if (context.isEmpty())
529 contextOrder.append(msg.context());
533 std::sort(contextOrder.begin(), contextOrder.end());
536 return m1.sourceText() < m2.sourceText();
538 for (QList<TranslatorMessage> &contextMessages : messageOrder)
539 std::sort(contextMessages.begin(), contextMessages.end(), messageComparator);
542 QHash<QString,
int> currentLine;
544 for (
const QString &context : std::as_const(contextOrder)) {
547 << tsProtect(context)
549 for (
const TranslatorMessage &msg : std::as_const(messageOrder[context])) {
553 if (!msg.id().isEmpty())
554 t <<
" id=\"" << tsProtect(msg.id()) <<
"\"";
556 t <<
" numerus=\"yes\"";
558 if (translator.locationsType() != Translator::NoLocations) {
559 QString cfile = currentFile;
561 for (
const TranslatorMessage::Reference &ref : msg.allReferences()) {
562 QString fn = cd.m_targetDir.relativeFilePath(ref.fileName())
563 .replace(u'\\', u'/');
564 int ln = ref.lineNumber();
566 if (translator.locationsType() == Translator::RelativeLocations) {
568 int dlt = ln - currentLine[fn];
571 ld.append(QString::number(dlt));
572 currentLine[fn] = ln;
585 ld = QString::number(ln);
591 t <<
" filename=\"" << fn <<
"\"";
592 t <<
" line=\"" << ld <<
"\"";
599 << tsProtect(msg.sourceText())
602 if (!msg.oldSourceText().isEmpty())
603 t <<
" <oldsource>" << tsProtect(msg.oldSourceText()) <<
"</oldsource>\n";
605 if (!msg.comment().isEmpty()) {
607 << tsProtect(msg.comment())
611 if (!msg.oldComment().isEmpty())
612 t <<
" <oldcomment>" << tsProtect(msg.oldComment()) <<
"</oldcomment>\n";
614 if (!msg.extraComment().isEmpty())
615 t <<
" <extracomment>" << tsProtect(msg.extraComment())
616 <<
"</extracomment>\n";
618 if (!msg.label().isEmpty())
619 t <<
" <label>" << tsProtect(msg.label()) <<
"</label>\n";
621 if (!msg.translatorComment().isEmpty())
622 t <<
" <translatorcomment>" << tsProtect(msg.translatorComment())
623 <<
"</translatorcomment>\n";
625 t <<
" <translation";
626 if (msg.type() == TranslatorMessage::Unfinished)
627 t <<
" type=\"unfinished\"";
628 else if (msg.type() == TranslatorMessage::Vanished)
629 t <<
" type=\"vanished\"";
630 else if (msg.type() == TranslatorMessage::Obsolete)
631 t <<
" type=\"obsolete\"";
632 if (msg.isPlural()) {
634 const QStringList &translns = msg.translations();
635 for (
int j = 0; j < translns.size(); ++j) {
636 t <<
"\n <numerusform";
637 writeVariants(t,
" ", translns[j]);
638 t <<
"</numerusform>";
642 writeVariants(t,
" ", msg.translation());
644 t <<
"</translation>\n";
646 writeExtras(t,
" ", msg.extras(), drops);
648 if (!msg.userData().isEmpty())
649 t <<
" <userdata>" << msg.userData() <<
"</userdata>\n";
650 t <<
" </message>\n";