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
translationutils.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
5
6#include <QtCore/qjsonarray.h>
7#include <QtCore/qjsondocument.h>
8#include <QtCore/qjsonobject.h>
9
10#include <optional>
11
12using namespace Qt::Literals::StringLiterals;
13
14static std::optional<QJsonArray> findJsonArray(const QJsonValue &jval, const QString &key)
15{
16 if (jval.isObject()) {
17 const QJsonObject obj = jval.toObject();
18 auto it = obj.find(key);
19 if (it != obj.end() && it->isArray())
20 return it->toArray();
21 for (it = obj.constBegin(); it != obj.constEnd(); ++it) {
22 if (it.key().trimmed() == key && it.value().isArray())
23 return it.value().toArray();
24 if (const auto r = findJsonArray(it.value(), key); r)
25 return r;
26 }
27 } else if (jval.isArray()) {
28 const QJsonArray arr = jval.toArray();
29 for (const QJsonValue &element : arr)
30 if (const auto r = findJsonArray(element, key); r)
31 return r;
32 } else if (jval.isString()) {
33 QString str = jval.toString();
34 const int startIdx = str.indexOf('{'_L1);
35 const int endIdx = str.lastIndexOf('}'_L1);
36 if (startIdx < 0 || endIdx < 0)
37 return {};
38 str.slice(startIdx, endIdx - startIdx + 1);
39 QJsonParseError err;
40 auto inner = QJsonDocument::fromJson(str.toUtf8(), &err);
41 if (err.error != QJsonParseError::NoError || !inner.isObject())
42 return {};
43 const auto obj = inner.object();
44 if (auto it = obj.find(key); it != obj.end()) {
45 if (it.value().isArray())
46 return it.value().toArray();
47 }
48 }
49 return {};
50}
51
52QT_BEGIN_NAMESPACE
53
54QHash<QString, QString> extractKeyValuePairs(const QJsonValue &jval, const QString &arrayKey)
55{
56 auto array = findJsonArray(jval, arrayKey);
57 if (!array)
58 return {};
59
60 QHash<QString, QString> out;
61 out.reserve(array->size());
62 for (const QJsonValue &v : std::as_const(*array)) {
63 if (v.isObject()) {
64 const QJsonObject obj = v.toObject();
65 for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
66 if (it.value().isString())
67 out[it.key()] = it.value().toString();
68 }
69 }
70 }
71 return out;
72}
73
75 const QString &arrayKey)
76{
77 auto array = findJsonArray(jval, arrayKey);
78 if (!array)
79 return {};
80
81 QHash<QString, QStringList> out;
82 out.reserve(array->size());
83 for (const QJsonValue &v : std::as_const(*array)) {
84 if (v.isObject()) {
85 const QJsonObject obj = v.toObject();
86 for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
87 if (it.value().isArray()) {
88 QStringList forms;
89 const QJsonArray arr = it.value().toArray();
90 forms.reserve(arr.size());
91 for (const QJsonValue &form : arr) {
92 if (form.isString())
93 forms.append(form.toString());
94 }
95 if (!forms.isEmpty())
96 out[it.key()] = forms;
97 }
98 }
99 }
100 }
101 return out;
102}
103
105{
106 static QString systemPrompt = uR"(
107You are a professional software translator specialized in Qt UI strings.
108
109When given a list of items of the given 'Context', each may include:
110- source: the original text to translate
111- comment: an optional developer note for more context
112
113If "Application Context" is provided, use it to understand the domain and terminology
114appropriate for the application (e.g., medical, financial, gaming) to produce more
115accurate and contextually appropriate translations.
116
117Translate the items into the **target language** specified by the user,
118preserving keyboard accelerators (e.g. "&File"), placeholders (e.g. "%1"),
119and ending punctuation.
120
121RESULT FORMAT (MUST FOLLOW):
122A single JSON object with one key, "Translations",
123whose value is an array of objects.
124Each object maps the original source string to translated string:
125
126Two examples:
127
128Input:
129Context: MainWindow
130Target: German
131Items:
132 - source: "File"
133 - source: "Exit"
134 - source: "&Open", comment: "opens a document"
135
136Output:
137{"Translations":[{"File":"Datei"},{"Exit":"Beenden"},{"&Open":"&Öffnen"}]}
138
139Input:
140Context: MainWindow
141Target: French
142Items:
143– source: "File"
144– source: "Exit"
145Output:
146{"Translations":[{"File":"Fichier"},{"Exit":"Quitter"}]}
147
148Return **only** valid JSON, no code fences, no extra text.
149After generating and before returning, verify:
1501. Every string is in the target language; if any aren't, correct them before returning.
1512. Every JSON key exactly matches one of the input source strings.
1523. No key equals its value.
1534. Every string is translated
154)"_s;
155
156 return systemPrompt;
157}
158
160{
161 static QString systemPrompt = uR"PROMPT(
162You are a professional software translator specialized in Qt UI strings with plural forms.
163
164When given a list of items, each may include:
165- source: the original text to translate (contains a placeholder like %n for the count)
166- comment: an optional developer note for more context
167
168The user will specify:
169- The target language
170- The number of plural forms required for that language
171
172You must provide exactly the specified number of plural forms for each source string.
173Each plural form corresponds to different grammatical number categories
174(e.g., "one", "few", "many", "other" depending on the language).
175
176Preserve keyboard accelerators (e.g. "&File"), placeholders (e.g. "%1", "%n"),
177and ending punctuation in all plural forms.
178
179RESULT FORMAT (MUST FOLLOW):
180A single JSON object with one key, "Plurals",
181whose value is an array of objects.
182Each object maps the original source string to an array of translated plural forms:
183
184Example for German (2 plural forms):
185
186Input:
187Target: German
188Plural forms: 2
189Items:
190 - source: "%n file(s) selected"
191 - source: "%n item(s) deleted"
192
193Output:
194{"Plurals":[{"%n file(s) selected":["%n Datei ausgewählt","%n Dateien ausgewählt"]},{"%n item(s) deleted":["%n Element gelöscht","%n Elemente gelöscht"]}]}
195
196Example for Polish (3 plural forms):
197
198Input:
199Target: Polish
200Plural forms: 3
201Items:
202 - source: "%n file(s)"
203
204Output:
205{"Plurals":[{"%n file(s)":["%n plik","%n pliki","%n plików"]}]}
206
207Return **only** valid JSON, no code fences, no extra text.
208After generating and before returning, verify:
2091. Every string is in the target language.
2102. Every JSON key exactly matches one of the input source strings.
2113. Each source has exactly the specified number of plural forms.
2124. The %n placeholder is preserved in all forms.
213)PROMPT"_s;
214
215 return systemPrompt;
216}
217
218QT_END_NAMESPACE
static std::optional< QJsonArray > findJsonArray(const QJsonValue &jval, const QString &key)
QHash< QString, QStringList > extractPluralTranslations(const QJsonValue &jval, const QString &arrayKey)
QString translationSystemPrompt()
QString pluralTranslationSystemPrompt()