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 strfilename = u"filename"_s;
170 static const QString strid = u"id"_s;
171 static const QString strlanguage = u"language"_s;
172 static const QString strline = u"line"_s;
173 static const QString strlocation = u"location"_s;
174 static const QString strmessage = u"message"_s;
175 static const QString strname = u"name"_s;
176 static const QString strnumerus = u"numerus"_s;
177 static const QString strnumerusform = u"numerusform"_s;
178 static const QString strobsolete = u"obsolete"_s;
179 static const QString stroldcomment = u"oldcomment"_s;
180 static const QString stroldsource = u"oldsource"_s;
181 static const QString strsource = u"source"_s;
182 static const QString strsourcelanguage = u"sourcelanguage"_s;
183 static const QString strtranslation = u"translation"_s;
184 static const QString strtranslatorcomment = u"translatorcomment"_s;
185 static const QString strTS = u"TS"_s;
186 static const QString strtype = u"type"_s;
187 static const QString strunfinished = u"unfinished"_s;
188 static const QString struserdata = u"userdata"_s;
189 static const QString strvanished = u"vanished"_s;
191 static const QString stryes = u"yes"_s;
193 static const QString strextrans(QLatin1String(
"extra-"));
197 if (isStartDocument()) {
200 }
else if (isEndDocument()) {
203 }
else if (isDTD()) {
206 }
else if (elementStarts(strTS)) {
209 QHash<QString,
int> currentLine;
211 bool maybeRelative =
false, maybeAbsolute =
false;
213 QXmlStreamAttributes atts = attributes();
215 translator.setLanguageCode(atts.value(strlanguage).toString());
216 translator.setSourceLanguageCode(atts.value(strsourcelanguage).toString());
219 if (isEndElement()) {
222 }
else if (isWhiteSpace()) {
224 }
else if (isStartElement()
225 && name().toString().startsWith(strextrans)) {
227 QString tag = name().toString();
228 translator.setExtra(tag.mid(6), readContents());
230 }
else if (elementStarts(strdependencies)) {
232
233
234
235
236
237 QStringList dependencies;
240 if (isEndElement()) {
243 }
else if (elementStarts(strdependency)) {
245 QXmlStreamAttributes atts = attributes();
246 dependencies.append(atts.value(strcatalog).toString());
249 if (isEndElement()) {
256 translator.setDependencies(dependencies);
257 }
else if (elementStarts(strcontext)) {
262 if (isEndElement()) {
265 }
else if (isWhiteSpace()) {
267 }
else if (elementStarts(strname)) {
269 context = readElementText();
271 }
else if (elementStarts(strmessage)) {
274 QString currentMsgFile = currentFile;
277 msg.setId(attributes().value(strid).toString());
278 msg.setContext(context);
280 msg
.setPlural(attributes().value(strnumerus) == stryes
);
284 if (isEndElement()) {
289 }
else if (isWhiteSpace()) {
291 }
else if (elementStarts(strsource)) {
293 msg.setSourceText(readContents());
294 }
else if (elementStarts(stroldsource)) {
296 msg.setOldSourceText(readContents());
297 }
else if (elementStarts(stroldcomment)) {
299 msg.setOldComment(readContents());
300 }
else if (elementStarts(strextracomment)) {
302 msg.setExtraComment(readContents());
303 }
else if (elementStarts(strtranslatorcomment)) {
305 msg.setTranslatorComment(readContents());
306 }
else if (elementStarts(strlocation)) {
308 maybeAbsolute =
true;
309 QXmlStreamAttributes atts = attributes();
310 QString fileName = atts.value(strfilename).toString();
311 if (fileName.isEmpty()) {
312 fileName = currentMsgFile;
313 maybeRelative =
true;
316 currentFile = fileName;
317 currentMsgFile = fileName;
319 const QString lin = atts.value(strline).toString();
324 int lineNo = lin.toInt(&bOK);
326 if (lin.startsWith(QLatin1Char(
'+')) || lin.startsWith(QLatin1Char(
'-'))) {
327 lineNo = (currentLine[fileName] += lineNo);
328 maybeRelative =
true;
334 }
else if (elementStarts(strcomment)) {
336 msg.setComment(readContents());
337 }
else if (elementStarts(struserdata)) {
339 msg.setUserData(readContents());
340 }
else if (elementStarts(strtranslation)) {
342 QXmlStreamAttributes atts = attributes();
343 QStringView type = atts.value(strtype);
344 if (type == strunfinished)
346 else if (type == strvanished)
348 else if (type == strobsolete)
351 QStringList translations;
354 if (isEndElement()) {
356 }
else if (isWhiteSpace()) {
358 }
else if (elementStarts(strnumerusform)) {
359 translations.append(readTransContents());
365 msg.setTranslations(translations);
367 msg.setTranslation(readTransContents());
370 }
else if (isStartElement()
371 && name().toString().startsWith(strextrans)) {
373 QString tag = name().toString();
374 msg.setExtra(tag.mid(6), readContents());
391 maybeAbsolute =
true;
401 m_cd.appendError(errorString());
491 t <<
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE TS>\n";
493 t <<
"<TS version=\"2.1\"";
495 QString languageCode = translator.languageCode();
496 if (!languageCode.isEmpty() && languageCode != QLatin1String(
"C"))
497 t <<
" language=\"" << languageCode <<
"\"";
498 languageCode = translator.sourceLanguageCode();
499 if (!languageCode.isEmpty() && languageCode != QLatin1String(
"C"))
500 t <<
" sourcelanguage=\"" << languageCode <<
"\"";
503 const QStringList deps = translator.dependencies();
504 if (!deps.isEmpty()) {
505 t <<
"<dependencies>\n";
506 for (
const QString &dep : deps)
507 t <<
"<dependency catalog=\"" << dep <<
"\"/>\n";
508 t <<
"</dependencies>\n";
511 QRegularExpression drops(QRegularExpression::anchoredPattern(cd.dropTags().join(QLatin1Char(
'|'))));
513 writeExtras(t,
" ", translator
.extras(), drops);
515 QHash<QString, QList<TranslatorMessage> > messageOrder;
516 QList<QString> contextOrder;
517 for (
const TranslatorMessage &msg : translator.messages()) {
519 if ((msg.type() == TranslatorMessage::Obsolete || msg.type() == TranslatorMessage::Vanished)
520 && msg.translation().isEmpty()) {
524 QList<TranslatorMessage> &context = messageOrder[msg.context()];
525 if (context.isEmpty())
526 contextOrder.append(msg.context());
530 std::sort(contextOrder.begin(), contextOrder.end());
532 QHash<QString,
int> currentLine;
534 for (
const QString &context : std::as_const(contextOrder)) {
537 << tsProtect(context)
539 for (
const TranslatorMessage &msg : std::as_const(messageOrder[context])) {
543 if (!msg.id().isEmpty())
544 t <<
" id=\"" << tsProtect(msg.id()) <<
"\"";
546 t <<
" numerus=\"yes\"";
548 if (translator.locationsType() != Translator::NoLocations) {
549 QString cfile = currentFile;
551 for (
const TranslatorMessage::Reference &ref : msg.allReferences()) {
552 QString fn = cd.m_targetDir.relativeFilePath(ref.fileName())
553 .replace(QLatin1Char(
'\\'),QLatin1Char(
'/'));
554 int ln = ref.lineNumber();
556 if (translator.locationsType() == Translator::RelativeLocations) {
558 int dlt = ln - currentLine[fn];
560 ld.append(QLatin1Char(
'+'));
561 ld.append(QString::number(dlt));
562 currentLine[fn] = ln;
575 ld = QString::number(ln);
579 t <<
" filename=\"" << fn <<
"\"";
581 t <<
" line=\"" << ld <<
"\"";
587 << tsProtect(msg.sourceText())
590 if (!msg.oldSourceText().isEmpty())
591 t <<
" <oldsource>" << tsProtect(msg.oldSourceText()) <<
"</oldsource>\n";
593 if (!msg.comment().isEmpty()) {
595 << tsProtect(msg.comment())
599 if (!msg.oldComment().isEmpty())
600 t <<
" <oldcomment>" << tsProtect(msg.oldComment()) <<
"</oldcomment>\n";
602 if (!msg.extraComment().isEmpty())
603 t <<
" <extracomment>" << tsProtect(msg.extraComment())
604 <<
"</extracomment>\n";
606 if (!msg.translatorComment().isEmpty())
607 t <<
" <translatorcomment>" << tsProtect(msg.translatorComment())
608 <<
"</translatorcomment>\n";
610 t <<
" <translation";
611 if (msg.type() == TranslatorMessage::Unfinished)
612 t <<
" type=\"unfinished\"";
613 else if (msg.type() == TranslatorMessage::Vanished)
614 t <<
" type=\"vanished\"";
615 else if (msg.type() == TranslatorMessage::Obsolete)
616 t <<
" type=\"obsolete\"";
617 if (msg.isPlural()) {
619 const QStringList &translns = msg.translations();
620 for (
int j = 0; j < translns.size(); ++j) {
621 t <<
"\n <numerusform";
622 writeVariants(t,
" ", translns[j]);
623 t <<
"</numerusform>";
627 writeVariants(t,
" ", msg.translation());
629 t <<
"</translation>\n";
631 writeExtras(t,
" ", msg.extras(), drops);
633 if (!msg.userData().isEmpty())
634 t <<
" <userdata>" << msg.userData() <<
"</userdata>\n";
635 t <<
" </message>\n";