6#ifndef LINGUIST_CONSOLE_APPLICATION
12using namespace Qt::Literals::StringLiterals;
16static QString leadingWhitespace(
const QString &str)
19 for (; i < str.size(); i++) {
20 if (!str[i].isSpace()) {
27static QString trailingWhitespace(
const QString &str)
31 if (!str[i].isSpace()) {
35 return str.mid(i + 1);
40 str = str.simplified();
44 switch (str.at(str.size() - 1).unicode()) {
46 if (str.endsWith(
"..."_L1))
70 return lang == QLocale::Greek ? Validator::End_Interrobang : Validator::End_None;
81static bool haveMnemonic(
const QString &str)
83 for (
const ushort *p = (ushort *)str.constData();;) {
94 if (c !=
'&' && c !=
' ' && c !=
'#' && QChar(c).isPrint()) {
96 for (; *p < 256 && isalpha(*p); p++)
98 if (pp == p || *p !=
';')
109static QHash<
int,
int> countPlaceMarkers(
const QString &str)
111 QHash<
int,
int> counts;
112 const QChar *c = str.unicode();
113 const QChar *cend = c + str.size();
115 if (c->unicode() ==
'%') {
116 const QChar *escape_start = ++c;
119 const QChar *escape_end = c;
122 QString::fromRawData(escape_start, escape_end - escape_start).toInt(&ok);
124 counts[markerIndex]++;
134 const QLocale::Language &locale,
135 const QHash<QString, QList<Phrase *>> &phrases)
139 if (checks.accelerator)
140 v.m_haveMnemonic.emplace(haveMnemonic(source));
141 if (checks.punctuation)
142 v.m_ending.emplace(ending(source, locale));
143 if (checks.placeMarker)
144 v.m_placeMarkerCounts.emplace(countPlaceMarkers(source));
146 v.m_leadingWhiteSpace.emplace(leadingWhitespace(source));
147 v.m_trailingWhiteSpace.emplace(trailingWhitespace(source));
149#ifndef LINGUIST_CONSOLE_APPLICATION
151 v.m_matchingPhraseTargets.emplace();
152 QString fsource = friendlyString(source);
153 QStringList lookupWords = fsource.split(QLatin1Char(
' '));
155 for (
const QString &s : std::as_const(lookupWords))
156 if (
auto wordPhrases = phrases.find(s); wordPhrases != phrases.constEnd())
157 for (
const Phrase *p : *wordPhrases)
158 if (fsource == friendlyString(p->source()))
159 v.m_matchingPhraseTargets.value()[s].append(friendlyString(p->target()));
167 const QLocale::Language &locale,
168 QList<
bool> countRefNeeds)
171 QMap<ErrorType, QString> errors;
172 for (QStringView translation : std::as_const(translations)) {
173 while (!translation.isEmpty()) {
174 auto sep = translation.indexOf(Translator::BinaryVariantSeparator);
176 sep = translation.size();
177 const QString trans = translation.first(sep).toString();
179 const bool needsRef = msg.isPlural() && countRefNeeds.at(i);
180 errors.insert(validateTranslation(trans, locale, needsRef));
181 translation.slice(std::min(sep + 1, translation.size()));
188QMap<Validator::ErrorType, QString>
Validator::validateTranslation(
const QString &translation,
189 const QLocale::Language &locale,
192 QMap<ErrorType, QString> errors;
193 if (m_haveMnemonic && *m_haveMnemonic != haveMnemonic(translation))
194 errors.insert(*m_haveMnemonic ? MissingAccelerator : SuperfluousAccelerator, translation);
195 if (m_placeMarkerCounts) {
196 if (*m_placeMarkerCounts != countPlaceMarkers(translation))
198 if (needsRef && !translation.contains(QLatin1String(
"%n"))
199 && !translation.contains(QLatin1String(
"%Ln")))
202 if (m_ending && *m_ending != ending(translation, locale))
205 if (m_leadingWhiteSpace
206 && (*m_leadingWhiteSpace != leadingWhitespace(translation)
207 || *m_trailingWhiteSpace != trailingWhitespace(translation)))
209#ifndef LINGUIST_CONSOLE_APPLICATION
210 if (m_matchingPhraseTargets) {
211 const QString ftranslation = friendlyString(translation);
212 for (
auto itr = m_matchingPhraseTargets->cbegin(); itr != m_matchingPhraseTargets->cend();
215 for (
const QString &target : itr.value()) {
216 if (ftranslation.indexOf(target) >= 0) {
bool surroundingWhiteSpace
QMap< ErrorType, QString > validate(QStringList translations, const TranslatorMessage &msg, const QLocale::Language &locale, QList< bool > countRefNeeds)
@ SurroundingWhitespaceDiffers