Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qph.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "translator.h"
5
6#include <QtCore/QByteArray>
7#include <QtCore/QDebug>
8#include <QtCore/QTextStream>
9
10#include <QtCore/QXmlStreamReader>
11
13
14using namespace Qt::Literals::StringLiterals;
15
17{
18public:
19 QPHReader(QIODevice &dev)
21 {}
22
23 // the "real thing"
24 bool read(Translator &translator);
25
26private:
27 bool isWhiteSpace() const
28 {
29 return isCharacters() && text().toString().trimmed().isEmpty();
30 }
31
32 enum DataField { NoField, SourceField, TargetField, DefinitionField };
33 DataField m_currentField;
34 QString m_currentSource;
35 QString m_currentTarget;
36 QString m_currentDefinition;
37};
38
39bool QPHReader::read(Translator &translator)
40{
41 m_currentField = NoField;
42 while (!atEnd()) {
43 readNext();
44 if (isStartElement()) {
45 if (name() == "source"_L1) {
46 m_currentField = SourceField;
47 } else if (name() == "target"_L1) {
48 m_currentField = TargetField;
49 } else if (name() == "definition"_L1) {
50 m_currentField = DefinitionField;
51 } else {
52 m_currentField = NoField;
53 if (name() == "QPH"_L1) {
54 QXmlStreamAttributes atts = attributes();
55 translator.setLanguageCode(atts.value("language"_L1).toString());
56 translator.setSourceLanguageCode(atts.value("sourcelanguage"_L1).toString());
57 }
58 }
59 } else if (isWhiteSpace()) {
60 // ignore these
61 } else if (isCharacters()) {
62 if (m_currentField == SourceField)
63 m_currentSource += text();
64 else if (m_currentField == TargetField)
65 m_currentTarget += text();
66 else if (m_currentField == DefinitionField)
67 m_currentDefinition += text();
68 } else if (isEndElement() && name() == "phrase"_L1) {
69 m_currentTarget.replace(Translator::TextVariantSeparator, Translator::BinaryVariantSeparator);
71 msg.setSourceText(m_currentSource);
72 msg.setTranslation(m_currentTarget);
73 msg.setComment(m_currentDefinition);
74 translator.append(msg);
75 m_currentSource.clear();
76 m_currentTarget.clear();
77 m_currentDefinition.clear();
78 }
79 }
80 return true;
81}
82
83static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &)
84{
86 QPHReader reader(dev);
87 return reader.read(translator);
88}
89
90static QString qphProtect(const QString &str)
91{
92 QString result;
93 result.reserve(str.size() * 12 / 10);
94 for (int i = 0; i != str.size(); ++i) {
95 uint c = str.at(i).unicode();
96 switch (c) {
97 case '\"':
98 result += "&quot;"_L1;
99 break;
100 case '&':
101 result += "&amp;"_L1;
102 break;
103 case '>':
104 result += "&gt;"_L1;
105 break;
106 case '<':
107 result += "&lt;"_L1;
108 break;
109 case '\'':
110 result += "&apos;"_L1;
111 break;
112 default:
113 if (c < 0x20 && c != '\r' && c != '\n' && c != '\t')
114 result += QString("&#%1;"_L1).arg(c);
115 else // this also covers surrogates
116 result += QChar(c);
117 }
118 }
119 return result;
120}
121
122static bool saveQPH(const Translator &translator, QIODevice &dev, ConversionData &)
123{
124 QTextStream t(&dev);
125 t << "<!DOCTYPE QPH>\n<QPH";
126 QString languageCode = translator.languageCode();
127 if (!languageCode.isEmpty() && languageCode != "C"_L1)
128 t << " language=\"" << languageCode << "\"";
129 languageCode = translator.sourceLanguageCode();
130 if (!languageCode.isEmpty() && languageCode != "C"_L1)
131 t << " sourcelanguage=\"" << languageCode << "\"";
132 t << ">\n";
133 for (const TranslatorMessage &msg : translator.messages()) {
134 t << "<phrase>\n";
135 t << " <source>" << qphProtect(msg.sourceText()) << "</source>\n";
136 QString str = msg.translations().join(u'@');
137 str.replace(QChar(Translator::BinaryVariantSeparator),
138 QChar(Translator::TextVariantSeparator));
139 t << " <target>" << qphProtect(str)
140 << "</target>\n";
141 if (!msg.comment().isEmpty())
142 t << " <definition>" << qphProtect(msg.comment()) << "</definition>\n";
143 t << "</phrase>\n";
144 }
145 t << "</QPH>\n";
146 return true;
147}
148
150{
151 Translator::FileFormat format;
152
153 format.extension = "qph"_L1;
154 format.untranslatedDescription = QT_TRANSLATE_NOOP("FMT", "Qt Linguist 'Phrase Book'");
156 format.priority = 0;
157 format.loader = &loadQPH;
158 format.saver = &saveQPH;
160
161 return 1;
162}
163
164Q_CONSTRUCTOR_FUNCTION(initQPH)
165
166QT_END_NAMESPACE
bool read(Translator &translator)
Definition qph.cpp:39
QPHReader(QIODevice &dev)
Definition qph.cpp:19
static void registerFileFormat(const FileFormat &format)
void append(const TranslatorMessage &msg)
void setLocationsType(LocationsType lt)
Definition translator.h:125
Combined button and popup list for selecting options.
static bool saveQPH(const Translator &translator, QIODevice &dev, ConversionData &)
Definition qph.cpp:122
static QString qphProtect(const QString &str)
Definition qph.cpp:90
static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &)
Definition qph.cpp:83
int initQPH()
Definition qph.cpp:149
const char * untranslatedDescription
Definition translator.h:166