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
metastrings.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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 "metastrings.h"
5
6#include <QFileInfo>
7
8namespace {
9using namespace Qt::Literals::StringLiterals;
10
11static constexpr QLatin1StringView PlaceholderClass = "<class>"_L1;
12static constexpr QLatin1StringView PlaceholderContext = "<context>"_L1;
13static constexpr QLatin1StringView PlaceholderFile = "<file>"_L1;
14static constexpr QLatin1StringView UnnamedPlaceholder = "<unnamed>"_L1;
15
16static constexpr QLatin1String CppMagicComment = "TRANSLATOR"_L1;
17} // namespace
18
20
21bool MetaStrings::parse(QString &string)
22{
23 const QChar *ptr = string.unicode();
24 if (*ptr == extraCommentAnotation && ptr[1].isSpace()) {
25 string.remove(0, 2);
26 m_extracomment += string;
27 if (!m_extracomment.endsWith(u'\n'))
28 m_extracomment.push_back(u'\n');
29 m_extracomment.detach();
30 } else if (*ptr == idAnotation && ptr[1].isSpace()) {
31 string.remove(0, 2);
32 m_msgid = string.simplified();
33 m_msgid.detach();
34 m_error =
35 "Setting translation IDs using //= or #= is deprecated and will be removed in the upcoming versions.\n"_L1;
36 } else if (*ptr == extraAnotation && ptr[1].isSpace()) {
37 string.remove(0, 2);
38 const QString trimmed = string.trimmed();
39 int k = trimmed.indexOf(u' ');
40 if (k > -1) {
41 QString commentvalue = trimmed.mid(k + 1).trimmed();
42 if (commentvalue.startsWith(u'"') && commentvalue.endsWith(u'"')
43 && commentvalue.size() != 1) {
44 commentvalue = commentvalue.sliced(1, commentvalue.size() - 2);
45 }
46 m_extra.insert(trimmed.left(k), commentvalue);
47 }
48 } else if (*ptr == sourceTextAnotation && ptr[1].isSpace()) {
49 m_sourcetext.reserve(m_sourcetext.size() + string.size() - 2);
50 ushort *ptr = (ushort *)m_sourcetext.data() + m_sourcetext.size();
51 int p = 2, c;
52 forever {
53 if (p >= string.size())
54 break;
55 c = string.unicode()[p++].unicode();
56 if (isspace(c))
57 continue;
58 if (c != '"') {
59 m_error = "Unexpected character in meta string\n"_L1;
60 break;
61 }
62 forever {
63 if (p >= string.size()) {
64 whoops:
65 m_error = "Unterminated meta string\n"_L1;
66 break;
67 }
68 c = string.unicode()[p++].unicode();
69 if (c == '"')
70 break;
71 if (c == '\\') {
72 if (p >= string.size())
73 goto whoops;
74 c = string.unicode()[p++].unicode();
75 if (c == '\n')
76 goto whoops;
77 *ptr++ = '\\';
78 }
79 *ptr++ = c;
80 }
81 }
82 m_sourcetext.resize(ptr - (ushort *)m_sourcetext.data());
83 } else if (*ptr == labelAnotation && ptr[1].isSpace()) {
84 string.remove(0, 2);
85 m_label = string.trimmed().simplified();
86 m_label.detach();
87 } else if (const QString trimmed = string.trimmed(); trimmed.startsWith(CppMagicComment)) {
88 qsizetype idx = CppMagicComment.size();
89 QString comment =
90 QString::fromRawData(trimmed.unicode() + idx, trimmed.size() - idx).simplified();
91 if (int k = comment.indexOf(u' '); k != -1) {
92 QString context = comment.left(k);
93 comment.remove(0, k + 1);
94 m_magicComment.emplace(MagicComment{ std::move(context), std::move(comment) });
95 }
96 }
97
98 return m_error.isEmpty();
99}
100
101bool MetaStrings::resolveLabel(const QString &filename, const QString &context,
102 const QString &className)
103{
104 if (m_label.contains(PlaceholderClass)) {
105 QString classStr = className;
106 if (classStr.isEmpty()) {
107 classStr = UnnamedPlaceholder;
108 m_error =
109 "Label placeholder <class> used, but no class available. Using <unnamed>.\n"_L1;
110 }
111 m_label.replace(PlaceholderClass, classStr);
112 }
113
114 if (m_label.contains(PlaceholderContext)) {
115 QString contextStr = context;
116 if (contextStr.isEmpty()) {
117 contextStr = UnnamedPlaceholder;
118 m_error +=
119 "Label placeholder <context> used, but no context available. Using <unnamed>.\n"_L1;
120 }
121 m_label.replace(PlaceholderContext, contextStr);
122 }
123
124 if (m_label.contains(PlaceholderFile))
125 m_label.replace(PlaceholderFile, QFileInfo(filename).fileName());
126
127 return m_error.isEmpty();
128}
129
131{
132 m_magicComment.reset();
133 m_extracomment.clear();
134 m_msgid.clear();
135 m_label.clear();
136 m_sourcetext.clear();
137 m_extra.clear();
138}
139
140bool MetaStrings::hasData() const
141{
142 return !m_msgid.isEmpty() || m_magicComment || !m_sourcetext.isEmpty()
143 || !m_extracomment.isEmpty() || !m_extra.isEmpty() || !m_label.isEmpty();
144}
145
146QT_END_NAMESPACE
bool parse(QString &string)
bool resolveLabel(const QString &filename, const QString &context, const QString &className=QString())
bool hasData() const