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
qlocale.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6#include "qglobal.h"
7
8#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1000
9/* gcc has complained about storing a pointer to a static QLocalePrivate in a
10 QSharedDataPointer, whose destructor would free the non-heap object if the
11 refcount ever got down to zero. The static instances this happens to are
12 instantiated with a refcount of 1 that never gets decremented so as long as
13 QSharedDataPointer keeps its incref()s and decref()s balanced it'll never get
14 down to zero - but the clever compiler isn't quite smart enough to figure
15 that out.
16*/
17QT_WARNING_DISABLE_GCC("-Wfree-nonheap-object") // false positive tracking
18#endif
19
20#if defined(Q_OS_MACOS)
21# include "private/qcore_mac_p.h"
22# include <CoreFoundation/CoreFoundation.h>
23#endif
24
25#include "qplatformdefs.h"
26
27#include "qcalendar.h"
28#include "qdatastream.h"
29#include "qdebug.h"
30#include "private/qduplicatetracker_p.h"
31#include "qhashfunctions.h"
32#include "qstring.h"
34#include "qlocale.h"
35#include "qlocale_p.h"
37#include <private/qtools_p.h>
38#if QT_CONFIG(datetimeparser)
39#include "private/qdatetimeparser_p.h"
40#endif
41#include "qnamespace.h"
42#include "qdatetime.h"
43#include "qstringlist.h"
44#include "qvariant.h"
46#include "qstringbuilder.h"
47#if QT_CONFIG(timezone)
48# include "qtimezone.h"
49#endif
50#include "private/qnumeric_p.h"
51#include "private/qtools_p.h"
52#include <cmath>
53#ifndef QT_NO_SYSTEMLOCALE
54# include "qmutex.h"
55#endif
56#ifdef Q_OS_WIN
57# include <qt_windows.h>
58# include <time.h>
59#endif
60
61#include "private/qcalendarbackend_p.h"
62#include "private/qgregoriancalendar_p.h"
63#if QT_CONFIG(timezone) && QT_CONFIG(timezone_locale) && !QT_CONFIG(icu)
64# include "private/qtimezonelocale_p.h"
65#endif
66#if QT_CONFIG(datestring)
67# include "private/qttemporalpattern_p.h"
68#endif
69
70#include <q20iterator.h>
71
73
74constexpr int QLocale::DefaultTwoDigitBaseYear;
75
76QT_IMPL_METATYPE_EXTERN_TAGGED(QList<Qt::DayOfWeek>, QList_Qt__DayOfWeek)
77#ifndef QT_NO_SYSTEMLOCALE
78QT_IMPL_METATYPE_EXTERN_TAGGED(QSystemLocale::CurrencyToStringArgument,
79 QSystemLocale__CurrencyToStringArgument)
80#endif
81
82using namespace Qt::StringLiterals;
83using namespace QtMiscUtils;
84
85#ifndef QT_NO_SYSTEMLOCALE
86Q_CONSTINIT static QSystemLocale *_systemLocale = nullptr;
87Q_CONSTINIT static QLocaleData systemLocaleData = {};
88#endif
89
90static_assert(ascii_isspace(' '));
91static_assert(ascii_isspace('\t'));
92static_assert(ascii_isspace('\n'));
93static_assert(ascii_isspace('\v'));
94static_assert(ascii_isspace('\f'));
95static_assert(ascii_isspace('\r'));
96static_assert(!ascii_isspace('\0'));
97static_assert(!ascii_isspace('\a'));
98static_assert(!ascii_isspace('a'));
99static_assert(!ascii_isspace('\177'));
100static_assert(!ascii_isspace(uchar('\200')));
101static_assert(!ascii_isspace(uchar('\xA0'))); // NBSP (is a space but Latin 1, not ASCII)
102static_assert(!ascii_isspace(uchar('\377')));
103
104/******************************************************************************
105** Helpers for accessing Qt locale database
106*/
107
108QT_BEGIN_INCLUDE_NAMESPACE
109#include "qlocale_data_p.h"
110QT_END_INCLUDE_NAMESPACE
111
112QLocale::Language QLocalePrivate::codeToLanguage(QStringView code,
113 QLocale::LanguageCodeTypes codeTypes) noexcept
114{
115 const auto len = code.size();
116 if (len != 2 && len != 3)
117 return QLocale::AnyLanguage;
118
119 const char16_t uc1 = code[0].toLower().unicode();
120 const char16_t uc2 = code[1].toLower().unicode();
121 const char16_t uc3 = len > 2 ? code[2].toLower().unicode() : 0;
122
123 // All language codes are ASCII.
124 if (uc1 > 0x7F || uc2 > 0x7F || uc3 > 0x7F)
125 return QLocale::AnyLanguage;
126
127 const AlphaCode codeBuf = { char(uc1), char(uc2), char(uc3) };
128
129 auto searchCode = [codeBuf](auto f) {
130 return std::find_if(languageCodeList.begin(), languageCodeList.end(),
131 [=](LanguageCodeEntry i) { return f(i) == codeBuf; });
132 };
133
134 if (codeTypes.testFlag(QLocale::ISO639Part1) && uc3 == 0) {
135 auto i = searchCode([](LanguageCodeEntry i) { return i.part1; });
136 if (i != languageCodeList.end())
137 return QLocale::Language(std::distance(languageCodeList.begin(), i));
138 }
139
140 if (uc3 != 0) {
141 if (codeTypes.testFlag(QLocale::ISO639Part2B)) {
142 auto i = searchCode([](LanguageCodeEntry i) { return i.part2B; });
143 if (i != languageCodeList.end())
144 return QLocale::Language(std::distance(languageCodeList.begin(), i));
145 }
146
147 // Optimization: Part 2T code if present is always the same as Part 3 code.
148 // This is asserted in iso639_3.LanguageCodeData.
149 if (codeTypes.testFlag(QLocale::ISO639Part2T)
150 && !codeTypes.testFlag(QLocale::ISO639Part3)) {
151 auto i = searchCode([](LanguageCodeEntry i) { return i.part2T; });
152 if (i != languageCodeList.end())
153 return QLocale::Language(std::distance(languageCodeList.begin(), i));
154 }
155
156 if (codeTypes.testFlag(QLocale::ISO639Part3)) {
157 auto i = searchCode([](LanguageCodeEntry i) { return i.part3; });
158 if (i != languageCodeList.end())
159 return QLocale::Language(std::distance(languageCodeList.begin(), i));
160 }
161 }
162
163 if (codeTypes.testFlag(QLocale::LegacyLanguageCode) && uc3 == 0) {
164 constexpr struct LegacyCodes {
165 AlphaCode code;
166 QLocale::Language language;
167 } legacyCodes[] = {
168 { {'n', 'o'}, QLocale::NorwegianBokmal }, // no -> nb
169 { {'t', 'l'}, QLocale::Filipino }, // tl -> fil
170 { {'s', 'h'}, QLocale::Serbian }, // sh -> sr[_Latn]
171 { {'m', 'o'}, QLocale::Romanian }, // mo -> ro
172 // Android uses the following deprecated codes:
173 { {'i', 'w'}, QLocale::Hebrew }, // iw -> he
174 { {'i', 'n'}, QLocale::Indonesian }, // in -> id
175 { {'j', 'i'}, QLocale::Yiddish }, // ji -> yi
176 };
177 // We don't need binary search for seven entries (and they're not
178 // sorted), so search linearly:
179 for (const auto &e : legacyCodes) {
180 if (codeBuf == e.code)
181 return e.language;
182 }
183 }
184 return QLocale::AnyLanguage;
185}
186
187static qsizetype scriptIndex(QStringView code, Qt::CaseSensitivity cs) noexcept
188{
189 if (code.size() != 4)
190 return -1;
191
192 // Scripts are titlecased in script_code_list.
193 const bool fixCase = cs == Qt::CaseInsensitive;
194 const unsigned char c0 = (fixCase ? code[0].toUpper() : code[0]).toLatin1();
195 const unsigned char c1 = (fixCase ? code[1].toLower() : code[1]).toLatin1();
196 const unsigned char c2 = (fixCase ? code[2].toLower() : code[2]).toLatin1();
197 const unsigned char c3 = (fixCase ? code[3].toLower() : code[3]).toLatin1();
198 // Any outside the Latin1 repertoire aren't ASCII => will not match.
199 if (!c0 || !c1 || !c2 || !c3)
200 return -1;
201
202 constexpr qsizetype NumScripts = QLocale::LastScript + 1;
203 static_assert(sizeof(script_code_list) == 4 * NumScripts + 1); // +1 for an extra NUL
204 const unsigned char *c = script_code_list;
205 for (qsizetype i = 0; i < NumScripts; ++i, c += 4) {
206 if (c0 == c[0] && c1 == c[1] && c2 == c[2] && c3 == c[3])
207 return i;
208 }
209 return -1;
210}
211
212QLocale::Script QLocalePrivate::codeToScript(QStringView code) noexcept
213{
214 qsizetype index = scriptIndex(code, Qt::CaseInsensitive);
215 return index < 0 ? QLocale::AnyScript : QLocale::Script(index);
216}
217
218QLocale::Territory QLocalePrivate::codeToTerritory(QStringView code) noexcept
219{
220 const auto len = code.size();
221 if (len != 2 && len != 3)
222 return QLocale::AnyTerritory;
223
224 char16_t uc1 = code[0].toUpper().unicode();
225 char16_t uc2 = code[1].toUpper().unicode();
226 char16_t uc3 = len > 2 ? code[2].toUpper().unicode() : 0;
227
228 const unsigned char *c = territory_code_list;
229 for (; *c != 0; c += 3) {
230 if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2])
231 return QLocale::Territory((c - territory_code_list)/3);
232 }
233
234 return QLocale::AnyTerritory;
235}
236
237std::array<char, 4> QLocalePrivate::languageToCode(QLocale::Language language,
238 QLocale::LanguageCodeTypes codeTypes)
239{
240 if (language == QLocale::AnyLanguage || language > QLocale::LastLanguage)
241 return {};
242 if (language == QLocale::C)
243 return {'C'};
244
245 const LanguageCodeEntry &i = languageCodeList[language];
246
247 if (codeTypes.testFlag(QLocale::ISO639Part1) && i.part1.isValid())
248 return i.part1.decode();
249
250 if (codeTypes.testFlag(QLocale::ISO639Part2B) && i.part2B.isValid())
251 return i.part2B.decode();
252
253 if (codeTypes.testFlag(QLocale::ISO639Part2T) && i.part2T.isValid())
254 return i.part2T.decode();
255
256 if (codeTypes.testFlag(QLocale::ISO639Part3))
257 return i.part3.decode();
258
259 return {};
260}
261
262QLatin1StringView QLocalePrivate::scriptToCode(QLocale::Script script)
263{
264 if (script == QLocale::AnyScript || script > QLocale::LastScript)
265 return {};
266 const unsigned char *c = script_code_list + 4 * script;
267 return {reinterpret_cast<const char *>(c), 4};
268}
269
270QLatin1StringView QLocalePrivate::territoryToCode(QLocale::Territory territory)
271{
272 if (territory == QLocale::AnyTerritory || territory > QLocale::LastTerritory)
273 return {};
274
275 const unsigned char *c = territory_code_list + 3 * territory;
276 return {reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3};
277}
278
279namespace {
280struct LikelyPair
281{
282 QLocaleId key; // Search key.
283 QLocaleId value = QLocaleId { 0, 0, 0 };
284};
285
286bool operator<(LikelyPair lhs, LikelyPair rhs)
287{
288 // Must match the comparison LocaleDataWriter.likelySubtags() uses when
289 // sorting, see qtbase/util/locale_database.qlocalexml2cpp.py
290 const auto compare = [](int lhs, int rhs) {
291 // 0 sorts after all other values; lhs and rhs are passed ushort values.
292 const int huge = 0x10000;
293 return (lhs ? lhs : huge) - (rhs ? rhs : huge);
294 };
295 const auto &left = lhs.key;
296 const auto &right = rhs.key;
297 // Comparison order: language, region, script:
298 if (int cmp = compare(left.language_id, right.language_id))
299 return cmp < 0;
300 if (int cmp = compare(left.territory_id, right.territory_id))
301 return cmp < 0;
302 return compare(left.script_id, right.script_id) < 0;
303}
304} // anonymous namespace
305
306/*!
307 \internal
308 Fill in blank fields of a locale ID.
309
310 An ID in which some fields are zero stands for any locale that agrees with
311 it in its non-zero fields. CLDR's likely-subtag data is meant to help us
312 chose which candidate to prefer. (Note, however, that CLDR does have some
313 cases where it maps an ID to a "best match" for which CLDR does not provide
314 data, even though there are locales for which CLDR does provide data that do
315 match the given ID. It's telling us, unhelpfully but truthfully, what
316 locale would (most likely) be meant by (someone using) the combination
317 requested, even when that locale isn't yet supported.) It may also map an
318 obsolete or generic tag to a modern or more specific replacement, possibly
319 filling in some of the other fields in the process (presently only for
320 countries). Note that some fields of the result may remain blank, but there
321 is no more specific recommendation available.
322
323 For the formal specification, see
324 https://www.unicode.org/reports/tr35/#Likely_Subtags
325
326 \note We also search und_script_region and und_region; they're not mentioned
327 in the spec, but the examples clearly presume them and CLDR does provide
328 such likely matches.
329*/
331{
332 /* Each pattern that appears in a comments below, language_script_region and
333 similar, indicates which of this's fields (even if blank) are being
334 attended to in a given search; for fields left out of the pattern, the
335 search uses 0 regardless of whether this has specified the field.
336
337 If a key matches what we're searching for (possibly with a wildcard in
338 the key matching a non-wildcard in our search), the tags from this that
339 are specified in the key are replaced by the match (even if different);
340 but the other tags of this replace what's in the match (even when the
341 match does specify a value).
342
343 Keep QLocaleXmlReader.__fillLikely() in sync with this, to ensure
344 locale-appropriate time-zone naming works correctly.
345 */
346 static_assert(std::size(likely_subtags) % 2 == 0);
347 auto *pairs = reinterpret_cast<const LikelyPair *>(likely_subtags);
348 auto *const afterPairs = pairs + std::size(likely_subtags) / 2;
349 LikelyPair sought { *this };
350 // Our array is sorted in the order that puts all candidate matches in the
351 // order we would want them; ones we should prefer appear before the others.
352 if (language_id) {
353 // language_script_region, language_region, language_script, language:
354 pairs = std::lower_bound(pairs, afterPairs, sought);
355 // Single language's block isn't long enough to warrant more binary
356 // chopping within it - just traverse it all:
357 for (; pairs < afterPairs && pairs->key.language_id == language_id; ++pairs) {
358 const QLocaleId &key = pairs->key;
360 continue;
361 if (key.script_id && key.script_id != script_id)
362 continue;
363 QLocaleId value = pairs->value;
364 if (territory_id && !key.territory_id)
366 if (script_id && !key.script_id)
367 value.script_id = script_id;
368 return value;
369 }
370 }
371 // und_script_region or und_region (in that order):
372 if (territory_id) {
373 sought.key = QLocaleId { 0, script_id, territory_id };
374 pairs = std::lower_bound(pairs, afterPairs, sought);
375 // Again, individual und_?_region block isn't long enough to make binary
376 // chop a win:
377 for (; pairs < afterPairs && pairs->key.territory_id == territory_id; ++pairs) {
378 const QLocaleId &key = pairs->key;
379 Q_ASSERT(!key.language_id);
380 if (key.script_id && key.script_id != script_id)
381 continue;
382 QLocaleId value = pairs->value;
383 if (language_id)
385 if (script_id && !key.script_id)
386 value.script_id = script_id;
387 return value;
388 }
389 }
390 // und_script:
391 if (script_id) {
392 sought.key = QLocaleId { 0, script_id, 0 };
393 pairs = std::lower_bound(pairs, afterPairs, sought);
394 if (pairs < afterPairs && pairs->key.script_id == script_id) {
395 Q_ASSERT(!pairs->key.language_id && !pairs->key.territory_id);
396 QLocaleId value = pairs->value;
397 if (language_id)
399 if (territory_id)
401 return value;
402 }
403 }
404 // Finally, fall back to the match-all rule (if there is one):
405 pairs = afterPairs - 1; // All other keys are < match-all.
406 if (pairs->key.matchesAll()) {
407 QLocaleId value = pairs->value;
408 if (language_id)
410 if (territory_id)
412 if (script_id)
413 value.script_id = script_id;
414 return value;
415 }
416 return *this;
417}
418
420{
422 // language
423 {
424 QLocaleId id { language_id, 0, 0 };
426 return id;
427 }
428 // language_region
429 if (territory_id) {
432 return id;
433 }
434 // language_script
435 if (script_id) {
438 return id;
439 }
440 return max;
441}
442
443QByteArray QLocaleId::name(char separator) const
444{
445 if (language_id == QLocale::AnyLanguage)
446 return QByteArray();
447 if (language_id == QLocale::C)
448 return QByteArrayLiteral("C");
449 Q_ASSERT(language_id <= QLocale::LastLanguage);
450 Q_ASSERT(script_id <= QLocale::LastScript);
451 Q_ASSERT(territory_id <= QLocale::LastTerritory);
452
453 const LanguageCodeEntry &language = languageCodeList[language_id];
454 AlphaCode lang;
455 qsizetype langLen;
456
457 if (language.part1.isValid()) {
458 lang = language.part1;
459 langLen = 2;
460 } else {
461 lang = language.part2B.isValid() ? language.part2B : language.part3;
462 langLen = 3;
463 }
464
465 const unsigned char *script =
466 (script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : nullptr);
467 const unsigned char *country =
468 (territory_id != QLocale::AnyTerritory
469 ? territory_code_list + 3 * territory_id : nullptr);
470 qsizetype len = langLen + (script ? 4 + 1 : 0) + (country ? (country[2] != 0 ? 3 : 2) + 1 : 0);
471 QByteArray name(len, Qt::Uninitialized);
472 char *uc = name.data();
473
474 auto langArray = lang.decode();
475
476 *uc++ = langArray[0];
477 *uc++ = langArray[1];
478 if (langLen > 2)
479 *uc++ = langArray[2];
480
481 if (script) {
482 *uc++ = separator;
483 *uc++ = script[0];
484 *uc++ = script[1];
485 *uc++ = script[2];
486 *uc++ = script[3];
487 }
488 if (country) {
489 *uc++ = separator;
490 *uc++ = country[0];
491 *uc++ = country[1];
492 if (country[2] != 0)
493 *uc++ = country[2];
494 }
495 return name;
496}
497
498QByteArray QLocalePrivate::bcp47Name(char separator) const
499{
500 if (m_data->m_language_id == QLocale::AnyLanguage)
501 return QByteArray();
502 if (m_data->m_language_id == QLocale::C)
503 return QByteArrayView("en") % separator % QByteArrayView("POSIX");
504
505 return m_data->id().withLikelySubtagsRemoved().name(separator);
506}
507
508static qsizetype findLocaleIndexById(QLocaleId localeId) noexcept
509{
510 qsizetype idx = locale_index[localeId.language_id];
511 // If there are no locales for specified language (so we we've got the
512 // default language, which has no associated script or country), give up:
513 if (localeId.language_id && idx == 0)
514 return idx;
515
516 Q_ASSERT(localeId.acceptLanguage(locale_data[idx].m_language_id));
517
518 do {
519 if (localeId.acceptScriptTerritory(locale_data[idx].id()))
520 return idx;
521 ++idx;
522 } while (localeId.acceptLanguage(locale_data[idx].m_language_id));
523
524 return -1;
525}
526
527static constexpr qsizetype locale_data_size = q20::ssize(locale_data) - 1; // trailing guard
528bool QLocaleData::allLocaleDataRows(bool (*check)(qsizetype, const QLocaleData &))
529{
530 for (qsizetype index = 0; index < locale_data_size; ++index) {
531 if (!(*check)(index, locale_data[index]))
532 return false;
533 }
534 return true;
535}
536
537// Internal: to enable tst_qlocaledata to access locales
538const QLocaleData *QLocaleData::dataForLocaleIndex(qsizetype index)
539{
540 Q_PRE(index >= 0);
541 Q_PRE(index < locale_data_size);
542 return locale_data + index;
543}
544
545#if QT_CONFIG(timezone) && QT_CONFIG(timezone_locale) && !QT_CONFIG(icu)
546namespace QtTimeZoneLocale {
547
548// Indices of locales obtained from the given by likely subtag fall-backs.
549QList<qsizetype> fallbackLocalesFor(qsizetype index)
550{
551 // Should match QLocaleXmlReader.pruneZoneNaming()'s fallbacks() helper,
552 // aside from the special-case kludge for C -> en_US.
553 Q_ASSERT(index < locale_data_size);
554 QList<qsizetype> result = {index};
555 QLocaleId id = locale_data[index].id();
556 if (id.language_id == QLocale::C) {
557 id = { QLocale::English, QLocale::LatinScript, QLocale::UnitedStates };
558 qsizetype it = findLocaleIndexById(id);
559 Q_ASSERT_X(it != -1, Q_FUNC_INFO, "Missing en_Latn_US from locale data");
560 Q_ASSERT_X(it != index, // equivalent to !result.contains(it)
561 Q_FUNC_INFO, "en_Latn_US != C");
562 result << it;
563 }
564
565 const QLocaleId base = id;
566 QLocaleId likely = id.withLikelySubtagsAdded();
567 if (likely != base) {
568 qsizetype it = findLocaleIndexById(likely);
569 if (it != -1 && !result.contains(it))
570 result << it;
571 }
572 if (id.territory_id) {
573 id.territory_id = 0;
574 likely = id.withLikelySubtagsAdded();
575 if (likely != base) {
576 qsizetype it = findLocaleIndexById(likely);
577 if (it != -1 && !result.contains(it))
578 result << it;
579 }
580 }
581 if (id.script_id) {
582 id.script_id = 0;
583 likely = id.withLikelySubtagsAdded();
584 if (likely != base) {
585 qsizetype it = findLocaleIndexById(likely);
586 if (it != -1 && !result.contains(it))
587 result << it;
588 }
589 }
590 return result;
591}
592
593} // QtTimeZoneLocale
594#endif // timezone_locale && !icu
595
596qsizetype QLocaleData::findLocaleIndex(QLocaleId lid) noexcept
597{
598 QLocaleId localeId = lid;
599 QLocaleId likelyId = localeId.withLikelySubtagsAdded();
600 const ushort fallback = likelyId.language_id;
601
602 // Try a straight match with the likely data:
603 qsizetype index = findLocaleIndexById(likelyId);
604 if (index >= 0)
605 return index;
606 QVarLengthArray<QLocaleId, 6> tried;
607 tried.push_back(likelyId);
608
609#define CheckCandidate(id) do {
610 if (!tried.contains(id)) {
611 index = findLocaleIndexById(id);
612 if (index >= 0)
613 return index;
614 tried.push_back(id);
615 }
616 } while (false) // end CheckCandidate
617
618 // No match; try again with raw data:
619 CheckCandidate(localeId);
620
621 // No match; try again with likely country for language_script
622 if (lid.territory_id && (lid.language_id || lid.script_id)) {
623 localeId.territory_id = 0;
624 likelyId = localeId.withLikelySubtagsAdded();
625 CheckCandidate(likelyId);
626
627 // No match; try again with any country
628 CheckCandidate(localeId);
629 }
630
631 // No match; try again with likely script for language_region
632 if (lid.script_id && (lid.language_id || lid.territory_id)) {
633 localeId = QLocaleId { lid.language_id, 0, lid.territory_id };
634 likelyId = localeId.withLikelySubtagsAdded();
635 CheckCandidate(likelyId);
636
637 // No match; try again with any script
638 CheckCandidate(localeId);
639 }
640#undef CheckCandidate
641
642 // No match; return base index for initial likely language:
643 return locale_index[fallback];
644}
645
646static QStringView findTag(QStringView name) noexcept
647{
648 const std::u16string_view v(name.utf16(), size_t(name.size()));
649 const auto i = v.find_first_of(u"_-.@");
650 if (i == std::string_view::npos)
651 return name;
652 return name.first(qsizetype(i));
653}
654
655static bool validTag(QStringView tag)
656{
657 // Is tag is a non-empty sequence of ASCII letters and/or digits ?
658 for (QChar uc : tag) {
659 const char16_t ch = uc.unicode();
660 if (!isAsciiLetterOrNumber(ch))
661 return false;
662 }
663 return tag.size() > 0;
664}
665
666bool qt_splitLocaleName(QStringView name,
667 QStringView *lang, QStringView *script, QStringView *land) noexcept
668{
669 // Assume each of lang, script and land is nullptr or points to an empty QStringView.
670 enum ParserState { NoState, LangState, ScriptState, CountryState };
671 ParserState state = LangState;
672 while (name.size() && state != NoState) {
673 const QStringView tag = findTag(name);
674 if (!validTag(tag))
675 break;
676 name = name.sliced(tag.size());
677 const bool sep = name.size() > 0;
678 if (sep) // tag wasn't all that remained; there was a separator
679 name = name.sliced(1);
680
681 switch (state) {
682 case LangState:
683 if (tag.size() != 2 && tag.size() != 3)
684 return false;
685 if (lang)
686 *lang = tag;
687 state = sep ? ScriptState : NoState;
688 break;
689 case ScriptState:
690 if (scriptIndex(tag, Qt::CaseSensitive) >= 0) {
691 if (script)
692 *script = tag;
693 state = sep ? CountryState : NoState;
694 break;
695 }
696 // It wasn't a script, assume it's a country.
697 Q_FALLTHROUGH();
698 case CountryState:
699 if (land)
700 *land = tag;
701 state = NoState;
702 break;
703 case NoState: // Precluded by loop condition !
704 Q_UNREACHABLE();
705 break;
706 }
707 }
708 return state != LangState;
709}
710
711QLocaleId QLocaleId::fromName(QStringView name) noexcept
712{
713 QStringView lang;
714 QStringView script;
715 QStringView land;
716 if (!qt_splitLocaleName(name, &lang, &script, &land))
717 return { QLocale::C, 0, 0 };
718
719 // POSIX is a variant, but looks like a territory.
720 if (land.compare("POSIX", Qt::CaseInsensitive) == 0)
721 return { QLocale::C, 0, 0 };
722
723 QLocale::Language langId = QLocalePrivate::codeToLanguage(lang);
724 if (langId == QLocale::AnyLanguage)
725 return { QLocale::C, 0, 0 };
726 return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToTerritory(land) };
727}
728
729QString qt_readEscapedFormatString(QStringView format, qsizetype *idx)
730{
731 qsizetype &i = *idx;
732
733 Q_ASSERT(format.at(i) == u'\'');
734 ++i;
735 if (i == format.size())
736 return QString();
737 if (format.at(i).unicode() == '\'') { // "''" outside of a quoted string
738 ++i;
739 return "'"_L1;
740 }
741
742 QString result;
743
744 while (i < format.size()) {
745 if (format.at(i).unicode() == '\'') {
746 if (format.mid(i + 1).startsWith(u'\'')) {
747 // "''" inside a quoted string
748 result.append(u'\'');
749 i += 2;
750 } else {
751 break;
752 }
753 } else {
754 result.append(format.at(i++));
755 }
756 }
757 if (i < format.size())
758 ++i;
759
760 return result;
761}
762
763Q_CONSTINIT static const QLocaleData *default_data = nullptr;
764Q_CONSTINIT QBasicAtomicInt QLocalePrivate::s_generation = Q_BASIC_ATOMIC_INITIALIZER(0);
765
766static QLocalePrivate *c_private() noexcept
767{
768 Q_CONSTINIT static QLocalePrivate c_locale(locale_data, 0, QLocale::OmitGroupSeparator, 1);
769 return &c_locale;
770}
771
772static constexpr QLocale::NumberOptions defaultNumberOptions(QLocale::Language forLanguage)
773{
774 return forLanguage == QLocale::C ? QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions;
775}
776
777static constexpr QLocale::NumberOptions defaultNumberOptions(quint16 forLanguage)
778{
779 return defaultNumberOptions(QLocale::Language(forLanguage));
780}
781
782#ifndef QT_NO_SYSTEMLOCALE
783/******************************************************************************
784** Default system locale behavior
785*/
786
787/*!
788 \internal
789 Constructs a QSystemLocale object.
790
791 The constructor will automatically install this object as the system locale.
792 It and the destructor maintain a stack of system locales, with the
793 most-recently-created instance (that hasn't yet been deleted) used as the
794 system locale. This is only intended as a way to let a platform plugin
795 install its own system locale, overriding what might otherwise be provided
796 for its class of platform (as Android does, differing from Linux), and to
797 let tests transiently override the system or plugin-supplied one. As such,
798 there should not be diverse threads creating and destroying QSystemLocale
799 instances concurrently, so no attempt is made at thread-safety in managing
800 the stack.
801
802 This constructor also resets the flag that'll prompt QLocale::system() to
803 re-initialize its data, so that instantiating a QSystemLocale (even
804 transiently) triggers a refresh of the system locale's data. This is
805 exploited by some test code.
806*/
807QSystemLocale::QSystemLocale() : next(_systemLocale)
808{
809 _systemLocale = this;
810
811 systemLocaleData.m_language_id = 0;
812}
813
814/*!
815 \internal
816 Deletes the object.
817*/
818QSystemLocale::~QSystemLocale()
819{
820 if (_systemLocale == this) {
821 _systemLocale = next;
822
823 // Change to system locale => force refresh.
824 systemLocaleData.m_language_id = 0;
825 } else {
826 for (QSystemLocale *p = _systemLocale; p; p = p->next) {
827 if (p->next == this)
828 p->next = next;
829 }
830 }
831}
832
834{
835 if (_systemLocale)
836 return _systemLocale;
837
838 // As this is only ever instantiated with _systemLocale null, it is
839 // necessarily the ->next-most in any chain that may subsequently develop;
840 // and it won't be destructed until exit()-time.
841 static QSystemLocale globalInstance;
842 return &globalInstance;
843}
844
846{
847 // This function is NOT thread-safe!
848 // It *should not* be called by anything but systemData()
849 // It *is* called before {system,default}LocalePrivate exist.
850 const QSystemLocale *sys_locale = systemLocale();
851
852 // tell the object that the system locale has changed.
853 sys_locale->query(QSystemLocale::LocaleChanged);
854
855 // Populate system locale with fallback as basis
856 systemLocaleData = locale_data[sys_locale->fallbackLocaleIndex()];
857
858 QVariant res = sys_locale->query(QSystemLocale::LanguageId);
859 if (!res.isNull()) {
860 systemLocaleData.m_language_id = res.toInt();
861 systemLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility
862 }
863 res = sys_locale->query(QSystemLocale::TerritoryId);
864 if (!res.isNull()) {
865 systemLocaleData.m_territory_id = res.toInt();
866 systemLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility
867 }
868 res = sys_locale->query(QSystemLocale::ScriptId);
869 if (!res.isNull())
870 systemLocaleData.m_script_id = res.toInt();
871
872 // Should we replace Any values based on likely sub-tags ?
873
874 // If system locale is default locale, update the default collator's generation:
875 if (default_data == &systemLocaleData)
876 QLocalePrivate::s_generation.fetchAndAddRelaxed(1);
877}
878#endif // !QT_NO_SYSTEMLOCALE
879
880static const QLocaleData *systemData(qsizetype *sysIndex = nullptr)
881{
882#ifndef QT_NO_SYSTEMLOCALE
883 /*
884 Copy over the information from the fallback locale and modify.
885
886 If sysIndex is passed, it should be the m_index of the system locale's
887 QLocalePrivate, which we'll update if it needs it.
888
889 This modifies (cross-thread) global state, so is mutex-protected.
890 */
891 {
892 Q_CONSTINIT static QLocaleId sysId;
893 bool updated = false;
894
895 Q_CONSTINIT static QBasicMutex systemDataMutex;
896 systemDataMutex.lock();
897 if (systemLocaleData.m_language_id == 0) {
898 updateSystemPrivate();
899 updated = true;
900 }
901 // Initialization of system private has *sysIndex == -1 to hit this.
902 if (sysIndex && (updated || *sysIndex < 0)) {
903 const QLocaleId nowId = systemLocaleData.id();
904 if (sysId != nowId || *sysIndex < 0) {
905 // This look-up may be expensive:
906 *sysIndex = QLocaleData::findLocaleIndex(nowId);
907 sysId = nowId;
908 }
909 }
910 systemDataMutex.unlock();
911 }
912
913 return &systemLocaleData;
914#else
915 Q_UNUSED(sysIndex);
916 return locale_data;
917#endif
918}
919
921{
922 if (!default_data)
923 default_data = systemData();
924 return default_data;
925}
926
928{
929 const QLocaleData *const data = defaultData();
930#ifndef QT_NO_SYSTEMLOCALE
931 if (data == &systemLocaleData) {
932 // Work out a suitable index matching the system data, for use when
933 // accessing calendar data, when not fetched from system.
934 return QLocaleData::findLocaleIndex(data->id());
935 }
936#endif
937
938 using QtPrivate::q_points_into_range;
939 Q_ASSERT(q_points_into_range(data, locale_data));
940 return data - locale_data;
941}
942
943const QLocaleData *QLocaleData::c() noexcept
944{
945 Q_ASSERT(locale_index[QLocale::C] == 0);
946 return locale_data;
947}
948
949#ifndef QT_NO_DATASTREAM
950QDataStream &operator<<(QDataStream &ds, const QLocale &l)
951{
952 ds << l.name();
953 return ds;
954}
955
956QDataStream &operator>>(QDataStream &ds, QLocale &l)
957{
958 QString s;
959 ds >> s;
960 l = QLocale(s);
961 return ds;
962}
963#endif // QT_NO_DATASTREAM
964
965Q_GLOBAL_STATIC(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate,
966 new QLocalePrivate(defaultData(), defaultIndex(),
967 defaultNumberOptions(defaultData()->m_language_id)))
968
969static QLocalePrivate *localePrivateByName(QStringView name)
970{
971 if (name == u"C")
972 return c_private();
973 const qsizetype index = QLocaleData::findLocaleIndex(QLocaleId::fromName(name));
974 return new QLocalePrivate(QLocaleData::dataForLocaleIndex(index), index,
975 defaultNumberOptions(locale_data[index].m_language_id));
976}
977
978static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script,
979 QLocale::Territory territory)
980{
981 if (language == QLocale::C)
982 return c_private();
983
984 qsizetype index = QLocaleData::findLocaleIndex(QLocaleId { language, script, territory });
985 const QLocaleData *data = QLocaleData::dataForLocaleIndex(index);
986
987 QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
988
989 // If not found, should use default locale:
990 if (data->m_language_id == QLocale::C) {
991 if (defaultLocalePrivate.exists())
992 numberOptions = defaultLocalePrivate->data()->m_numberOptions;
993 data = defaultData();
994 index = defaultIndex();
995 }
996 return new QLocalePrivate(data, index, numberOptions);
997}
998
999bool comparesEqual(const QLocale &loc, QLocale::Language lang)
1000{
1001 // Keep in sync with findLocalePrivate()!
1002 auto compareWithPrivate = [&loc](const QLocaleData *data, QLocale::NumberOptions opts)
1003 {
1004 return loc.d->m_data == data && loc.d->m_numberOptions == opts;
1005 };
1006
1007 if (lang == QLocale::C)
1008 return compareWithPrivate(c_private()->m_data, c_private()->m_numberOptions);
1009
1010 qsizetype index = QLocaleData::findLocaleIndex(QLocaleId { lang });
1011 const QLocaleData *data = QLocaleData::dataForLocaleIndex(index);
1012
1013 QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
1014
1015 // If not found, should use default locale:
1016 if (data->m_language_id == QLocale::C) {
1017 if (defaultLocalePrivate.exists())
1018 numberOptions = defaultLocalePrivate->data()->m_numberOptions;
1019 data = defaultData();
1020 }
1021 return compareWithPrivate(data, numberOptions);
1022}
1023
1024static std::optional<QString>
1025systemLocaleString(const QLocaleData *that, QSystemLocale::QueryType type)
1026{
1027#ifndef QT_NO_SYSTEMLOCALE
1028 if (that != &systemLocaleData)
1029 return std::nullopt;
1030
1031 QVariant v = systemLocale()->query(type);
1032 if (v.metaType() != QMetaType::fromType<QString>())
1033 return std::nullopt;
1034
1035 return v.toString();
1036#else
1037 Q_UNUSED(that)
1038 Q_UNUSED(type)
1039 return std::nullopt;
1040#endif
1041}
1042
1043static QString localeString(const QLocaleData *that, QSystemLocale::QueryType type,
1044 QLocaleData::DataRange range)
1045{
1046 if (auto opt = systemLocaleString(that, type))
1047 return *opt;
1048 return range.getData(single_character_data);
1049}
1050
1052{
1053 return localeString(this, QSystemLocale::DecimalPoint, decimalSeparator());
1054}
1055
1057{
1058 return localeString(this, QSystemLocale::GroupSeparator, groupDelim());
1059}
1060
1061QString QLocaleData::percentSign() const
1062{
1063 return percent().getData(single_character_data);
1064}
1065
1067{
1068 return listDelimit().getData(single_character_data);
1069}
1070
1071QString QLocaleData::zeroDigit() const
1072{
1073 return localeString(this, QSystemLocale::ZeroDigit, zero());
1074}
1075
1076char32_t QLocaleData::zeroUcs() const
1077{
1078#ifndef QT_NO_SYSTEMLOCALE
1079 if (this == &systemLocaleData) {
1080 const auto text = systemLocale()->query(QSystemLocale::ZeroDigit).toString();
1081 if (!text.isEmpty()) {
1082 if (text.size() == 1 && !text.at(0).isSurrogate())
1083 return text.at(0).unicode();
1084 if (text.size() == 2 && text.at(0).isHighSurrogate())
1085 return QChar::surrogateToUcs4(text.at(0), text.at(1));
1086 }
1087 }
1088#endif
1090}
1091
1093{
1094 return localeString(this, QSystemLocale::NegativeSign, minus());
1095}
1096
1098{
1099 return localeString(this, QSystemLocale::PositiveSign, plus());
1100}
1101
1103{
1104 return exponential().getData(single_character_data);
1105}
1106
1108{
1109#ifndef QT_NO_SYSTEMLOCALE
1110 if (this == &systemLocaleData) {
1111 QVariant queryResult = systemLocale()->query(QSystemLocale::Grouping);
1112 if (!queryResult.isNull()) {
1113 QLocaleData::GroupSizes sysGroupSizes =
1114 queryResult.value<QLocaleData::GroupSizes>();
1115 if (sysGroupSizes.first <= 0)
1116 sysGroupSizes.first = m_grouping_first;
1117 if (sysGroupSizes.higher <= 0)
1118 sysGroupSizes.higher = m_grouping_higher;
1119 if (sysGroupSizes.least <= 0)
1120 sysGroupSizes.least = m_grouping_least;
1121 return sysGroupSizes;
1122 }
1123 }
1124#endif
1125 return { m_grouping_first,
1126 m_grouping_higher,
1127 m_grouping_least };
1128}
1129
1130/*!
1131 \internal
1132*/
1133QLocale::QLocale(QLocalePrivate &dd)
1134 // If this ever becomes explicitly noexcept(false),
1135 // adjust QLocale::c() to not use this ctor anymore.
1136 : d(&dd)
1137{}
1138
1139/*!
1140 \variable QLocale::DefaultTwoDigitBaseYear
1141 \since 6.7
1142
1143 \brief The default start year of the century within which a format taking
1144 a two-digit year will select. The value of the constant is \c {1900}.
1145
1146 Some locales use, particularly for ShortFormat, only the last two digits of
1147 the year. Proir to 6.7 the year 1900 was always used as a base year for
1148 such cases. Now various QLocale and QDate functions have the overloads that
1149 allow callers to specify the base year, and this constant is used as its
1150 default value.
1151
1152 \sa toDate(), toDateTime(), QDate::fromString(), QDateTime::fromString()
1153*/
1154
1155/*!
1156 \since 6.3
1157
1158 Constructs a QLocale object with the specified \a name.
1159
1160 The name has the format "language[_script][_territory][.codeset][@modifier]"
1161 or "C", where:
1162
1163 \list
1164 \li language is a lowercase, two-letter, ISO 639 language code (some
1165 three-letter codes are also recognized),
1166 \li script is a capitalized, four-letter, ISO 15924 script code,
1167 \li territory is an uppercase, two-letter, ISO 3166 territory code
1168 (some numeric codes are also recognized), and
1169 \li codeset and modifier are ignored.
1170 \endlist
1171
1172 The separator can be either underscore \c{'_'} (U+005F, "low line") or a
1173 dash \c{'-'} (U+002D, "hyphen-minus"). If QLocale has no data for the
1174 specified combination of language, script, and territory, then it uses the
1175 most suitable match it can find instead. If the string violates the locale
1176 format, or no suitable data can be found for the specified keys, the "C"
1177 locale is used instead.
1178
1179 This constructor is much slower than QLocale(Language, Script, Territory) or
1180 QLocale(Language, Territory).
1181
1182 \sa bcp47Name(), {Matching combinations of language, script and territory}
1183*/
1184QLocale::QLocale(QStringView name)
1185 : d(localePrivateByName(name))
1186{
1187}
1188
1189/*!
1190 \fn QLocale::QLocale(const QString &name)
1191 \overload
1192*/
1193
1194/*!
1195 Constructs a QLocale object initialized with the default locale.
1196
1197 If no default locale was set using setDefault(), this locale will be the
1198 same as the one returned by system().
1199
1200 \sa setDefault(), system()
1201*/
1202
1203QLocale::QLocale()
1204 : d(c_private())
1205{
1206 if (!defaultLocalePrivate.isDestroyed()) {
1207 // Make sure system data is up to date:
1208 systemData();
1209 d = *defaultLocalePrivate;
1210 }
1211}
1212
1213/*!
1214 Constructs a QLocale object for the specified \a language and \a territory.
1215
1216 If there is more than one script in use for this combination, a likely
1217 script will be selected. If QLocale has no data for the specified \a
1218 language, the default locale is used. If QLocale has no data for the
1219 specified combination of \a language and \a territory, an alternative
1220 territory may be used instead.
1221
1222 \sa setDefault(), {Matching combinations of language, script and territory}
1223*/
1224
1225QLocale::QLocale(Language language, Territory territory)
1226 : d(findLocalePrivate(language, AnyScript, territory))
1227{
1228}
1229
1230/*!
1231 \since 4.8
1232
1233 Constructs a QLocale object for the specified \a language, \a script and \a
1234 territory.
1235
1236 If QLocale does not have data for the given combination, it will find data
1237 for as good a match as it can. It falls back on the default locale if
1238
1239 \list
1240 \li \a language is \c AnyLanguage and no language can be inferred from \a
1241 script and \a territory
1242 \li QLocale has no data for the language, either given as \a language or
1243 inferred as above.
1244 \endlist
1245
1246 \sa setDefault(), {Matching combinations of language, script and territory}
1247*/
1248
1249QLocale::QLocale(Language language, Script script, Territory territory)
1250 : d(findLocalePrivate(language, script, territory))
1251{
1252}
1253
1254/*!
1255 Constructs a QLocale object as a copy of \a other.
1256*/
1257
1258QLocale::QLocale(const QLocale &other) noexcept = default;
1259
1260/*!
1261 Destructor
1262*/
1263
1264QLocale::~QLocale()
1265{
1266}
1267
1268/*!
1269 Assigns \a other to this QLocale object and returns a reference
1270 to this QLocale object.
1271*/
1272
1273QLocale &QLocale::operator=(const QLocale &other) noexcept = default;
1274
1275/*!
1276 \internal
1277 Equality comparison.
1278*/
1279
1280bool QLocale::equals(const QLocale &other) const noexcept
1281{
1282 return d->m_data == other.d->m_data && d->m_numberOptions == other.d->m_numberOptions;
1283}
1284
1285/*!
1286 \fn void QLocale::swap(QLocale &other)
1287 \since 5.6
1288 \memberswap{locale}
1289*/
1290
1291/*!
1292 \since 5.6
1293 \qhashold{QLocale}
1294*/
1295size_t qHash(const QLocale &key, size_t seed) noexcept
1296{
1297 return qHashMulti(seed, key.d->m_data, key.d->m_numberOptions);
1298}
1299
1300/*!
1301 \since 4.2
1302
1303 Sets the \a options related to number conversions for this QLocale instance.
1304
1305 \sa numberOptions(), FloatingPointPrecisionOption
1306*/
1307void QLocale::setNumberOptions(NumberOptions options)
1308{
1309 d->m_numberOptions = options;
1310}
1311
1312/*!
1313 \since 4.2
1314
1315 Returns the options related to number conversions for this QLocale instance.
1316
1317 By default, no options are set for the standard locales, except for the "C"
1318 locale, which has OmitGroupSeparator set by default.
1319
1320 \sa setNumberOptions(), toString(), groupSeparator(), FloatingPointPrecisionOption
1321*/
1322QLocale::NumberOptions QLocale::numberOptions() const
1323{
1324 return d->m_numberOptions;
1325}
1326
1327/*!
1328 \fn QString QLocale::quoteString(const QString &str, QuotationStyle style) const
1329
1330 \since 4.8
1331
1332 Returns \a str quoted according to the current locale using the given
1333 quotation \a style.
1334*/
1335
1336/*!
1337 \since 6.0
1338
1339 \overload
1340*/
1341QString QLocale::quoteString(QStringView str, QuotationStyle style) const
1342{
1343#ifndef QT_NO_SYSTEMLOCALE
1344 if (d->m_data == &systemLocaleData) {
1345 QVariant res;
1346 if (style == AlternateQuotation)
1347 res = systemLocale()->query(QSystemLocale::StringToAlternateQuotation,
1348 QVariant::fromValue(str));
1349 if (res.isNull() || style == StandardQuotation)
1350 res = systemLocale()->query(QSystemLocale::StringToStandardQuotation,
1351 QVariant::fromValue(str));
1352 if (!res.isNull())
1353 return res.toString();
1354 }
1355#endif
1356
1357 QLocaleData::DataRange start, end;
1358 if (style == StandardQuotation) {
1359 start = d->m_data->quoteStart();
1360 end = d->m_data->quoteEnd();
1361 } else {
1362 start = d->m_data->quoteStartAlternate();
1363 end = d->m_data->quoteEndAlternate();
1364 }
1365
1366 return start.viewData(single_character_data) % str % end.viewData(single_character_data);
1367}
1368
1369/*!
1370 \since 4.8
1371
1372 Returns a string that represents a join of a given \a list of strings with
1373 a separator defined by the locale.
1374*/
1375QString QLocale::createSeparatedList(const QStringList &list) const
1376{
1377 // May be empty if list is empty or sole entry is empty.
1378#ifndef QT_NO_SYSTEMLOCALE
1379 if (d->m_data == &systemLocaleData) {
1380 QVariant res =
1381 systemLocale()->query(QSystemLocale::ListToSeparatedString, QVariant::fromValue(list));
1382
1383 if (!res.isNull())
1384 return res.toString();
1385 }
1386#endif
1387
1388 const qsizetype size = list.size();
1389 if (size < 1)
1390 return QString();
1391
1392 if (size == 1)
1393 return list.at(0);
1394
1395 if (size == 2)
1396 return d->m_data->pairListPattern().getData(
1397 list_pattern_part_data).arg(list.at(0), list.at(1));
1398
1399 QStringView formatStart = d->m_data->startListPattern().viewData(list_pattern_part_data);
1400 QStringView formatMid = d->m_data->midListPattern().viewData(list_pattern_part_data);
1401 QStringView formatEnd = d->m_data->endListPattern().viewData(list_pattern_part_data);
1402 QString result = formatStart.arg(list.at(0), list.at(1));
1403 for (qsizetype i = 2; i < size - 1; ++i)
1404 result = formatMid.arg(result, list.at(i));
1405 result = formatEnd.arg(result, list.at(size - 1));
1406 return result;
1407}
1408
1409/*!
1410 \nonreentrant
1411
1412 Sets the global default locale to \a locale.
1413
1414 This locale is used when a QLocale object is constructed with no
1415 arguments. If this function is not called, the system's locale is used.
1416
1417 \warning In a multithreaded application, the default locale should be set at
1418 application startup, before any non-GUI threads are created.
1419
1420 \sa system(), c()
1421*/
1422
1423void QLocale::setDefault(const QLocale &locale)
1424{
1425 default_data = locale.d->m_data;
1426
1427 if (defaultLocalePrivate.isDestroyed())
1428 return; // avoid crash on exit
1429 if (!defaultLocalePrivate.exists()) {
1430 // Force it to exist; see QTBUG-83016
1431 [[maybe_unused]] QLocale ignoreme;
1432 Q_ASSERT(defaultLocalePrivate.exists());
1433 }
1434
1435 // update the cached private
1436 *defaultLocalePrivate = locale.d;
1437 QLocalePrivate::s_generation.fetchAndAddRelaxed(1);
1438}
1439
1440/*!
1441 Returns the language of this locale.
1442
1443 \sa script(), territory(), languageToString(), bcp47Name()
1444*/
1445QLocale::Language QLocale::language() const
1446{
1447 return Language(d->languageId());
1448}
1449
1450/*!
1451 \since 4.8
1452
1453 Returns the script of this locale.
1454
1455 \sa language(), territory(), languageToString(), scriptToString(), bcp47Name()
1456*/
1457QLocale::Script QLocale::script() const
1458{
1459 return Script(d->m_data->m_script_id);
1460}
1461
1462/*!
1463 \since 6.2
1464
1465 Returns the territory of this locale.
1466
1467 \sa language(), script(), territoryToString(), bcp47Name()
1468*/
1469QLocale::Territory QLocale::territory() const
1470{
1471 return Territory(d->territoryId());
1472}
1473
1474#if QT_DEPRECATED_SINCE(6, 6)
1475/*!
1476 \deprecated [6.6] Use \l territory() instead.
1477
1478 Returns the territory of this locale.
1479
1480 \sa language(), script(), territoryToString(), bcp47Name()
1481*/
1482QLocale::Country QLocale::country() const
1483{
1484 return territory();
1485}
1486#endif
1487
1488/*!
1489 \since 6.7
1490 \enum QLocale::TagSeparator
1491
1492 Indicate how to combine the parts that make up a locale identifier.
1493
1494 A locale identifier may be made up of several tags, indicating language,
1495 script and territory (plus, potentially, other details), joined together to
1496 form the identifier. Various standards and conventional forms use either a
1497 dash (the Unicode HYPHEN-MINUS, U+002D) or an underscore (LOW LINE, U+005F).
1498 Different clients of QLocale may thus need one or the other.
1499
1500 \value Dash Use \c{'-'}, the dash or hyphen character.
1501 \value Underscore Use \c{'_'}, the underscore character.
1502
1503 \note Although dash and underscore are the only separators used in public
1504 standards (as at 2023), it is possible to cast any \l
1505 {https://en.cppreference.com/w/cpp/language/ascii} {ASCII} character to this
1506 type if a non-standard ASCII separator is needed. Casting a non-ASCII
1507 character (with decimal value above 127) is not supported: such values are
1508 reserved for future use as enum members if some public standard ever uses a
1509 non-ASCII separator. It is, of course, possible to use QString::replace() to
1510 replace the separator used by a function taking a parameter of this type
1511 with an arbitrary Unicode character or string.
1512*/
1513
1514Q_DECL_COLD_FUNCTION static void badSeparatorWarning(const char *method, char sep)
1515{
1516 qWarning("QLocale::%s(): Using non-ASCII separator '%c' (%02x) is unsupported",
1517 method, sep, uint(uchar(sep)));
1518}
1519
1520/*!
1521 \brief The short name of this locale.
1522
1523 Returns the language and territory of this locale as a string of the form
1524 "language_territory", where language is a lowercase, two-letter ISO 639
1525 language code, and territory is an uppercase, two- or three-letter ISO 3166
1526 territory code. If the locale has no specified territory, only the language
1527 name is returned. Since Qt 6.7 an optional \a separator parameter can be
1528 supplied to override the default underscore character separating the two
1529 tags.
1530
1531 Even if the QLocale object was constructed with an explicit script, name()
1532 will not contain it for compatibility reasons. Use \l bcp47Name() instead if
1533 you need a full locale name, or construct the string you want to identify a
1534 locale by from those returned by passing its \l language() to \l
1535 languageToCode() and similar for the script and territory.
1536
1537 \sa QLocale(), language(), script(), territory(), bcp47Name(), uiLanguages()
1538*/
1539
1540QString QLocale::name(TagSeparator separator) const
1541{
1542 const char sep = char(separator);
1543 if (uchar(sep) > 0x7f) {
1544 badSeparatorWarning("name", sep);
1545 return {};
1546 }
1547 const auto code = d->languageCode();
1548 QLatin1StringView view{code.data()};
1549
1550 Language l = language();
1551 if (l == C)
1552 return view;
1553
1554 Territory c = territory();
1555 if (c == AnyTerritory)
1556 return view;
1557
1558 return view + QLatin1Char(sep) + d->territoryCode();
1559}
1560
1561template <typename T> static inline
1562T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
1563{
1564 constexpr bool isUnsigned = std::is_unsigned_v<T>;
1565 using Int64 = typename std::conditional_t<isUnsigned, quint64, qint64>;
1566
1567 QSimpleParsedNumber<Int64> r{};
1568 if constexpr (isUnsigned)
1569 r = d->m_data->stringToUnsLongLong(str, 10, d->m_numberOptions);
1570 else
1571 r = d->m_data->stringToLongLong(str, 10, d->m_numberOptions);
1572
1573 if (ok)
1574 *ok = r.ok();
1575
1576 Int64 val = r.result;
1577 if (T(val) != val) {
1578 if (ok != nullptr)
1579 *ok = false;
1580 val = 0;
1581 }
1582 return T(val);
1583}
1584
1585
1586/*!
1587 \since 4.8
1588
1589 \brief Returns the BCP47 field names joined with dashes.
1590
1591 This combines as many of language, script and territory (and possibly other
1592 BCP47 fields) for this locale as are needed to uniquely specify it. Note
1593 that fields may be omitted if the Unicode consortium's \l {Matching
1594 combinations of language, script and territory}{Likely Subtag Rules} imply
1595 the omitted fields when given those retained. See \l name() for how to
1596 construct a string from individual fields, if some other format is needed.
1597
1598 Unlike uiLanguages(), the value returned by bcp47Name() represents the
1599 locale name of the QLocale data; this need not be the language the
1600 user-interface should be in.
1601
1602 This function tries to conform the locale name to the IETF Best Common
1603 Practice 47, defined by RFC 5646. Since Qt 6.7, it supports an optional \a
1604 separator parameter which can be used to override the BCP47-specified use of
1605 a hyphen to separate the tags. For use in IETF-defined protocols, however,
1606 the default, QLocale::TagSeparator::Dash, should be retained.
1607
1608 \sa name(), language(), territory(), script(), uiLanguages()
1609*/
1610QString QLocale::bcp47Name(TagSeparator separator) const
1611{
1612 const char sep = char(separator);
1613 if (uchar(sep) > 0x7f) {
1614 badSeparatorWarning("bcp47Name", sep);
1615 return {};
1616 }
1617 return QString::fromLatin1(d->bcp47Name(sep));
1618}
1619
1620/*!
1621 Returns the two- or three-letter language code for \a language, as defined
1622 in the ISO 639 standards.
1623
1624 If specified, \a codeTypes selects which set of codes to consider. The first
1625 code from the set that is defined for \a language is returned. Otherwise,
1626 all ISO-639 codes are considered. The codes are considered in the following
1627 order: \c ISO639Part1, \c ISO639Part2B, \c ISO639Part2T, \c ISO639Part3.
1628 \c LegacyLanguageCode is ignored by this function.
1629
1630 \note For \c{QLocale::C} the function returns \c{"C"}.
1631 For \c QLocale::AnyLanguage an empty string is returned.
1632 If the language has no code in any selected code set, an empty string
1633 is returned.
1634
1635 \since 6.3
1636 \sa codeToLanguage(), language(), name(), bcp47Name(), territoryToCode(), scriptToCode()
1637*/
1638QString QLocale::languageToCode(Language language, LanguageCodeTypes codeTypes)
1639{
1640 const auto code = QLocalePrivate::languageToCode(language, codeTypes);
1641 return QLatin1StringView{code.data()};
1642}
1643
1644/*!
1645 Returns the QLocale::Language enum corresponding to the two- or three-letter
1646 \a languageCode, as defined in the ISO 639 standards.
1647
1648 If specified, \a codeTypes selects which set of codes to consider for
1649 conversion. By default all codes known to Qt are considered. The codes are
1650 matched in the following order: \c ISO639Part1, \c ISO639Part2B,
1651 \c ISO639Part2T, \c ISO639Part3, \c LegacyLanguageCode.
1652
1653 If the code is invalid or not known \c QLocale::AnyLanguage is returned.
1654
1655 \since 6.3
1656 \sa languageToCode(), codeToTerritory(), codeToScript()
1657*/
1658QLocale::Language QLocale::codeToLanguage(QStringView languageCode,
1659 LanguageCodeTypes codeTypes) noexcept
1660{
1661 return QLocalePrivate::codeToLanguage(languageCode, codeTypes);
1662}
1663
1664/*!
1665 \since 6.2
1666
1667 Returns the two-letter territory code for \a territory, as defined
1668 in the ISO 3166 standard.
1669
1670 \note For \c{QLocale::AnyTerritory} an empty string is returned.
1671
1672 \sa codeToTerritory(), territory(), name(), bcp47Name(), languageToCode(), scriptToCode()
1673*/
1674QString QLocale::territoryToCode(QLocale::Territory territory)
1675{
1676 return QLocalePrivate::territoryToCode(territory);
1677}
1678
1679/*!
1680 \since 6.2
1681
1682 Returns the QLocale::Territory enum corresponding to the two-letter or
1683 three-digit \a territoryCode, as defined in the ISO 3166 standard.
1684
1685 If the code is invalid or not known QLocale::AnyTerritory is returned.
1686
1687 \sa territoryToCode(), codeToLanguage(), codeToScript()
1688*/
1689QLocale::Territory QLocale::codeToTerritory(QStringView territoryCode) noexcept
1690{
1691 return QLocalePrivate::codeToTerritory(territoryCode);
1692}
1693
1694#if QT_DEPRECATED_SINCE(6, 6)
1695/*!
1696 \deprecated [6.6] Use \l territoryToCode() instead.
1697
1698 Returns the two-letter territory code for \a country, as defined
1699 in the ISO 3166 standard.
1700
1701 \note For \c{QLocale::AnyTerritory} or \c{QLocale::AnyCountry} an empty string is returned.
1702
1703 \sa codeToTerritory(), territory(), name(), bcp47Name(), languageToCode(), scriptToCode()
1704*/
1705QString QLocale::countryToCode(Country country)
1706{
1707 return territoryToCode(country);
1708}
1709
1710/*!
1711 Returns the QLocale::Territory enum corresponding to the two-letter or
1712 three-digit \a countryCode, as defined in the ISO 3166 standard.
1713
1714 If the code is invalid or not known QLocale::AnyTerritory is returned.
1715
1716 \deprecated [6.6] Use codeToTerritory(QStringView) instead.
1717 \since 6.1
1718 \sa territoryToCode(), codeToLanguage(), codeToScript()
1719*/
1720QLocale::Country QLocale::codeToCountry(QStringView countryCode) noexcept
1721{
1722 return QLocalePrivate::codeToTerritory(countryCode);
1723}
1724#endif
1725
1726/*!
1727 Returns the four-letter script code for \a script, as defined in the
1728 ISO 15924 standard.
1729
1730 \note For \c{QLocale::AnyScript} an empty string is returned.
1731
1732 \since 6.1
1733 \sa script(), name(), bcp47Name(), languageToCode(), territoryToCode()
1734*/
1735QString QLocale::scriptToCode(Script script)
1736{
1737 return QLocalePrivate::scriptToCode(script);
1738}
1739
1740/*!
1741 Returns the QLocale::Script enum corresponding to the four-letter script
1742 \a scriptCode, as defined in the ISO 15924 standard.
1743
1744 If the code is invalid or not known QLocale::AnyScript is returned.
1745
1746 \since 6.1
1747 \sa scriptToCode(), codeToLanguage(), codeToTerritory()
1748*/
1749QLocale::Script QLocale::codeToScript(QStringView scriptCode) noexcept
1750{
1751 return QLocalePrivate::codeToScript(scriptCode);
1752}
1753
1754/*!
1755 Returns a QString containing the name of \a language.
1756
1757 \sa territoryToString(), scriptToString(), bcp47Name()
1758*/
1759
1760QString QLocale::languageToString(Language language)
1761{
1762 if (language > LastLanguage)
1763 return "Unknown"_L1;
1764 return QString::fromUtf8(language_name_list + language_name_index[language]);
1765}
1766
1767/*!
1768 \since 6.2
1769
1770 Returns a QString containing the name of \a territory.
1771
1772 \sa languageToString(), scriptToString(), territory(), bcp47Name()
1773*/
1774QString QLocale::territoryToString(Territory territory)
1775{
1776 if (territory > LastTerritory)
1777 return "Unknown"_L1;
1778 return QString::fromUtf8(territory_name_list + territory_name_index[territory]);
1779}
1780
1781#if QT_DEPRECATED_SINCE(6, 6)
1782/*!
1783 \deprecated [6.6] Use \l territoryToString() instead.
1784
1785 Returns a QString containing the name of \a country.
1786
1787 \sa languageToString(), scriptToString(), territory(), bcp47Name()
1788*/
1789QString QLocale::countryToString(Country country)
1790{
1791 return territoryToString(country);
1792}
1793#endif
1794
1795/*!
1796 \since 4.8
1797
1798 Returns a QString containing the name of \a script.
1799
1800 \sa languageToString(), territoryToString(), script(), bcp47Name()
1801*/
1802QString QLocale::scriptToString(Script script)
1803{
1804 if (script > LastScript)
1805 return "Unknown"_L1;
1806 return QString::fromUtf8(script_name_list + script_name_index[script]);
1807}
1808
1809/*!
1810 \fn short QLocale::toShort(const QString &s, bool *ok) const
1811
1812 Returns the short int represented by the localized string \a s.
1813
1814 If the conversion fails the function returns 0.
1815
1816 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1817 to \c false, and success by setting *\a{ok} to \c true.
1818
1819 This function ignores leading and trailing whitespace.
1820
1821 \sa toUShort(), toString()
1822*/
1823
1824/*!
1825 \fn ushort QLocale::toUShort(const QString &s, bool *ok) const
1826
1827 Returns the unsigned short int represented by the localized string \a s.
1828
1829 If the conversion fails the function returns 0.
1830
1831 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1832 to \c false, and success by setting *\a{ok} to \c true.
1833
1834 This function ignores leading and trailing whitespace.
1835
1836 \sa toShort(), toString()
1837*/
1838
1839/*!
1840 \fn int QLocale::toInt(const QString &s, bool *ok) const
1841 Returns the int represented by the localized string \a s.
1842
1843 If the conversion fails the function returns 0.
1844
1845 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1846 to \c false, and success by setting *\a{ok} to \c true.
1847
1848 This function ignores leading and trailing whitespace.
1849
1850 \sa toUInt(), toString()
1851*/
1852
1853/*!
1854 \fn uint QLocale::toUInt(const QString &s, bool *ok) const
1855 Returns the unsigned int represented by the localized string \a s.
1856
1857 If the conversion fails the function returns 0.
1858
1859 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1860 to \c false, and success by setting *\a{ok} to \c true.
1861
1862 This function ignores leading and trailing whitespace.
1863
1864 \sa toInt(), toString()
1865*/
1866
1867/*!
1868 \since 5.13
1869 \fn long QLocale::toLong(const QString &s, bool *ok) const
1870
1871 Returns the long int represented by the localized string \a s.
1872
1873 If the conversion fails the function returns 0.
1874
1875 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1876 to \c false, and success by setting *\a{ok} to \c true.
1877
1878 This function ignores leading and trailing whitespace.
1879
1880 \sa toInt(), toULong(), toDouble(), toString()
1881*/
1882
1883/*!
1884 \since 5.13
1885 \fn ulong QLocale::toULong(const QString &s, bool *ok) const
1886
1887 Returns the unsigned long int represented by the localized
1888 string \a s.
1889
1890 If the conversion fails the function returns 0.
1891
1892 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1893 to \c false, and success by setting *\a{ok} to \c true.
1894
1895 This function ignores leading and trailing whitespace.
1896
1897 \sa toLong(), toInt(), toDouble(), toString()
1898*/
1899
1900/*!
1901 \fn qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
1902 Returns the long long int represented by the localized string \a s.
1903
1904 If the conversion fails the function returns 0.
1905
1906 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1907 to \c false, and success by setting *\a{ok} to \c true.
1908
1909 This function ignores leading and trailing whitespace.
1910
1911 \sa toInt(), toULongLong(), toDouble(), toString()
1912*/
1913
1914/*!
1915 \fn qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
1916
1917 Returns the unsigned long long int represented by the localized
1918 string \a s.
1919
1920 If the conversion fails the function returns 0.
1921
1922 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1923 to \c false, and success by setting *\a{ok} to \c true.
1924
1925 This function ignores leading and trailing whitespace.
1926
1927 \sa toLongLong(), toInt(), toDouble(), toString()
1928*/
1929
1930/*!
1931 \fn float QLocale::toFloat(const QString &s, bool *ok) const
1932
1933 Returns the float represented by the localized string \a s.
1934
1935 Returns an infinity if the conversion overflows or 0.0 if the
1936 conversion fails for any other reason (e.g. underflow).
1937
1938 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1939 to \c false, and success by setting *\a{ok} to \c true.
1940
1941 This function ignores leading and trailing whitespace.
1942
1943 \sa toDouble(), toInt(), toString()
1944*/
1945
1946/*!
1947 \fn double QLocale::toDouble(const QString &s, bool *ok) const
1948 Returns the double represented by the localized string \a s.
1949
1950 Returns an infinity if the conversion overflows or 0.0 if the
1951 conversion fails for any other reason (e.g. underflow).
1952
1953 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1954 to \c false, and success by setting *\a{ok} to \c true.
1955
1956 \snippet code/src_corelib_text_qlocale.cpp 3
1957
1958 Notice that the last conversion returns 1234.0, because '.' is the
1959 thousands group separator in the German locale.
1960
1961 This function ignores leading and trailing whitespace.
1962
1963 \sa toFloat(), toInt(), toString()
1964*/
1965
1966/*!
1967 Returns the short int represented by the localized string \a s.
1968
1969 If the conversion fails, the function returns 0.
1970
1971 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1972 to \c false, and success by setting *\a{ok} to \c true.
1973
1974 This function ignores leading and trailing whitespace.
1975
1976 \sa toUShort(), toString()
1977
1978 \since 5.10
1979*/
1980
1981short QLocale::toShort(QStringView s, bool *ok) const
1982{
1983 return toIntegral_helper<short>(d, s, ok);
1984}
1985
1986/*!
1987 Returns the unsigned short int represented by the localized string \a s.
1988
1989 If the conversion fails, the function returns 0.
1990
1991 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
1992 to \c false, and success by setting *\a{ok} to \c true.
1993
1994 This function ignores leading and trailing whitespace.
1995
1996 \sa toShort(), toString()
1997
1998 \since 5.10
1999*/
2000
2001ushort QLocale::toUShort(QStringView s, bool *ok) const
2002{
2003 return toIntegral_helper<ushort>(d, s, ok);
2004}
2005
2006/*!
2007 Returns the int represented by the localized string \a s.
2008
2009 If the conversion fails, the function returns 0.
2010
2011 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2012 to \c false, and success by setting *\a{ok} to \c true.
2013
2014 This function ignores leading and trailing whitespace.
2015
2016 \sa toUInt(), toString()
2017
2018 \since 5.10
2019*/
2020
2021int QLocale::toInt(QStringView s, bool *ok) const
2022{
2023 return toIntegral_helper<int>(d, s, ok);
2024}
2025
2026/*!
2027 Returns the unsigned int represented by the localized string \a s.
2028
2029 If the conversion fails, the function returns 0.
2030
2031 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2032 to \c false, and success by setting *\a{ok} to \c true.
2033
2034 This function ignores leading and trailing whitespace.
2035
2036 \sa toInt(), toString()
2037
2038 \since 5.10
2039*/
2040
2041uint QLocale::toUInt(QStringView s, bool *ok) const
2042{
2043 return toIntegral_helper<uint>(d, s, ok);
2044}
2045
2046/*!
2047 \since 5.13
2048 Returns the long int represented by the localized string \a s.
2049
2050 If the conversion fails the function returns 0.
2051
2052 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2053 to \c false, and success by setting *\a{ok} to \c true.
2054
2055 This function ignores leading and trailing whitespace.
2056
2057 \sa toInt(), toULong(), toDouble(), toString()
2058*/
2059
2060long QLocale::toLong(QStringView s, bool *ok) const
2061{
2062 return toIntegral_helper<long>(d, s, ok);
2063}
2064
2065/*!
2066 \since 5.13
2067 Returns the unsigned long int represented by the localized
2068 string \a s.
2069
2070 If the conversion fails the function returns 0.
2071
2072 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2073 to \c false, and success by setting *\a{ok} to \c true.
2074
2075 This function ignores leading and trailing whitespace.
2076
2077 \sa toLong(), toInt(), toDouble(), toString()
2078*/
2079
2080ulong QLocale::toULong(QStringView s, bool *ok) const
2081{
2082 return toIntegral_helper<ulong>(d, s, ok);
2083}
2084
2085/*!
2086 Returns the long long int represented by the localized string \a s.
2087
2088 If the conversion fails, the function returns 0.
2089
2090 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2091 to \c false, and success by setting *\a{ok} to \c true.
2092
2093 This function ignores leading and trailing whitespace.
2094
2095 \sa toInt(), toULongLong(), toDouble(), toString()
2096
2097 \since 5.10
2098*/
2099
2100
2101qlonglong QLocale::toLongLong(QStringView s, bool *ok) const
2102{
2103 return toIntegral_helper<qlonglong>(d, s, ok);
2104}
2105
2106/*!
2107 Returns the unsigned long long int represented by the localized
2108 string \a s.
2109
2110 If the conversion fails, the function returns 0.
2111
2112 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2113 to \c false, and success by setting *\a{ok} to \c true.
2114
2115 This function ignores leading and trailing whitespace.
2116
2117 \sa toLongLong(), toInt(), toDouble(), toString()
2118
2119 \since 5.10
2120*/
2121
2122qulonglong QLocale::toULongLong(QStringView s, bool *ok) const
2123{
2124 return toIntegral_helper<qulonglong>(d, s, ok);
2125}
2126
2127/*!
2128 Returns the float represented by the localized string \a s.
2129
2130 Returns an infinity if the conversion overflows or 0.0 if the
2131 conversion fails for any other reason (e.g. underflow).
2132
2133 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2134 to \c false, and success by setting *\a{ok} to \c true.
2135
2136 This function ignores leading and trailing whitespace.
2137
2138 \sa toDouble(), toInt(), toString()
2139
2140 \since 5.10
2141*/
2142
2143float QLocale::toFloat(QStringView s, bool *ok) const
2144{
2145 return QLocaleData::convertDoubleToFloat(toDouble(s, ok), ok);
2146}
2147
2148/*!
2149 Returns the double represented by the localized string \a s.
2150
2151 Returns an infinity if the conversion overflows or 0.0 if the
2152 conversion fails for any other reason (e.g. underflow).
2153
2154 If \a ok is not \nullptr, failure is reported by setting *\a{ok}
2155 to \c false, and success by setting *\a{ok} to \c true.
2156
2157 \snippet code/src_corelib_text_qlocale.cpp 3-qstringview
2158
2159 Notice that the last conversion returns 1234.0, because '.' is the
2160 thousands group separator in the German locale.
2161
2162 This function ignores leading and trailing whitespace.
2163
2164 \sa toFloat(), toInt(), toString()
2165
2166 \since 5.10
2167*/
2168
2169double QLocale::toDouble(QStringView s, bool *ok) const
2170{
2171 return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
2172}
2173
2174/*!
2175 Returns a localized string representation of \a i.
2176
2177 \sa toLongLong(), numberOptions(), zeroDigit(), positiveSign()
2178*/
2179
2180QString QLocale::toString(qlonglong i) const
2181{
2182 int flags = (d->m_numberOptions & OmitGroupSeparator
2183 ? 0 : QLocaleData::GroupDigits);
2184
2185 return d->m_data->longLongToString(i, -1, 10, -1, flags);
2186}
2187
2188/*!
2189 \overload
2190
2191 \sa toULongLong(), numberOptions(), zeroDigit(), positiveSign()
2192*/
2193
2194QString QLocale::toString(qulonglong i) const
2195{
2196 int flags = (d->m_numberOptions & OmitGroupSeparator
2197 ? 0 : QLocaleData::GroupDigits);
2198
2199 return d->m_data->unsLongLongToString(i, -1, 10, -1, flags);
2200}
2201// ### Incorrect way of calculating the width, will be fixed soon.
2202static qsizetype stringWidth(QStringView text)
2203{
2204 QStringIterator counter(text);
2205 qsizetype count = 0;
2206 while (counter.hasNext()) {
2207 ++count;
2208 [[maybe_unused]] auto ch = counter.next();
2209 }
2210 return count;
2211}
2212
2213static unsigned calculateFlags(int fieldWidth, char32_t fillChar,
2214 const QLocale &locale)
2215{
2216 unsigned flags = QLocaleData::NoFlags;
2217 if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
2218 flags |= QLocaleData::GroupDigits;
2219 if (fieldWidth < 0)
2221 else if (fillChar == U'0')
2222 flags |= QLocaleData::ZeroPadded;
2223
2224 return flags;
2225}
2226
2227static QString calculateFiller(qsizetype padding,
2228 char32_t fillChar,
2229 [[maybe_unused]] qsizetype fieldWidth,
2230 const QLocaleData *localeData)
2231{
2232 QString filler;
2233 if (fillChar == U'0') {
2234 Q_ASSERT(fieldWidth < 0);
2235 filler = localeData->zeroDigit();
2236 } else {
2237 filler = QString(QChar::fromUcs4(fillChar));
2238 }
2239 // ### size is not width
2240 if (padding > 1)
2241 filler = filler.repeated(padding);
2242 return filler;
2243}
2244
2245/*!
2246 \fn QString QLocale::toString(short number, int fieldWidth, char32_t fillChar) const
2247 \fn QString QLocale::toString(int number, int fieldWidth, char32_t fillChar) const
2248 \fn QString QLocale::toString(long number, int fieldWidth, char32_t fillChar) const
2249 \include qlocale.cpp tostring-with-padding
2250 \include qlocale.cpp tostring-signed-padding
2251*/
2252/*!
2253//! [tostring-with-padding]
2254 Returns a string representation of the given \a number.
2255
2256 The string's length shall be at least the absolute value of \a fieldWidth,
2257 using \a fillChar as padding if the \a number has fewer digits. If
2258 \a fillChar is \c{'0'} the zero digit of this locale is used as padding.
2259 If \a fieldWidth is negative the string starts with its representation
2260 of \a number and, if shorter, is padded to length \c{-fieldWidth} with
2261 the given \a fillChar. For positive fieldWidth, the padding appears before
2262 the representation of \a number.
2263//! [tostring-with-padding]
2264//! [tostring-signed-padding]
2265 When the \a number is negative and \a fieldWidth is positive, if
2266 \a fillChar is a \c{'0'} the padding is inserted between this locale's
2267 minus sign and the start of the number's digits.
2268 \overload toString()
2269//! [tostring-signed-padding]
2270 */
2271QString QLocale::toString(qlonglong number, int fieldWidth, char32_t fillChar) const
2272{
2273 int absFieldWidth = qAbs(fieldWidth);
2274 int width = (fillChar == U'0') ? absFieldWidth : -1;
2275 unsigned flags = calculateFlags(fieldWidth, fillChar, *this);
2276
2277 QString result = d->m_data->longLongToString(number, -1, 10, width, flags);
2278 qsizetype padding = absFieldWidth - stringWidth(result);
2279
2280 if (padding > 0) {
2281 QString filler = calculateFiller(padding, fillChar, fieldWidth, d->m_data);
2282 if (fieldWidth < 0)
2283 result.append(filler);
2284 else
2285 result.prepend(filler);
2286 }
2287 return result;
2288}
2289
2290/*!
2291 \fn QString QLocale::toString(ushort number, int fieldWidth, char32_t fillChar) const
2292 \fn QString QLocale::toString(uint number, int fieldWidth, char32_t fillChar) const
2293 \fn QString QLocale::toString(ulong number, int fieldWidth, char32_t fillChar) const
2294 \include qlocale.cpp tostring-with-padding
2295 \overload toString()
2296 */
2297/*!
2298 \include qlocale.cpp tostring-with-padding
2299 \overload toString()
2300 */
2301QString QLocale::toString(qulonglong number, int fieldWidth, char32_t fillChar) const
2302{
2303 int absFieldWidth = qAbs(fieldWidth);
2304 int width = (fillChar == U'0') ? absFieldWidth : -1;
2305 unsigned flags = calculateFlags(fieldWidth, fillChar, *this);
2306
2307 QString result = d->m_data->unsLongLongToString(number, -1, 10, width, flags);
2308 qsizetype padding = absFieldWidth - stringWidth(result);
2309
2310 if (padding > 0) {
2311 QString filler = calculateFiller(padding, fillChar, fieldWidth, d->m_data);
2312 if (fieldWidth < 0)
2313 result.append(filler);
2314 else
2315 result.prepend(filler);
2316 }
2317 return result;
2318}
2319
2320/*!
2321 \overload
2322*/
2323
2324QString QLocale::toString(QDate date, const QString &format) const
2325{
2326 return toString(date, qToStringViewIgnoringNull(format));
2327}
2328
2329/*!
2330 \overload
2331 Returns a localized string representation of the given \a time according
2332 to the specified \a format (see QTime::toString()).
2333
2334 If \a format is an empty string, an empty string is returned.
2335
2336 \sa dateFormat(), QTime::toString()
2337*/
2338
2339QString QLocale::toString(QTime time, const QString &format) const
2340{
2341 return toString(time, qToStringViewIgnoringNull(format));
2342}
2343
2344/*!
2345 \since 4.4
2346 \fn QString QLocale::toString(const QDateTime &dateTime, const QString &format) const
2347 \overload
2348*/
2349
2350/*!
2351 \since 5.14
2352 \overload
2353
2354 Returns a localized string representation of the given \a date in the
2355 specified \a format (see QDate::toString()), optionally for a specified
2356 calendar \a cal.
2357
2358 If \a format is an empty string, an empty string is returned.
2359
2360 \sa dateFormat(), QDate::toString()
2361*/
2362QString QLocale::toString(QDate date, QStringView format, QCalendar cal) const
2363{
2364 return cal.dateTimeToString(format, QDateTime(), date, QTime(), *this);
2365}
2366
2367/*!
2368 \since 5.10
2369 \overload
2370*/
2371QString QLocale::toString(QDate date, QStringView format) const
2372{
2373 return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
2374}
2375
2376/*!
2377 \since 5.14
2378
2379 Returns a localized string representation of the given \a date according to
2380 the specified \a format (see dateFormat()), optionally for a specified
2381 calendar \a cal.
2382
2383 \note Some locales may use formats that limit the range of years they can
2384 represent. Some locales' use of two-digit years may lead to ambiguity.
2385*/
2386QString QLocale::toString(QDate date, FormatType format, QCalendar cal) const
2387{
2388 if (!date.isValid())
2389 return QString();
2390
2391#ifndef QT_NO_SYSTEMLOCALE
2392 if (cal.isGregorian() && d->m_data == &systemLocaleData) {
2393 QVariant res = systemLocale()->query(format == LongFormat
2394 ? QSystemLocale::DateToStringLong
2395 : QSystemLocale::DateToStringShort,
2396 date);
2397 if (!res.isNull())
2398 return res.toString();
2399 }
2400#endif
2401
2402 QString format_str = dateFormat(format);
2403 return toString(date, format_str, cal);
2404}
2405
2406/*!
2407 \since 4.5
2408 \overload
2409*/
2410QString QLocale::toString(QDate date, FormatType format) const
2411{
2412 if (!date.isValid())
2413 return QString();
2414
2415#ifndef QT_NO_SYSTEMLOCALE
2416 if (d->m_data == &systemLocaleData) {
2417 QVariant res = systemLocale()->query(format == LongFormat
2418 ? QSystemLocale::DateToStringLong
2419 : QSystemLocale::DateToStringShort,
2420 date);
2421 if (!res.isNull())
2422 return res.toString();
2423 }
2424#endif
2425
2426 QString format_str = dateFormat(format);
2427 return toString(date, format_str);
2428}
2429
2430static bool timeFormatContainsAP(QStringView format)
2431{
2432 qsizetype i = 0;
2433 while (i < format.size()) {
2434 if (format.at(i).unicode() == '\'') {
2435 qt_readEscapedFormatString(format, &i);
2436 continue;
2437 }
2438
2439 if (format.at(i).toLower().unicode() == 'a')
2440 return true;
2441
2442 ++i;
2443 }
2444 return false;
2445}
2446
2447/*!
2448 \since 4.5
2449 \overload
2450*/
2451QString QLocale::toString(QTime time, QStringView format) const
2452{
2453 return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
2454}
2455
2456/*!
2457 \since 5.14
2458
2459 Returns a localized string representation of the given \a dateTime according
2460 to the specified \a format (see QDateTime::toString()), optionally for a
2461 specified calendar \a cal.
2462
2463 If \a format is an empty string, an empty string is returned.
2464
2465 \sa QDateTime::toString(), QDate::toString(), QTime::toString()
2466*/
2467QString QLocale::toString(const QDateTime &dateTime, QStringView format, QCalendar cal) const
2468{
2469 return cal.dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2470}
2471
2472/*!
2473 \since 5.10
2474 \overload
2475*/
2476QString QLocale::toString(const QDateTime &dateTime, QStringView format) const
2477{
2478 return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
2479}
2480
2481/*!
2482 \since 5.14
2483
2484 Returns a localized string representation of the given \a dateTime according
2485 to the specified \a format (see dateTimeFormat()), optionally for a
2486 specified calendar \a cal.
2487
2488 \note Some locales may use formats that limit the range of years they can
2489 represent. Some locales' use of two-digit years may lead to ambiguity.
2490*/
2491QString QLocale::toString(const QDateTime &dateTime, FormatType format, QCalendar cal) const
2492{
2493 if (!dateTime.isValid())
2494 return QString();
2495
2496#ifndef QT_NO_SYSTEMLOCALE
2497 if (cal.isGregorian() && d->m_data == &systemLocaleData) {
2498 QVariant res = systemLocale()->query(format == LongFormat
2499 ? QSystemLocale::DateTimeToStringLong
2500 : QSystemLocale::DateTimeToStringShort,
2501 dateTime);
2502 if (!res.isNull())
2503 return res.toString();
2504 }
2505#endif
2506
2507 const QString format_str = dateTimeFormat(format);
2508 return toString(dateTime, format_str, cal);
2509}
2510
2511/*!
2512 \since 4.4
2513 \overload
2514*/
2515QString QLocale::toString(const QDateTime &dateTime, FormatType format) const
2516{
2517 if (!dateTime.isValid())
2518 return QString();
2519
2520#ifndef QT_NO_SYSTEMLOCALE
2521 if (d->m_data == &systemLocaleData) {
2522 QVariant res = systemLocale()->query(format == LongFormat
2523 ? QSystemLocale::DateTimeToStringLong
2524 : QSystemLocale::DateTimeToStringShort,
2525 dateTime);
2526 if (!res.isNull())
2527 return res.toString();
2528 }
2529#endif
2530
2531 const QString format_str = dateTimeFormat(format);
2532 return toString(dateTime, format_str);
2533}
2534
2535
2536/*!
2537 Returns a localized string representation of the given \a time in the
2538 specified \a format (see timeFormat()).
2539*/
2540
2541QString QLocale::toString(QTime time, FormatType format) const
2542{
2543 if (!time.isValid())
2544 return QString();
2545
2546#ifndef QT_NO_SYSTEMLOCALE
2547 if (d->m_data == &systemLocaleData) {
2548 QVariant res = systemLocale()->query(format == LongFormat
2549 ? QSystemLocale::TimeToStringLong
2550 : QSystemLocale::TimeToStringShort,
2551 time);
2552 if (!res.isNull())
2553 return res.toString();
2554 }
2555#endif
2556
2557 QString format_str = timeFormat(format);
2558 return toString(time, format_str);
2559}
2560
2561/*!
2562 \since 4.1
2563
2564 Returns the date format used for the current locale.
2565
2566 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2567 For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy},
2568 ShortFormat is \c{M/d/yy}.
2569
2570 \sa QDate::toString(), QDate::fromString()
2571*/
2572
2573QString QLocale::dateFormat(FormatType format) const
2574{
2575#ifndef QT_NO_SYSTEMLOCALE
2576 if (d->m_data == &systemLocaleData) {
2577 QVariant res = systemLocale()->query(format == LongFormat
2578 ? QSystemLocale::DateFormatLong
2579 : QSystemLocale::DateFormatShort,
2580 QVariant());
2581 if (!res.isNull())
2582 return res.toString();
2583 }
2584#endif
2585
2586 return (format == LongFormat
2587 ? d->m_data->longDateFormat()
2588 : d->m_data->shortDateFormat()
2589 ).getData(date_format_data);
2590}
2591
2592/*!
2593 \since 4.1
2594
2595 Returns the time format used for the current locale.
2596
2597 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2598 For example, LongFormat for the \c{en_US} locale is \c{h:mm:ss AP t},
2599 ShortFormat is \c{h:mm AP}.
2600
2601 \sa QTime::toString(), QTime::fromString()
2602*/
2603
2604QString QLocale::timeFormat(FormatType format) const
2605{
2606#ifndef QT_NO_SYSTEMLOCALE
2607 if (d->m_data == &systemLocaleData) {
2608 QVariant res = systemLocale()->query(format == LongFormat
2609 ? QSystemLocale::TimeFormatLong
2610 : QSystemLocale::TimeFormatShort,
2611 QVariant());
2612 if (!res.isNull())
2613 return res.toString();
2614 }
2615#endif
2616
2617 return (format == LongFormat
2618 ? d->m_data->longTimeFormat()
2619 : d->m_data->shortTimeFormat()
2620 ).getData(time_format_data);
2621}
2622
2623/*!
2624 \since 4.4
2625
2626 Returns the date time format used for the current locale.
2627
2628 If \a format is LongFormat, the format will be elaborate, otherwise it will be short.
2629 For example, LongFormat for the \c{en_US} locale is \c{dddd, MMMM d, yyyy h:mm:ss AP t},
2630 ShortFormat is \c{M/d/yy h:mm AP}.
2631
2632 \sa QDateTime::toString(), QDateTime::fromString()
2633*/
2634
2635QString QLocale::dateTimeFormat(FormatType format) const
2636{
2637#ifndef QT_NO_SYSTEMLOCALE
2638 if (d->m_data == &systemLocaleData) {
2639 QVariant res = systemLocale()->query(format == LongFormat
2640 ? QSystemLocale::DateTimeFormatLong
2641 : QSystemLocale::DateTimeFormatShort,
2642 QVariant());
2643 if (!res.isNull()) {
2644 return res.toString();
2645 }
2646 }
2647#endif
2648 return dateFormat(format) + u' ' + timeFormat(format);
2649}
2650
2651#if QT_CONFIG(datestring)
2652/*!
2653 \since 4.4
2654
2655 Reads \a string as a time in a locale-specific \a format.
2656
2657 Parses \a string and returns the time it represents. The format of the time
2658 string is chosen according to the \a format parameter (see timeFormat()).
2659
2660 \note Any am/pm indicators used must match \l amText() or \l pmText(),
2661 ignoring case.
2662
2663 If the time could not be parsed, returns an invalid time.
2664
2665 \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2666*/
2667QTime QLocale::toTime(const QString &string, FormatType format) const
2668{
2669 return toTime(string, timeFormat(format));
2670}
2671
2672/*!
2673 \since 4.4
2674
2675 Reads \a string as a date in a locale-specific \a format.
2676
2677 Parses \a string and returns the date it represents. The format of the date
2678 string is chosen according to the \a format parameter (see dateFormat()).
2679
2680//! [base-year-for-short]
2681 Some locales use, particularly for ShortFormat, only the last two digits of
2682 the year. In such a case, the 100 years starting at \a baseYear are the
2683 candidates first considered. Prior to 6.7 there was no \a baseYear parameter
2684 and 1900 was always used. This is the default for \a baseYear, selecting a
2685 year from then to 1999. In some cases, other fields may lead to the next or
2686 previous century being selected, to get a result consistent with all fields
2687 given. See \l QDate::fromString() for details.
2688//! [base-year-for-short]
2689
2690 \note Month and day names, where used, must be given in the locale's
2691 language.
2692
2693 If the date could not be parsed, returns an invalid date.
2694
2695 \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2696*/
2697QDate QLocale::toDate(const QString &string, FormatType format, int baseYear) const
2698{
2699 return toDate(string, dateFormat(format), baseYear);
2700}
2701
2702/*!
2703 \since 5.14
2704 \overload
2705*/
2706QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal, int baseYear) const
2707{
2708 return toDate(string, dateFormat(format), cal, baseYear);
2709}
2710
2711/*!
2712 \since 4.4
2713
2714 Reads \a string as a date-time in a locale-specific \a format.
2715
2716 Parses \a string and returns the date-time it represents. The format of the
2717 date string is chosen according to the \a format parameter (see
2718 dateFormat()).
2719
2720 \include qlocale.cpp base-year-for-short
2721
2722 \note Month and day names, where used, must be given in the locale's
2723 language. Any am/pm indicators used must match \l amText() or \l pmText(),
2724 ignoring case.
2725
2726 If the string could not be parsed, returns an invalid QDateTime.
2727
2728 \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2729*/
2730QDateTime QLocale::toDateTime(const QString &string, FormatType format, int baseYear) const
2731{
2732 return toDateTime(string, dateTimeFormat(format), baseYear);
2733}
2734
2735/*!
2736 \since 5.14
2737 \overload
2738*/
2739QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal,
2740 int baseYear) const
2741{
2742 return toDateTime(string, dateTimeFormat(format), cal, baseYear);
2743}
2744
2745/*!
2746 \since 4.4
2747
2748 Reads \a string as a time in the given \a format.
2749
2750 Parses \a string and returns the time it represents. See QTime::fromString()
2751 for the interpretation of \a format.
2752
2753 \note Any am/pm indicators used must match \l amText() or \l pmText(),
2754 ignoring case.
2755
2756 If \a format is malformed or \a string does not match it, returns an invalid
2757 time.
2758
2759 \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
2760*/
2761QTime QLocale::toTime(const QString &string, const QString &format) const
2762{
2763#if QT_CONFIG(datetimeparser)
2764 QTimePattern pattern = QTimePattern::fromQtFormat(format);
2765 if (pattern.isNull() && !format.isEmpty())
2766 return {};
2767 pattern.setLocale(*this);
2768 if (auto match = pattern.parse(string, QTime(0, 0)); match.size == string.size())
2769 return std::move(match.payload);
2770#else
2771 Q_UNUSED(string);
2772 Q_UNUSED(format);
2773#endif
2774 return {};
2775}
2776
2777/*!
2778 \since 4.4
2779
2780 Reads \a string as a date in the given \a format.
2781
2782 Parses \a string and returns the date it represents. See QDate::fromString()
2783 for the interpretation of \a format.
2784
2785//! [base-year-for-two-digit]
2786 When \a format only specifies the last two digits of a year, the 100 years
2787 starting at \a baseYear are the candidates first considered. Prior to 6.7
2788 there was no \a baseYear parameter and 1900 was always used. This is the
2789 default for \a baseYear, selecting a year from then to 1999. In some cases,
2790 other fields may lead to the next or previous century being selected, to get
2791 a result consistent with all fields given. See \l QDate::fromString() for
2792 details.
2793//! [base-year-for-two-digit]
2794
2795 \note Month and day names, where used, must be given in the locale's
2796 language.
2797
2798 If \a format is malformed or \a string does not match it, returns an invalid
2799 date.
2800
2801 \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
2802*/
2803QDate QLocale::toDate(const QString &string, const QString &format, int baseYear) const
2804{
2805 return toDate(string, format, QCalendar(), baseYear);
2806}
2807
2808/*!
2809 \since 5.14
2810 \overload
2811*/
2812QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal, int baseYear) const
2813{
2814#if QT_CONFIG(datetimeparser)
2815 QDatePattern pattern = QDatePattern::fromQtFormat(format);
2816 if (pattern.isNull() && !format.isEmpty())
2817 return {};
2818 pattern.setLocale(*this);
2819 pattern.setCalendar(cal);
2820 pattern.setBaseYear(baseYear);
2821 if (auto match = pattern.parse(string, QDate(baseYear, 1, 1, cal));
2822 match.size == string.size()) {
2823 return std::move(match.payload);
2824 }
2825#else
2826 Q_UNUSED(string);
2827 Q_UNUSED(format);
2828 Q_UNUSED(cal);
2829 Q_UNUSED(baseYear);
2830#endif
2831 return {};
2832}
2833
2834/*!
2835 \since 4.4
2836
2837 Reads \a string as a date-time in the given \a format.
2838
2839 Parses \a string and returns the date-time it represents. See
2840 QDateTime::fromString() for the interpretation of \a format.
2841
2842 \include qlocale.cpp base-year-for-two-digit
2843
2844 \note Month and day names, where used, must be given in the locale's
2845 language. Any am/pm indicators used must match \l amText() or \l pmText(),
2846 ignoring case.
2847
2848 If \a format is invalid or \a string does not match it, returns an invalid
2849 QDateTime.
2850
2851 If the string can be parsed and represents an invalid date-time (for
2852 example, in a gap skipped by a time-zone transition), the returned QDateTime
2853 represents a nearby datetime that is valid (typically differing from it by
2854 the width of the gap in valid datetimes - in the example given, the hour
2855 skipped by a transition).
2856
2857 \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
2858*/
2859QDateTime QLocale::toDateTime(const QString &string, const QString &format, int baseYear) const
2860{
2861 return toDateTime(string, format, QCalendar(), baseYear);
2862}
2863
2864/*!
2865 \since 5.14
2866 \overload
2867*/
2868QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal,
2869 int baseYear) const
2870{
2871#if QT_CONFIG(datetimeparser)
2872 QDateTimePattern pattern = QDateTimePattern::fromQtFormat(format);
2873 if (pattern.isNull() && !format.isEmpty())
2874 return {};
2875 pattern.setLocale(*this);
2876 pattern.setCalendar(cal);
2877 pattern.setBaseYear(baseYear);
2878 if (auto match = pattern.parse(string, QDate(baseYear, 1, 1, cal).startOfDay());
2879 match.size == string.size()) {
2880 return std::move(match.payload);
2881 }
2882#else
2883 Q_UNUSED(string);
2884 Q_UNUSED(format);
2885 Q_UNUSED(cal);
2886 Q_UNUSED(baseYear);
2887#endif
2888 return {};
2889}
2890#endif // datestring
2891
2892/*!
2893 \since 4.1
2894
2895 Returns the fractional part separator for this locale.
2896
2897 This is the token that separates the whole number part from the fracional
2898 part in the representation of a number which has a fractional part. This is
2899 commonly called the "decimal point character" - even though, in many
2900 locales, it is not a "point" (or similar dot). It is (since Qt 6.0) returned
2901 as a string in case some locale needs more than one UTF-16 code-point to
2902 represent its separator.
2903
2904 \sa groupSeparator(), toString()
2905*/
2906QString QLocale::decimalPoint() const
2907{
2908 return d->m_data->decimalPoint();
2909}
2910
2911/*!
2912 \since 4.1
2913
2914 Returns the digit-grouping separator for this locale.
2915
2916 This is a token used to break up long sequences of digits, in the
2917 representation of a number, to make it easier to read. In some locales it
2918 may be empty, indicating that digits should not be broken up into groups in
2919 this way. In others it may be a spacing character. It is (since Qt 6.0)
2920 returned as a string in case some locale needs more than one UTF-16
2921 code-point to represent its separator.
2922
2923 \sa decimalPoint(), toString()
2924*/
2925QString QLocale::groupSeparator() const
2926{
2927 return d->m_data->groupSeparator();
2928}
2929
2930/*!
2931 \since 4.1
2932
2933 Returns the percent marker of this locale.
2934
2935 This is a token presumed to be appended to a number to indicate a
2936 percentage. It is (since Qt 6.0) returned as a string because, in some
2937 locales, it is not a single character - for example, because it includes a
2938 text-direction-control character.
2939
2940 \sa toString()
2941*/
2942QString QLocale::percent() const
2943{
2944 return d->m_data->percentSign();
2945}
2946
2947/*!
2948 \since 4.1
2949
2950 Returns the zero digit character of this locale.
2951
2952 This is a single Unicode character but may be encoded as a surrogate pair,
2953 so is (since Qt 6.0) returned as a string. In most locales, other digits
2954 follow it in Unicode ordering - however, some number systems, notably those
2955 using U+3007 as zero, do not have contiguous digits. Use toString() to
2956 obtain suitable representations of numbers, rather than trying to construct
2957 them from this zero digit.
2958
2959 \sa toString()
2960*/
2961QString QLocale::zeroDigit() const
2962{
2963 return d->m_data->zeroDigit();
2964}
2965
2966/*!
2967 \since 4.1
2968
2969 Returns the negative sign indicator of this locale.
2970
2971 This is a token presumed to be used as a prefix to a number to indicate that
2972 it is negative. It is (since Qt 6.0) returned as a string because, in some
2973 locales, it is not a single character - for example, because it includes a
2974 text-direction-control character.
2975
2976 \sa positiveSign(), toString()
2977*/
2978QString QLocale::negativeSign() const
2979{
2980 return d->m_data->negativeSign();
2981}
2982
2983/*!
2984 \since 4.5
2985
2986 Returns the positive sign indicator of this locale.
2987
2988 This is a token presumed to be used as a prefix to a number to indicate that
2989 it is positive. It is (since Qt 6.0) returned as a string because, in some
2990 locales, it is not a single character - for example, because it includes a
2991 text-direction-control character.
2992
2993 \sa negativeSign(), toString()
2994*/
2995QString QLocale::positiveSign() const
2996{
2997 return d->m_data->positiveSign();
2998}
2999
3000/*!
3001 \since 4.1
3002
3003 Returns the exponent separator for this locale.
3004
3005 This is a token used to separate mantissa from exponent in some
3006 floating-point numeric representations. It is (since Qt 6.0) returned as a
3007 string because, in some locales, it is not a single character - for example,
3008 it may consist of a multiplication sign and a representation of the "ten to
3009 the power" operator.
3010
3011 \sa toString(double, char, int)
3012*/
3013QString QLocale::exponential() const
3014{
3015 return d->m_data->exponentSeparator();
3016}
3017
3018/*!
3019 \overload
3020 Returns a string representing the floating-point number \a f.
3021
3022 The form of the representation is controlled by the \a format and \a
3023 precision parameters.
3024
3025 The \a format defaults to \c{'g'}. It can be any of the following:
3026
3027 \table
3028 \header \li Format \li Meaning \li Meaning of \a precision
3029 \row \li \c 'e' \li format as [-]9.9e[+|-]999 \li number of digits \e after the decimal point
3030 \row \li \c 'E' \li format as [-]9.9E[+|-]999 \li "
3031 \row \li \c 'f' \li format as [-]9.9 \li "
3032 \row \li \c 'F' \li same as \c 'f' except for INF and NAN (see below) \li "
3033 \row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise \li maximum number of significant digits (trailing zeroes are omitted)
3034 \row \li \c 'G' \li use \c 'E' or \c 'F' format, whichever is more concise \li "
3035 \endtable
3036
3037 The special \a precision value QLocale::FloatingPointShortest selects the
3038 shortest representation that, when read as a number, gets back the original floating-point
3039 value. Aside from that, any negative \a precision is ignored in favor of the
3040 default, 6.
3041
3042 For the \c 'e', \c 'f' and \c 'g' formats, positive infinity is represented
3043 as "inf", negative infinity as "-inf" and floating-point NaN (not-a-number)
3044 values are represented as "nan". For the \c 'E', \c 'F' and \c 'G' formats,
3045 "INF" and "NAN" are used instead. This does not vary with locale.
3046
3047 \sa toDouble(), numberOptions(), exponential(), decimalPoint(), zeroDigit(),
3048 positiveSign(), percent(), toCurrencyString(), formattedDataSize(),
3049 QLocale::FloatingPointPrecisionOption
3050*/
3051
3052QString QLocale::toString(double f, char format, int precision) const
3053{
3054 QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
3055 uint flags = isAsciiUpper(format) ? QLocaleData::CapitalEorX : 0;
3056
3057 switch (QtMiscUtils::toAsciiLower(format)) {
3058 case 'f':
3059 form = QLocaleData::DFDecimal;
3060 break;
3061 case 'e':
3062 form = QLocaleData::DFExponent;
3063 break;
3064 case 'g':
3065 form = QLocaleData::DFSignificantDigits;
3066 break;
3067 default:
3068 break;
3069 }
3070
3071 if (!(d->m_numberOptions & OmitGroupSeparator))
3072 flags |= QLocaleData::GroupDigits;
3073 if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
3074 flags |= QLocaleData::ZeroPadExponent;
3075 if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
3076 flags |= QLocaleData::AddTrailingZeroes;
3077 return d->m_data->doubleToString(f, precision, form, -1, flags);
3078}
3079
3080/*!
3081 Returns a QLocale object initialized to the "C" locale.
3082
3083 This locale is based on en_US but with various quirks of its own, such as
3084 simplified number formatting and its own date formatting. It implements the
3085 POSIX standards that describe the behavior of standard library functions of
3086 the "C" programming language.
3087
3088 Among other things, this means its collation order is based on the ASCII
3089 values of letters, so that (for case-sensitive sorting) all upper-case
3090 letters sort before any lower-case one (rather than each letter's upper- and
3091 lower-case forms sorting adjacent to one another, before the next letter's
3092 two forms).
3093
3094 \sa system()
3095*/
3096QLocale QLocale::c() noexcept
3097{
3098 return QLocale(*c_private());
3099}
3100
3101/*!
3102 Returns a QLocale object initialized to the system locale.
3103
3104 The system locale may use system-specific sources for locale data, where
3105 available, otherwise falling back on QLocale's built-in database entry for
3106 the language, script and territory the system reports.
3107
3108 For example, on Windows and Mac, this locale will use the decimal/grouping
3109 characters and date/time formats specified in the system configuration
3110 panel.
3111
3112 \sa c()
3113*/
3114
3115QLocale QLocale::system()
3116{
3117 constexpr auto sysData = []() {
3118 // Same return as systemData(), but leave the setup to the actual call to it.
3119#ifdef QT_NO_SYSTEMLOCALE
3120 return locale_data;
3121#else
3122 return &systemLocaleData;
3123#endif
3124 };
3125 Q_CONSTINIT static QLocalePrivate locale(sysData(), -1, DefaultNumberOptions, 1);
3126 // Calling systemData() ensures system data is up to date; we also need it
3127 // to ensure that locale's index stays up to date:
3128 systemData(&locale.m_index);
3129 Q_ASSERT(locale.m_index >= 0 && locale.m_index < locale_data_size);
3130 locale.m_numberOptions = defaultNumberOptions(locale.m_data->m_language_id);
3131
3132 return QLocale(locale);
3133}
3134
3135/*!
3136 Returns a list of valid locale objects that match the given \a language, \a
3137 script and \a territory.
3138
3139 Getting a list of all locales:
3140 QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
3141 QLocale::AnyTerritory);
3142
3143 Getting a list of locales suitable for Russia:
3144 QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
3145 QLocale::Russia);
3146*/
3147QList<QLocale> QLocale::matchingLocales(Language language, Script script, Territory territory)
3148{
3149 QList<QLocale> result;
3150
3151 const QLocaleId filter { language, script, territory };
3152 if (!filter.isValid())
3153 return result;
3154
3155 if (language == C) {
3156 result.emplace_back(C);
3157 return result;
3158 }
3159
3160 if (filter.matchesAll())
3161 result.reserve(locale_data_size);
3162
3163 quint16 index = locale_index[language];
3164 // There may be no matches, for some languages (e.g. Abkhazian at CLDR v39).
3165 while (index < locale_data_size
3166 && filter.acceptLanguage(locale_data[index].m_language_id)) {
3167 const QLocaleId id = locale_data[index].id();
3168 if (filter.acceptScriptTerritory(id)) {
3169 result.append(QLocale(*(id.language_id == C ? c_private()
3170 : new QLocalePrivate(locale_data + index, index))));
3171 }
3172 ++index;
3173 }
3174
3175 // Add current system locale, if it matches
3176 const auto syslocaledata = systemData();
3177
3178 if (filter.acceptLanguage(syslocaledata->m_language_id)) {
3179 const QLocaleId id = syslocaledata->id();
3180 if (filter.acceptScriptTerritory(id))
3181 result.append(system());
3182 }
3183
3184 return result;
3185}
3186
3187#if QT_DEPRECATED_SINCE(6, 6)
3188/*!
3189 \deprecated [6.6] Use \l matchingLocales() instead and consult the \l territory() of each.
3190 \since 4.3
3191
3192 Returns the list of countries that have entries for \a language in Qt's locale
3193 database. If the result is an empty list, then \a language is not represented in
3194 Qt's locale database.
3195
3196 \sa matchingLocales()
3197*/
3198QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
3199{
3200 const auto locales = matchingLocales(language, AnyScript, AnyCountry);
3201 QList<Country> result;
3202 result.reserve(locales.size());
3203 for (const auto &locale : locales)
3204 result.append(locale.territory());
3205 return result;
3206}
3207#endif
3208
3209/*!
3210 \since 4.2
3211
3212 Returns the localized name of \a month, in the format specified
3213 by \a type.
3214
3215 For example, if the locale is \c en_US and \a month is 1,
3216 \l LongFormat will return \c January. \l ShortFormat \c Jan,
3217 and \l NarrowFormat \c J.
3218
3219 \sa dayName(), standaloneMonthName()
3220*/
3221QString QLocale::monthName(int month, FormatType type) const
3222{
3223 return QCalendar().monthName(*this, month, QCalendar::Unspecified, type);
3224}
3225
3226/*!
3227 \since 4.5
3228
3229 Returns the localized name of \a month that is used as a
3230 standalone text, in the format specified by \a type.
3231
3232 If the locale information doesn't specify the standalone month
3233 name then return value is the same as in monthName().
3234
3235 \sa monthName(), standaloneDayName()
3236*/
3237QString QLocale::standaloneMonthName(int month, FormatType type) const
3238{
3239 return QCalendar().standaloneMonthName(*this, month, QCalendar::Unspecified, type);
3240}
3241
3242/*!
3243 \since 4.2
3244
3245 Returns the localized name of the \a day (where 1 represents
3246 Monday, 2 represents Tuesday and so on), in the format specified
3247 by \a type.
3248
3249 For example, if the locale is \c en_US and \a day is 1,
3250 \l LongFormat will return \c Monday, \l ShortFormat \c Mon,
3251 and \l NarrowFormat \c M.
3252
3253 \sa monthName(), standaloneDayName()
3254*/
3255QString QLocale::dayName(int day, FormatType type) const
3256{
3257 return QCalendar().weekDayName(*this, day, type);
3258}
3259
3260/*!
3261 \since 4.5
3262
3263 Returns the localized name of the \a day (where 1 represents
3264 Monday, 2 represents Tuesday and so on) that is used as a
3265 standalone text, in the format specified by \a type.
3266
3267 If the locale information does not specify the standalone day
3268 name then return value is the same as in dayName().
3269
3270 \sa dayName(), standaloneMonthName()
3271*/
3272QString QLocale::standaloneDayName(int day, FormatType type) const
3273{
3274 return QCalendar().standaloneWeekDayName(*this, day, type);
3275}
3276
3277// Calendar look-up of month and day names:
3278
3279// Get locale-specific month name data:
3281 const QCalendarLocale *table)
3282{
3283 // Only used in assertions
3284 [[maybe_unused]] const auto sameLocale = [](const QLocaleData &locale,
3285 const QCalendarLocale &cal) {
3286 return locale.m_language_id == cal.m_language_id
3287 && locale.m_script_id == cal.m_script_id
3288 && locale.m_territory_id == cal.m_territory_id;
3289 };
3290 const QCalendarLocale &monthly = table[loc->m_index];
3291#ifdef QT_NO_SYSTEMLOCALE
3292 [[maybe_unused]] constexpr bool isSys = false;
3293#else // Can't have preprocessor directives in a macro's parameter list, so use local.
3294 [[maybe_unused]] const bool isSys = loc->m_data == &systemLocaleData;
3295#endif
3296 Q_ASSERT(loc->m_data == &locale_data[loc->m_index] || isSys);
3297 // Compare monthly to locale_data[] entry, as the m_index used with
3298 // systemLocaleData is a best fit, not necessarily an exact match.
3299 Q_ASSERT(sameLocale(locale_data[loc->m_index], monthly));
3300 return monthly;
3301}
3302
3303/*!
3304 \internal
3305 */
3306
3307static QString rawMonthName(const QCalendarLocale &localeData,
3308 const char16_t *monthsData, int month,
3309 QLocale::FormatType type)
3310{
3311 const QLocaleData::DataRange range = localeData.monthName(type);
3312 return range.getListEntry(monthsData, month - 1);
3313}
3314
3315/*!
3316 \internal
3317 */
3318
3319static QString rawStandaloneMonthName(const QCalendarLocale &localeData,
3320 const char16_t *monthsData, int month,
3321 QLocale::FormatType type)
3322{
3323 const QLocaleData::DataRange range = localeData.standaloneMonthName(type);
3324 if (QString name = range.getListEntry(monthsData, month - 1); !name.isEmpty())
3325 return name;
3326 return rawMonthName(localeData, monthsData, month, type);
3327}
3328
3329/*!
3330 \internal
3331 */
3332
3333static QString rawWeekDayName(const QLocaleData *data, const int day,
3334 QLocale::FormatType type)
3335{
3336 QLocaleData::DataRange range;
3337 switch (type) {
3338 case QLocale::LongFormat:
3339 range = data->longDayNames();
3340 break;
3341 case QLocale::ShortFormat:
3342 range = data->shortDayNames();
3343 break;
3344 case QLocale::NarrowFormat:
3345 range = data->narrowDayNames();
3346 break;
3347 default:
3348 return QString();
3349 }
3350 return range.getListEntry(days_data, day == 7 ? 0 : day);
3351}
3352
3353/*!
3354 \internal
3355 */
3356
3357static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day,
3358 QLocale::FormatType type)
3359{
3360 QLocaleData::DataRange range;
3361 switch (type) {
3362 case QLocale::LongFormat:
3363 range =data->longDayNamesStandalone();
3364 break;
3365 case QLocale::ShortFormat:
3366 range = data->shortDayNamesStandalone();
3367 break;
3368 case QLocale::NarrowFormat:
3369 range = data->narrowDayNamesStandalone();
3370 break;
3371 default:
3372 return QString();
3373 }
3374 QString name = range.getListEntry(days_data, day == 7 ? 0 : day);
3375 if (name.isEmpty())
3376 return rawWeekDayName(data, day, type);
3377 return name;
3378}
3379
3380// Refugees from qcalendar.cpp that need functions above:
3381
3382QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
3383 QLocale::FormatType format) const
3384{
3385 Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3386 return rawMonthName(getMonthDataFor(locale.d, localeMonthIndexData()),
3387 localeMonthData(), month, format);
3388}
3389
3390QString QRomanCalendar::monthName(const QLocale &locale, int month, int year,
3391 QLocale::FormatType format) const
3392{
3393#ifndef QT_NO_SYSTEMLOCALE
3394 if (locale.d->m_data == &systemLocaleData) {
3395 Q_ASSERT(month >= 1 && month <= 12);
3396 QSystemLocale::QueryType queryType = QSystemLocale::MonthNameLong;
3397 switch (format) {
3398 case QLocale::LongFormat:
3399 queryType = QSystemLocale::MonthNameLong;
3400 break;
3401 case QLocale::ShortFormat:
3402 queryType = QSystemLocale::MonthNameShort;
3403 break;
3404 case QLocale::NarrowFormat:
3405 queryType = QSystemLocale::MonthNameNarrow;
3406 break;
3407 }
3408 QVariant res = systemLocale()->query(queryType, month);
3409 if (!res.isNull())
3410 return res.toString();
3411 }
3412#endif
3413
3414 return QCalendarBackend::monthName(locale, month, year, format);
3415}
3416
3417QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month, int,
3418 QLocale::FormatType format) const
3419{
3420 Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
3421 return rawStandaloneMonthName(getMonthDataFor(locale.d, localeMonthIndexData()),
3422 localeMonthData(), month, format);
3423}
3424
3425QString QRomanCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
3426 QLocale::FormatType format) const
3427{
3428#ifndef QT_NO_SYSTEMLOCALE
3429 if (locale.d->m_data == &systemLocaleData) {
3430 Q_ASSERT(month >= 1 && month <= 12);
3431 QSystemLocale::QueryType queryType = QSystemLocale::StandaloneMonthNameLong;
3432 switch (format) {
3433 case QLocale::LongFormat:
3434 queryType = QSystemLocale::StandaloneMonthNameLong;
3435 break;
3436 case QLocale::ShortFormat:
3437 queryType = QSystemLocale::StandaloneMonthNameShort;
3438 break;
3439 case QLocale::NarrowFormat:
3440 queryType = QSystemLocale::StandaloneMonthNameNarrow;
3441 break;
3442 }
3443 QVariant res = systemLocale()->query(queryType, month);
3444 if (!res.isNull())
3445 return res.toString();
3446 }
3447#endif
3448
3449 return QCalendarBackend::standaloneMonthName(locale, month, year, format);
3450}
3451
3452// Most calendars share the common week-day naming, modulo locale.
3453// Calendars that don't must override these methods.
3454QString QCalendarBackend::weekDayName(const QLocale &locale, int day,
3455 QLocale::FormatType format) const
3456{
3457 if (day < 1 || day > 7)
3458 return QString();
3459
3460#ifndef QT_NO_SYSTEMLOCALE
3461 if (locale.d->m_data == &systemLocaleData) {
3462 QSystemLocale::QueryType queryType = QSystemLocale::DayNameLong;
3463 switch (format) {
3464 case QLocale::LongFormat:
3465 queryType = QSystemLocale::DayNameLong;
3466 break;
3467 case QLocale::ShortFormat:
3468 queryType = QSystemLocale::DayNameShort;
3469 break;
3470 case QLocale::NarrowFormat:
3471 queryType = QSystemLocale::DayNameNarrow;
3472 break;
3473 }
3474 QVariant res = systemLocale()->query(queryType, day);
3475 if (!res.isNull())
3476 return res.toString();
3477 }
3478#endif
3479
3480 return rawWeekDayName(locale.d->m_data, day, format);
3481}
3482
3483QString QCalendarBackend::standaloneWeekDayName(const QLocale &locale, int day,
3484 QLocale::FormatType format) const
3485{
3486 if (day < 1 || day > 7)
3487 return QString();
3488
3489#ifndef QT_NO_SYSTEMLOCALE
3490 if (locale.d->m_data == &systemLocaleData) {
3491 QSystemLocale::QueryType queryType = QSystemLocale::StandaloneDayNameLong;
3492 switch (format) {
3493 case QLocale::LongFormat:
3494 queryType = QSystemLocale::StandaloneDayNameLong;
3495 break;
3496 case QLocale::ShortFormat:
3497 queryType = QSystemLocale::StandaloneDayNameShort;
3498 break;
3499 case QLocale::NarrowFormat:
3500 queryType = QSystemLocale::StandaloneDayNameNarrow;
3501 break;
3502 }
3503 QVariant res = systemLocale()->query(queryType, day);
3504 if (!res.isNull())
3505 return res.toString();
3506 }
3507#endif
3508
3509 return rawStandaloneWeekDayName(locale.d->m_data, day, format);
3510}
3511
3512// End of this block of qcalendar.cpp refugees. (One more follows.)
3513
3514/*!
3515 \since 4.8
3516
3517 Returns the first day of the week according to the current locale.
3518*/
3519Qt::DayOfWeek QLocale::firstDayOfWeek() const
3520{
3521#ifndef QT_NO_SYSTEMLOCALE
3522 if (d->m_data == &systemLocaleData) {
3523 const auto res = systemLocale()->query(QSystemLocale::FirstDayOfWeek);
3524 if (!res.isNull())
3525 return static_cast<Qt::DayOfWeek>(res.toUInt());
3526 }
3527#endif
3528 return static_cast<Qt::DayOfWeek>(d->m_data->m_first_day_of_week);
3529}
3530
3532{
3533 /* Unicode CLDR's information about measurement systems doesn't say which to
3534 use by default in each locale. Even if it did, adding another entry in
3535 every locale's row of locale_data[] would take up much more memory than
3536 the small table below.
3537 */
3538 struct TerritoryLanguage
3539 {
3540 quint16 languageId;
3541 quint16 territoryId;
3542 QLocale::MeasurementSystem system;
3543 };
3544 // TODO: research how realistic and/or complete this is:
3545 constexpr TerritoryLanguage ImperialMeasurementSystems[] = {
3546 { QLocale::English, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3547 { QLocale::English, QLocale::UnitedStatesMinorOutlyingIslands, QLocale::ImperialUSSystem },
3548 { QLocale::Spanish, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3549 { QLocale::Hawaiian, QLocale::UnitedStates, QLocale::ImperialUSSystem },
3550 { QLocale::English, QLocale::UnitedKingdom, QLocale::ImperialUKSystem }
3551 };
3552
3553 for (const auto &system : ImperialMeasurementSystems) {
3554 if (system.languageId == m_data->m_language_id
3555 && system.territoryId == m_data->m_territory_id) {
3556 return system.system;
3557 }
3558 }
3559 return QLocale::MetricSystem;
3560}
3561
3562/*!
3563 \since 4.8
3564
3565 Returns a list of days that are considered weekdays according to the current locale.
3566*/
3567QList<Qt::DayOfWeek> QLocale::weekdays() const
3568{
3569#ifndef QT_NO_SYSTEMLOCALE
3570 if (d->m_data == &systemLocaleData) {
3571 auto res
3572 = qvariant_cast<QList<Qt::DayOfWeek> >(systemLocale()->query(QSystemLocale::Weekdays));
3573 if (!res.isEmpty())
3574 return res;
3575 }
3576#endif
3577 QList<Qt::DayOfWeek> weekdays;
3578 quint16 weekendStart = d->m_data->m_weekend_start;
3579 quint16 weekendEnd = d->m_data->m_weekend_end;
3580 for (int day = Qt::Monday; day <= Qt::Sunday; day++) {
3581 if ((weekendEnd >= weekendStart && (day < weekendStart || day > weekendEnd)) ||
3582 (weekendEnd < weekendStart && (day > weekendEnd && day < weekendStart)))
3583 weekdays << static_cast<Qt::DayOfWeek>(day);
3584 }
3585 return weekdays;
3586}
3587
3588/*!
3589 \since 4.4
3590
3591 Returns the measurement system for the locale.
3592*/
3593QLocale::MeasurementSystem QLocale::measurementSystem() const
3594{
3595#ifndef QT_NO_SYSTEMLOCALE
3596 if (d->m_data == &systemLocaleData) {
3597 const auto res = systemLocale()->query(QSystemLocale::MeasurementSystem);
3598 if (!res.isNull())
3599 return MeasurementSystem(res.toInt());
3600 }
3601#endif
3602
3603 return d->measurementSystem();
3604}
3605
3606/*!
3607 \since 4.7
3608
3609 Returns the text direction of the language.
3610*/
3611Qt::LayoutDirection QLocale::textDirection() const
3612{
3613 switch (script()) {
3614 case AdlamScript:
3615 case ArabicScript:
3616 case AvestanScript:
3617 case CypriotScript:
3618 case HatranScript:
3619 case HebrewScript:
3620 case ImperialAramaicScript:
3621 case InscriptionalPahlaviScript:
3622 case InscriptionalParthianScript:
3623 case KharoshthiScript:
3624 case LydianScript:
3625 case MandaeanScript:
3626 case ManichaeanScript:
3627 case MendeKikakuiScript:
3628 case MeroiticCursiveScript:
3629 case MeroiticScript:
3630 case NabataeanScript:
3631 case NkoScript:
3632 case OldHungarianScript:
3633 case OldNorthArabianScript:
3634 case OldSouthArabianScript:
3635 case OrkhonScript:
3636 case PalmyreneScript:
3637 case PhoenicianScript:
3638 case PsalterPahlaviScript:
3639 case SamaritanScript:
3640 case SyriacScript:
3641 case ThaanaScript:
3642 return Qt::RightToLeft;
3643 default:
3644 break;
3645 }
3646 return Qt::LeftToRight;
3647}
3648
3649/*!
3650 \since 4.8
3651
3652 Returns an uppercase copy of \a str.
3653
3654 If Qt Core is using the ICU libraries, they will be used to perform
3655 the transformation according to the rules of the current locale.
3656 Otherwise the conversion may be done in a platform-dependent manner,
3657 with QString::toUpper() as a generic fallback.
3658
3659 \note In some cases the uppercase form of a string may be longer than the
3660 original.
3661
3662 \sa QString::toUpper()
3663*/
3664QString QLocale::toUpper(const QString &str) const
3665{
3666#if !defined(QT_BOOTSTRAPPED) && (QT_CONFIG(icu) || defined(Q_OS_WIN) || defined(Q_OS_APPLE))
3667 bool ok = true;
3668 QString result = d->toUpper(str, &ok);
3669 if (ok)
3670 return result;
3671 // else fall through and use Qt's toUpper
3672#endif
3673 return str.toUpper();
3674}
3675
3676/*!
3677 \since 4.8
3678
3679 Returns a lowercase copy of \a str.
3680
3681 If Qt Core is using the ICU libraries, they will be used to perform
3682 the transformation according to the rules of the current locale.
3683 Otherwise the conversion may be done in a platform-dependent manner,
3684 with QString::toLower() as a generic fallback.
3685
3686 \sa QString::toLower()
3687*/
3688QString QLocale::toLower(const QString &str) const
3689{
3690#if !defined(QT_BOOTSTRAPPED) && (QT_CONFIG(icu) || defined(Q_OS_WIN) || defined(Q_OS_APPLE))
3691 bool ok = true;
3692 const QString result = d->toLower(str, &ok);
3693 if (ok)
3694 return result;
3695 // else fall through and use Qt's toLower
3696#endif
3697 return str.toLower();
3698}
3699
3700
3701/*!
3702 \since 4.5
3703
3704 Returns the localized name of the "AM" suffix for times specified using
3705 the conventions of the 12-hour clock.
3706
3707 \sa pmText()
3708*/
3709QString QLocale::amText() const
3710{
3711#ifndef QT_NO_SYSTEMLOCALE
3712 if (d->m_data == &systemLocaleData) {
3713 auto res = systemLocale()->query(QSystemLocale::AMText).toString();
3714 if (!res.isEmpty())
3715 return res;
3716 }
3717#endif
3718 return d->m_data->anteMeridiem().getData(am_data);
3719}
3720
3721/*!
3722 \since 4.5
3723
3724 Returns the localized name of the "PM" suffix for times specified using
3725 the conventions of the 12-hour clock.
3726
3727 \sa amText()
3728*/
3729QString QLocale::pmText() const
3730{
3731#ifndef QT_NO_SYSTEMLOCALE
3732 if (d->m_data == &systemLocaleData) {
3733 auto res = systemLocale()->query(QSystemLocale::PMText).toString();
3734 if (!res.isEmpty())
3735 return res;
3736 }
3737#endif
3738 return d->m_data->postMeridiem().getData(pm_data);
3739}
3740
3741// For the benefit of QCalendar, below.
3742static QString offsetFromAbbreviation(QString &&text)
3743{
3744 QStringView tail{text};
3745 // May need to strip a prefix:
3746 if (tail.startsWith("UTC"_L1) || tail.startsWith("GMT"_L1))
3747 tail = tail.sliced(3);
3748 // TODO: there may be a locale-specific alternative prefix.
3749 // Hard to know without zone-name L10n details, though.
3750 return (tail.isEmpty() // The Qt::UTC case omits the zero offset:
3751 ? u"+00:00"_s
3752 // Whole-hour offsets may lack the zero minutes:
3753 : (tail.size() <= 3
3754 ? tail + ":00"_L1
3755 : std::move(text).right(tail.size())));
3756}
3757
3758// For the benefit of QCalendar, below, when not provided by QTZL.
3759#if !QT_CONFIG(datestring)
3760// No need for temporal data serialization and parsing code.
3761#elif QT_CONFIG(icu) || !(QT_CONFIG(timezone) && QT_CONFIG(timezone_locale))
3762namespace QtTimeZoneLocale {
3763
3764// TODO: is there a way to get this non-kludgily from ICU ?
3765// If so, that version goes in QTZL.cpp's relevant #if-ery branch.
3766QString zoneOffsetFormat([[maybe_unused]] const QLocale &locale,
3767 qsizetype,
3768 QtTemporalPattern::TemporalFieldFlags,
3769 const QDateTime &when,
3770 int offsetSeconds)
3771{
3772 // Only the non-ICU TZ-locale code uses the prefix forms, so this tacitly
3773 // assumes flags: Numeric | Abbreviated | NeedNoUtcPrefix | ZeroPad.
3774 QString text =
3775#if QT_CONFIG(timezone)
3776 locale != QLocale::system()
3777 ? when.timeRepresentation().displayName(when, QTimeZone::OffsetName, locale)
3778 :
3779#endif
3780 when.toOffsetFromUtc(offsetSeconds).timeZoneAbbreviation();
3781
3782 if (!text.isEmpty())
3783 text = offsetFromAbbreviation(std::move(text));
3784 // else: no suitable representation of the zone.
3785 return text;
3786}
3787
3788} // QtTimeZoneLocale
3789#endif // ICU or no TZ L10n
3790
3791// Another intrusion from QCalendar, using some of the tools above:
3792QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &datetime,
3793 QDate dateOnly, QTime timeOnly,
3794 const QLocale &locale) const
3795{
3796 QDate date;
3797 QTime time;
3798 bool formatDate = false;
3799 bool formatTime = false;
3800 if (datetime.isValid()) {
3801 date = datetime.date();
3802 time = datetime.time();
3803 formatDate = true;
3804 formatTime = true;
3805 } else if (dateOnly.isValid()) {
3806 date = dateOnly;
3807 formatDate = true;
3808 } else if (timeOnly.isValid()) {
3809 time = timeOnly;
3810 formatTime = true;
3811 } else {
3812 return QString();
3813 }
3814
3815 QString result;
3816 int year = 0, month = 0, day = 0;
3817 if (formatDate) {
3818 const auto parts = julianDayToDate(date.toJulianDay());
3819 if (!parts.isValid())
3820 return QString();
3821 year = parts.year;
3822 month = parts.month;
3823 day = parts.day;
3824 }
3825
3826 auto appendToResult = [&](int t, int repeat) {
3827 auto data = locale.d->m_data;
3828 if (repeat > 1)
3829 result.append(data->longLongToString(t, -1, 10, repeat, QLocaleData::ZeroPadded));
3830 else
3831 result.append(data->longLongToString(t));
3832 };
3833
3834 auto formatType = [](int repeat) {
3835 return repeat == 3 ? QLocale::ShortFormat : QLocale::LongFormat;
3836 };
3837
3838 qsizetype i = 0;
3839 while (i < format.size()) {
3840 if (format.at(i).unicode() == '\'') {
3841 result.append(qt_readEscapedFormatString(format, &i));
3842 continue;
3843 }
3844
3845 const QChar c = format.at(i);
3846 qsizetype rep = qt_repeatCount(format.mid(i));
3847 Q_ASSERT(rep < std::numeric_limits<int>::max());
3848 int repeat = int(rep);
3849 bool used = false;
3850 if (formatDate) {
3851 switch (c.unicode()) {
3852 case 'y':
3853 used = true;
3854 if (repeat >= 4)
3855 repeat = 4;
3856 else if (repeat >= 2)
3857 repeat = 2;
3858
3859 switch (repeat) {
3860 case 4:
3861 // Years with more than four digits must have a sign:
3862 if (year > 9999)
3863 result.append(locale.positiveSign());
3864 appendToResult(year, (year < 0) ? 5 : 4);
3865 break;
3866 case 2:
3867 appendToResult(year % 100, 2);
3868 break;
3869 default:
3870 repeat = 1;
3871 result.append(c);
3872 break;
3873 }
3874 break;
3875
3876 case 'M':
3877 used = true;
3878 repeat = qMin(repeat, 4);
3879 if (repeat <= 2)
3880 appendToResult(month, repeat);
3881 else
3882 result.append(monthName(locale, month, year, formatType(repeat)));
3883 break;
3884
3885 case 'd':
3886 used = true;
3887 repeat = qMin(repeat, 4);
3888 if (repeat <= 2)
3889 appendToResult(day, repeat);
3890 else
3891 result.append(
3892 locale.dayName(dayOfWeek(date.toJulianDay()), formatType(repeat)));
3893 break;
3894
3895 default:
3896 break;
3897 }
3898 }
3899 if (!used && formatTime) {
3900 switch (c.unicode()) {
3901 case 'h': {
3902 used = true;
3903 repeat = qMin(repeat, 2);
3904 int hour = time.hour();
3905 if (timeFormatContainsAP(format)) {
3906 if (hour > 12)
3907 hour -= 12;
3908 else if (hour == 0)
3909 hour = 12;
3910 }
3911 appendToResult(hour, repeat);
3912 break;
3913 }
3914 case 'H':
3915 used = true;
3916 repeat = qMin(repeat, 2);
3917 appendToResult(time.hour(), repeat);
3918 break;
3919
3920 case 'm':
3921 used = true;
3922 repeat = qMin(repeat, 2);
3923 appendToResult(time.minute(), repeat);
3924 break;
3925
3926 case 's':
3927 used = true;
3928 repeat = qMin(repeat, 2);
3929 appendToResult(time.second(), repeat);
3930 break;
3931
3932 case 'A':
3933 case 'a': {
3934 QString text = time.hour() < 12 ? locale.amText() : locale.pmText();
3935 used = true;
3936 repeat = 1;
3937 if (format.mid(i + 1).startsWith(u'p', Qt::CaseInsensitive))
3938 ++repeat;
3939 if (c.unicode() == 'A' && (repeat == 1 || format.at(i + 1).unicode() == 'P'))
3940 text = std::move(text).toUpper();
3941 else if (c.unicode() == 'a' && (repeat == 1 || format.at(i + 1).unicode() == 'p'))
3942 text = std::move(text).toLower();
3943 // else 'Ap' or 'aP' => use CLDR text verbatim, preserving case
3944 result.append(text);
3945 break;
3946 }
3947
3948 case 'z':
3949 used = true;
3950 repeat = qMin(repeat, 3);
3951
3952 // note: the millisecond component is treated like the decimal part of the seconds
3953 // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200"
3954 appendToResult(time.msec(), 3);
3955 if (repeat != 3) {
3956 const QString zero = locale.zeroDigit();
3957 if (result.endsWith(zero))
3958 result.chop(zero.size());
3959 if (result.endsWith(zero))
3960 result.chop(zero.size());
3961 }
3962 break;
3963
3964 case 't': {
3965#if QT_CONFIG(datestring)
3966 // Feature check should really apply to the whole function, but
3967 // this portion of it depends on internals entangled with the
3968 // feature.
3969 enum AbbrType { Long, Offset, Short };
3970 const auto tzAbbr = [locale](const QDateTime &when, AbbrType type) {
3971 QString text;
3972 if (type == Offset) {
3973 using Flag = QtTemporalPattern::TemporalFieldFlag;
3974 constexpr auto noPrefixOffset = Flag::Numeric | Flag::Abbreviated
3975 | Flag::NeedNoUtcPrefix | Flag::ZeroPad;
3976 text = QtTimeZoneLocale::zoneOffsetFormat(locale, locale.d->m_index,
3977 noPrefixOffset,
3978 when, when.offsetFromUtc());
3979 // When using timezone_locale data, this should always succeed:
3980 if (!text.isEmpty())
3981 return text;
3982 }
3983# if QT_CONFIG(timezone)
3984 if (type != Short || locale != QLocale::system()) {
3985 QTimeZone::NameType mode =
3986 type == Short ? QTimeZone::ShortName
3987 : type == Long ? QTimeZone::LongName : QTimeZone::OffsetName;
3988 text = when.timeRepresentation().displayName(when, mode, locale);
3989 if (!text.isEmpty())
3990 return text;
3991 // else fall back to an unlocalized one if we can find one.
3992 }
3993 if (type == Long) {
3994 // If no long name found, use IANA ID:
3995 text = QString::fromLatin1(when.timeZone().id());
3996 if (!text.isEmpty())
3997 return text;
3998 }
3999 // else: prefer QDateTime's abbreviation, for backwards-compatibility.
4000# endif // else, make do with non-localized abbreviation:
4001 // Absent timezone_locale data, Offset might still reach here:
4002 if (type == Offset) // Our prior failure might not have tried this:
4003 text = when.toOffsetFromUtc(when.offsetFromUtc()).timeZoneAbbreviation();
4004 if (text.isEmpty()) // Notably including type != Offset
4005 text = when.timeZoneAbbreviation();
4006 if (type == Offset)
4007 text = offsetFromAbbreviation(std::move(text));
4008 return text;
4009 };
4010
4011 used = true;
4012 repeat = qMin(repeat, 4);
4013 // If we don't have a date-time, use the current system time:
4014 const QDateTime when = formatDate ? datetime : QDateTime::currentDateTime();
4015 QString text;
4016 switch (repeat) {
4017 case 4:
4018 text = tzAbbr(when, Long);
4019 break;
4020 case 3: // ±hh:mm
4021 case 2: // ±hhmm (we'll remove the ':' at the end)
4022 text = tzAbbr(when, Offset);
4023 if (repeat == 2)
4024 text.remove(u':');
4025 break;
4026 default:
4027 text = tzAbbr(when, Short);
4028 // UTC-offset zones only include minutes if non-zero.
4029 if (text.startsWith("UTC"_L1) && text.size() == 6)
4030 text += ":00"_L1;
4031 break;
4032 }
4033 if (!text.isEmpty())
4034 result.append(text);
4035#endif // datestring
4036 break;
4037 }
4038
4039 default:
4040 break;
4041 }
4042 }
4043 if (!used)
4044 result.resize(result.size() + repeat, c);
4045 i += repeat;
4046 }
4047
4048 return result;
4049}
4050// End of QCalendar intrustions
4051
4052QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
4053 int width, unsigned flags) const
4054{
4055 // Although the special handling of F.P.Shortest below is limited to
4056 // DFSignificantDigits, the double-conversion library does treat it
4057 // specially for the other forms, shedding trailing zeros for DFDecimal and
4058 // using the shortest mantissa that faithfully represents the value for
4059 // DFExponent.
4060 if (precision != QLocale::FloatingPointShortest && precision < 0)
4061 precision = 6;
4062 if (width < 0)
4063 width = 0;
4064
4065 int decpt;
4066 qsizetype bufSize = 1;
4067 if (precision == QLocale::FloatingPointShortest)
4068 bufSize += std::numeric_limits<double>::max_digits10;
4069 else if (form == DFDecimal && qt_is_finite(d))
4070 bufSize += wholePartSpace(qAbs(d)) + precision;
4071 else // Add extra digit due to different interpretations of precision.
4072 bufSize += qMax(2, precision) + 1; // Must also be big enough for "nan" or "inf"
4073
4074 QVarLengthArray<char> buf(bufSize);
4075 int length;
4076 bool negative = false;
4077 qt_doubleToAscii(d, form, precision, buf.data(), bufSize, negative, length, decpt);
4078
4079 const QString prefix = signPrefix(negative && !qIsNull(d), flags);
4080 QString numStr;
4081
4082 if (length == 3
4083 && (qstrncmp(buf.data(), "inf", 3) == 0 || qstrncmp(buf.data(), "nan", 3) == 0)) {
4084 numStr = QString::fromLatin1(buf.data(), length);
4085 } else { // Handle finite values
4086 const QString zero = zeroDigit();
4087 QString digits = QString::fromLatin1(buf.data(), length);
4088
4089 if (zero == u"0") {
4090 // No need to convert digits.
4091 Q_ASSERT(std::all_of(buf.cbegin(), buf.cbegin() + length, isAsciiDigit));
4092 // That check is taken care of in unicodeForDigits, below.
4093 } else if (zero.size() == 2 && zero.at(0).isHighSurrogate()) {
4094 const char32_t zeroUcs4 = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
4095 QString converted;
4096 converted.reserve(2 * digits.size());
4097 for (QChar ch : std::as_const(digits)) {
4098 const char32_t digit = unicodeForDigit(ch.unicode() - '0', zeroUcs4);
4099 Q_ASSERT(QChar::requiresSurrogates(digit));
4100 converted.append(QChar::highSurrogate(digit));
4101 converted.append(QChar::lowSurrogate(digit));
4102 }
4103 digits = std::move(converted);
4104 } else {
4105 Q_ASSERT(zero.size() == 1);
4106 Q_ASSERT(!zero.at(0).isSurrogate());
4107 char16_t z = zero.at(0).unicode();
4108 char16_t *const value = reinterpret_cast<char16_t *>(digits.data());
4109 for (qsizetype i = 0; i < digits.size(); ++i)
4110 value[i] = unicodeForDigit(value[i] - '0', z);
4111 }
4112
4113 const bool mustMarkDecimal = flags & ForcePoint;
4114 const bool groupDigits = flags & GroupDigits;
4115 const int minExponentDigits = flags & ZeroPadExponent ? 2 : 1;
4116 switch (form) {
4117 case DFExponent:
4118 numStr = exponentForm(std::move(digits), decpt, precision, PMDecimalDigits,
4119 mustMarkDecimal, minExponentDigits);
4120 break;
4121 case DFDecimal:
4122 numStr = decimalForm(std::move(digits), decpt, precision, PMDecimalDigits,
4123 mustMarkDecimal, groupDigits);
4124 break;
4125 case DFSignificantDigits: {
4126 PrecisionMode mode
4127 = (flags & AddTrailingZeroes) ? PMSignificantDigits : PMChopTrailingZeros;
4128
4129 /* POSIX specifies sprintf() to follow fprintf(), whose 'g/G' format
4130 says; with P = 6 if precision unspecified else 1 if precision is
4131 0 else precision; when 'e/E' would have exponent X, use:
4132 * 'f/F' if P > X >= -4, with precision P-1-X
4133 * 'e/E' otherwise, with precision P-1
4134 Helpfully, we already have mapped precision < 0 to 6 - except for
4135 F.P.Shortest mode, which is its own story - and those of our
4136 callers with unspecified precision either used 6 or -1 for it.
4137 */
4138 bool useDecimal;
4139 if (precision == QLocale::FloatingPointShortest) {
4140 // Find out which representation is shorter.
4141 // Set bias to everything added to exponent form but not
4142 // decimal, minus the converse.
4143
4144 const QLocaleData::GroupSizes grouping = groupSizes();
4145 // Exponent adds separator, sign and digits:
4146 int bias = 2 + minExponentDigits;
4147 // Decimal form may get grouping separators inserted:
4148 if (groupDigits && decpt >= grouping.first + grouping.least)
4149 bias -= (decpt - grouping.least) / grouping.higher + 1;
4150 // X = decpt - 1 needs two digits if decpt > 10:
4151 if (decpt > 10 && minExponentDigits == 1)
4152 ++bias;
4153 // Assume digitCount < 95, so we can ignore the 3-digit
4154 // exponent case (we'll set useDecimal false anyway).
4155
4156 const qsizetype digitCount = digits.size() / zero.size();
4157 if (!mustMarkDecimal) {
4158 // Decimal separator is skipped if at end; adjust if
4159 // that happens for only one form:
4160 if (digitCount <= decpt && digitCount > 1)
4161 ++bias; // decimal but not exponent
4162 else if (digitCount == 1 && decpt <= 0)
4163 --bias; // exponent but not decimal
4164 }
4165 // When 0 < decpt <= digitCount, the forms have equal digit
4166 // counts, plus things bias has taken into account; otherwise
4167 // decimal form's digit count is right-padded with zeros to
4168 // decpt, when decpt is positive, otherwise it's left-padded
4169 // with 1 - decpt zeros.
4170 useDecimal = (decpt <= 0 ? 1 - decpt <= bias
4171 : decpt <= digitCount ? 0 <= bias : decpt <= digitCount + bias);
4172 } else {
4173 // X == decpt - 1, POSIX's P; -4 <= X < P iff -4 < decpt <= P
4174 Q_ASSERT(precision >= 0);
4175 useDecimal = decpt > -4 && decpt <= (precision ? precision : 1);
4176 }
4177
4178 numStr = useDecimal
4179 ? decimalForm(std::move(digits), decpt, precision, mode,
4180 mustMarkDecimal, groupDigits)
4181 : exponentForm(std::move(digits), decpt, precision, mode,
4182 mustMarkDecimal, minExponentDigits);
4183 break;
4184 }
4185 }
4186
4187 // Pad with zeros. LeftAdjusted overrides ZeroPadded.
4188 if (flags & ZeroPadded && !(flags & LeftAdjusted)) {
4189 for (qsizetype i = numStr.size() / zero.size() + prefix.size(); i < width; ++i)
4190 numStr.prepend(zero);
4191 }
4192 }
4193
4194 return prefix + (flags & CapitalEorX
4195 ? std::move(numStr).toUpper()
4196 : std::move(numStr).toLower());
4197}
4198
4199QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision,
4200 PrecisionMode pm, bool mustMarkDecimal,
4201 bool groupDigits) const
4202{
4203 const QString zero = zeroDigit();
4204 const auto digitWidth = zero.size();
4205 Q_ASSERT(digitWidth == 1 || digitWidth == 2);
4206 Q_ASSERT(digits.size() % digitWidth == 0);
4207
4208 // Separator needs to go at index decpt: so add zeros before or after the
4209 // given digits, if they don't reach that position already:
4210 if (decpt < 0) {
4211 for (; decpt < 0; ++decpt)
4212 digits.prepend(zero);
4213 } else {
4214 for (qsizetype i = digits.size() / digitWidth; i < decpt; ++i)
4215 digits.append(zero);
4216 }
4217
4218 switch (pm) {
4219 case PMDecimalDigits:
4220 for (qsizetype i = digits.size() / digitWidth - decpt; i < precision; ++i)
4221 digits.append(zero);
4222 break;
4223 case PMSignificantDigits:
4224 for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
4225 digits.append(zero);
4226 break;
4227 case PMChopTrailingZeros:
4228 Q_ASSERT(digits.size() / digitWidth <= qMax(decpt, 1) || !digits.endsWith(zero));
4229 break;
4230 }
4231
4232 if (mustMarkDecimal || decpt < digits.size() / digitWidth)
4233 digits.insert(decpt * digitWidth, decimalPoint());
4234
4235 if (groupDigits) {
4236 const QLocaleData::GroupSizes grouping = groupSizes();
4237 const QString group = groupSeparator();
4238 qsizetype i = decpt - grouping.least;
4239 if (i >= grouping.first) {
4240 digits.insert(i * digitWidth, group);
4241 while ((i -= grouping.higher) > 0)
4242 digits.insert(i * digitWidth, group);
4243 }
4244 }
4245
4246 if (decpt == 0)
4247 digits.prepend(zero);
4248
4249 return std::move(digits);
4250}
4251
4252QString QLocaleData::exponentForm(QString &&digits, int decpt, int precision,
4253 PrecisionMode pm, bool mustMarkDecimal,
4254 int minExponentDigits) const
4255{
4256 const QString zero = zeroDigit();
4257 const auto digitWidth = zero.size();
4258 Q_ASSERT(digitWidth == 1 || digitWidth == 2);
4259 Q_ASSERT(digits.size() % digitWidth == 0);
4260
4261 switch (pm) {
4262 case PMDecimalDigits:
4263 for (qsizetype i = digits.size() / digitWidth; i < precision + 1; ++i)
4264 digits.append(zero);
4265 break;
4266 case PMSignificantDigits:
4267 for (qsizetype i = digits.size() / digitWidth; i < precision; ++i)
4268 digits.append(zero);
4269 break;
4270 case PMChopTrailingZeros:
4271 Q_ASSERT(digits.size() / digitWidth <= 1 || !digits.endsWith(zero));
4272 break;
4273 }
4274
4275 if (mustMarkDecimal || digits.size() > digitWidth)
4276 digits.insert(digitWidth, decimalPoint());
4277
4278 digits.append(exponentSeparator());
4279 digits.append(longLongToString(decpt - 1, minExponentDigits, 10, -1, AlwaysShowSign));
4280
4281 return std::move(digits);
4282}
4283
4284QString QLocaleData::signPrefix(bool negative, unsigned flags) const
4285{
4286 if (negative)
4287 return negativeSign();
4288 if (flags & AlwaysShowSign)
4289 return positiveSign();
4290 if (flags & BlankBeforePositive)
4291 return u" "_s;
4292 return {};
4293}
4294
4295QString QLocaleData::longLongToString(qlonglong n, int precision,
4296 int base, int width, unsigned flags) const
4297{
4298 bool negative = n < 0;
4299
4300 /*
4301 Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
4302 taking an absolute value has to take a slight detour.
4303 */
4304 QString numStr = qulltoa(negative ? 1u + qulonglong(-(n + 1)) : qulonglong(n),
4305 base, zeroDigit());
4306
4307 return applyIntegerFormatting(std::move(numStr), negative, precision, base, width, flags);
4308}
4309
4310QString QLocaleData::unsLongLongToString(qulonglong l, int precision,
4311 int base, int width, unsigned flags) const
4312{
4313 return applyIntegerFormatting(qulltoa(l, base, zeroDigit()),
4314 false, precision, base, width, flags);
4315}
4316
4317QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int precision,
4318 int base, int width, unsigned flags) const
4319{
4320 const QString zero = base == 10 ? zeroDigit() : QStringLiteral("0");
4321 const auto digitWidth = zero.size();
4322 const auto digitCount = numStr.size() / digitWidth;
4323
4324 const auto basePrefix = [&] () -> QStringView {
4325 if (flags & ShowBase) {
4326 const bool upper = flags & UppercaseBase;
4327 if (base == 16)
4328 return upper ? u"0X" : u"0x";
4329 if (base == 2)
4330 return upper ? u"0B" : u"0b";
4331 if (base == 8 && !numStr.startsWith(zero))
4332 return zero;
4333 }
4334 return {};
4335 }();
4336
4337 const QString prefix = signPrefix(negative, flags) + basePrefix;
4338 // Count how much of width we've used up. Each digit counts as one
4339 qsizetype usedWidth = digitCount + prefix.size();
4340
4341 if (base == 10 && flags & GroupDigits) {
4342 const QLocaleData::GroupSizes grouping = groupSizes();
4343 const QString group = groupSeparator();
4344 qsizetype i = digitCount - grouping.least;
4345 if (i >= grouping.first) {
4346 numStr.insert(i * digitWidth, group);
4347 ++usedWidth;
4348 while ((i -= grouping.higher) > 0) {
4349 numStr.insert(i * digitWidth, group);
4350 ++usedWidth;
4351 }
4352 }
4353 // TODO: should we group any zero-padding we add later ?
4354 }
4355
4356 const bool noPrecision = precision == -1;
4357 if (noPrecision)
4358 precision = 1;
4359
4360 for (qsizetype i = numStr.size(); i < precision; ++i) {
4361 numStr.prepend(zero);
4362 usedWidth++;
4363 }
4364
4365 // LeftAdjusted overrides ZeroPadded; and sprintf() only pads when
4366 // precision is not specified in the format string.
4367 if (noPrecision && flags & ZeroPadded && !(flags & LeftAdjusted)) {
4368 for (qsizetype i = usedWidth; i < width; ++i)
4369 numStr.prepend(zero);
4370 }
4371
4372 QString result(flags & CapitalEorX ? std::move(numStr).toUpper() : std::move(numStr));
4373 if (prefix.size())
4374 result.prepend(prefix);
4375 return result;
4376}
4377
4379 : grouping(data->groupSizes()), isC(data == c())
4380 // Note: actually test pointer equality to c(), not language == C, as
4381 // system locale might be configured as C with tweaks.
4382{
4383 if (isC)
4384 return;
4385 setZero(data->zero().viewData(single_character_data));
4386 group = data->groupDelim().viewData(single_character_data);
4387 // Note: minus, plus and exponent might not actually be single characters.
4388 minus = data->minus().viewData(single_character_data);
4389 plus = data->plus().viewData(single_character_data);
4390 if (mode != IntegerMode)
4391 decimal = data->decimalSeparator().viewData(single_character_data);
4392 if (mode == DoubleScientificMode) {
4393 exponent = data->exponential().viewData(single_character_data);
4394 // exponentCyrillic means "apply the Cyrrilic-specific exponent hack"
4395 exponentCyrillic = data->m_script_id == QLocale::CyrillicScript;
4396 }
4397#ifndef QT_NO_SYSTEMLOCALE
4398 if (data == &systemLocaleData) {
4399 const auto getString = [sys = systemLocale()](QSystemLocale::QueryType query) {
4400 return sys->query(query).toString();
4401 };
4402 if (mode != IntegerMode) {
4403 sysDecimal = getString(QSystemLocale::DecimalPoint);
4404 if (sysDecimal.size())
4405 decimal = QStringView{sysDecimal};
4406 }
4407 sysGroup = getString(QSystemLocale::GroupSeparator);
4408 if (sysGroup.size())
4409 group = QStringView{sysGroup};
4410 sysMinus = getString(QSystemLocale::NegativeSign);
4411 if (sysMinus.size())
4412 minus = QStringView{sysMinus};
4413 sysPlus = getString(QSystemLocale::PositiveSign);
4414 if (sysPlus.size())
4415 plus = QStringView{sysPlus};
4416 setZero(getString(QSystemLocale::ZeroDigit));
4417 }
4418#endif
4419}
4420
4421namespace {
4422// A bit like QStringIterator but rather specialized ... and some of the tokens
4423// it recognizes aren't single Unicode code-points (but it does map each to a
4424// single character).
4425class NumericTokenizer
4426{
4427 // TODO: use deterministic finite-state-automata.
4428 // TODO QTBUG-95460: CLDR has Inf/NaN representations per locale.
4429 static constexpr char lettersInfNaN[] = "afin"; // Letters of Inf, NaN
4430 static constexpr auto matchInfNaN = QtPrivate::makeCharacterSetMatch<lettersInfNaN>();
4431 const QStringView m_text;
4432 const QLocaleData::NumericData m_guide;
4433 qsizetype m_index;
4434 const QLocaleData::NumberMode m_mode;
4435 static_assert('+' + 1 == ',' && ',' + 1 == '-' && '-' + 1 == '.');
4436 char lastMark; // C locale accepts '+' through lastMark.
4437public:
4438 NumericTokenizer(QStringView text, QLocaleData::NumericData &&guide,
4439 QLocaleData::NumberMode mode, qsizetype from = 0)
4440 : m_text(text), m_guide(guide), m_index(from), m_mode(mode),
4441 lastMark(mode == QLocaleData::IntegerMode ? '-' : '.')
4442 {
4443 Q_ASSERT(m_guide.isValid(mode));
4444 }
4445 bool done() const { return !(m_index < m_text.size()); }
4446 qsizetype index() const { return m_index; }
4447 int digitValue(char32_t digit) const { return m_guide.digitValue(digit); }
4448 bool isInfNanChar(char ch) const { return matchInfNaN.matches(ch); }
4449 char nextToken();
4450 bool fractionGroupClash() const
4451 {
4452 // If the user's hand-configuration of the system makes group and
4453 // fractional part separators coincide, we have some kludges to apply,
4454 // though we can skip them in integer mode.
4455 return Q_UNLIKELY(m_mode != QLocaleData::IntegerMode && m_guide.fractionalIsGroup());
4456 }
4457 const QLocaleData::GroupSizes &groupSizes() { return m_guide.groupSizes(); }
4458};
4459
4460char NumericTokenizer::nextToken()
4461{
4462 // As long as caller stops iterating on a zero return, those don't need to
4463 // keep m_index correctly updated.
4464 Q_ASSERT(!done());
4465 do {
4466 // Mauls non-letters above 'Z' but we don't care:
4467 const auto asciiLower = [](unsigned char c) { return c >= 'A' ? c | 0x20 : c; };
4468 const QStringView tail = m_text.sliced(m_index);
4469 const QChar ch = tail.front();
4470 if (ch == u'\u2212') {
4471 // Special case: match the "proper" minus sign, for all locales.
4472 ++m_index;
4473 return '-';
4474 }
4475 if (m_guide.isC) {
4476 // "Conversion" to C locale is just a filter:
4477 if (Q_LIKELY(ch.unicode() < 256)) {
4478 unsigned char ascii = asciiLower(ch.toLatin1());
4479 if (Q_LIKELY(isAsciiDigit(ascii) || ('+' <= ascii && ascii <= lastMark)
4480 // No caller presently (6.5) passes DoubleStandardMode,
4481 // so !IntegerMode implies scientific, for now.
4482 || (m_mode != QLocaleData::IntegerMode && isInfNanChar(ascii))
4483 || (m_mode == QLocaleData::DoubleScientificMode && ascii == 'e'))) {
4484 ++m_index;
4485 return ascii;
4486 }
4487 }
4488 return 0;
4489 }
4490 if (ch.unicode() < 256) {
4491 // Accept the C locale's digits and signs in all locales:
4492 char ascii = asciiLower(ch.toLatin1());
4493 if (isAsciiDigit(ascii) || ascii == '-' || ascii == '+'
4494 // Also its Inf and NaN letters:
4495 || (m_mode != QLocaleData::IntegerMode && isInfNanChar(ascii))) {
4496 ++m_index;
4497 return ascii;
4498 }
4499 }
4500
4501 // Other locales may be trickier:
4502 if (tail.startsWith(m_guide.minus)) {
4503 m_index += m_guide.minus.size();
4504 return '-';
4505 }
4506 if (tail.startsWith(m_guide.plus)) {
4507 m_index += m_guide.plus.size();
4508 return '+';
4509 }
4510 if (!m_guide.group.isEmpty() && tail.startsWith(m_guide.group)) {
4511 m_index += m_guide.group.size();
4512 // When group and decimal coincide, and a fractional part is not
4513 // unexpected, treat the last as a fractional part separator (and leave
4514 // the caller to special-case the situations where that causes a
4515 // parse-fail that we can dodge by not reading it that way).
4516 if (fractionGroupClash() && tail.indexOf(m_guide.decimal, m_guide.group.size()) == -1)
4517 return '.';
4518 return ',';
4519 }
4520 if (m_mode != QLocaleData::IntegerMode && tail.startsWith(m_guide.decimal)) {
4521 m_index += m_guide.decimal.size();
4522 return '.';
4523 }
4525 && tail.startsWith(m_guide.exponent, Qt::CaseInsensitive)) {
4526 m_index += m_guide.exponent.size();
4527 return 'e';
4528 }
4529
4530 // Must match qlocale_tools.h's unicodeForDigit()
4531 if (m_guide.zeroLen == 1) {
4532 if (!ch.isSurrogate()) {
4533 if (const int gap = digitValue(char32_t(ch.unicode())); gap >= 0) {
4534 ++m_index;
4535 return '0' + gap;
4536 }
4537 } else if (ch.isHighSurrogate() && tail.size() > 1 && tail.at(1).isLowSurrogate()) {
4538 return 0;
4539 }
4540 // There remain one or two things a non-surrogate might be ...
4541 } else if (ch.isHighSurrogate()) {
4542 // None of the corner cases below matches a surrogate, so return
4543 // early if we don't have a digit.
4544 if (tail.size() > 1) {
4545 if (const QChar low = tail.at(1); low.isLowSurrogate()) {
4546 if (const int gap = digitValue(QChar::surrogateToUcs4(ch, low)); gap >= 0) {
4547 m_index += 2;
4548 return '0' + gap;
4549 }
4550 }
4551 }
4552 return 0;
4553 }
4554
4555 // All cases where tail starts with properly-matched surrogate pair
4556 // have been handled by this point.
4557 Q_ASSERT(!(ch.isHighSurrogate() && tail.size() > 1 && tail.at(1).isLowSurrogate()));
4558
4559 // Weird corner cases (code above assumes these match no surrogates):
4560 switch (ch.unicode()) {
4561 // Skip over inivisble marks commonly found in numeric forms:
4562 case 0x061C: // Arabic Letter Mark (before signs in standard Arabic)
4563 case 0x200E: // Left-to-Right marker
4564 case 0x200F: // Right-to-Left marker
4565 ++m_index;
4566 continue;
4567
4568 case u' ':
4569 // Some locales use a non-breaking space (U+00A0) or its thin
4570 // version (U+202f) for grouping. These look like spaces, so people
4571 // (and thus some of our tests) use a regular space instead and
4572 // complain if it doesn't work.
4573 // Should this be extended generally to any case where group is a space ?
4574 if (m_guide.group == u"\u00a0" || m_guide.group == u"\u202f") {
4575 ++m_index;
4576 return ',';
4577 }
4578 break;
4579
4580 // Case-insensitive match:
4581 case u'E':
4582 case u'e':
4583 case u'\u0415': // Cyrillic E
4584 case u'\u0435': // Cyrillic e
4585 // Cyrillic E is used by Ukrainian as exponent; but others writing
4586 // Cyrillic may well use that; and Ukrainians might well use E.
4587 // All other Cyrillic locales (officially) use plain ASCII E.
4588 if (m_guide.exponentCyrillic) { // Only true in scientific float mode.
4589 ++m_index;
4590 return 'e';
4591 }
4592 break;
4593 }
4594
4595 break;
4596 } while (!done());
4597 return 0;
4598}
4599} // namespace with no name
4600
4601/*!
4602 \internal
4603 \since 6.12
4604 \class QLocaleData::DigitSequence
4605 \brief Descriptor for a digit sequence within a text.
4606
4607 Packages the ASCII equivalent (optional sign and) digit sequence, along with
4608 a description of which parts come from where in the original text.
4609
4610 Supports construction or assignment by moving or copying. Modifying its
4611 members, other than by assigning a newly constructed value or a result of
4612 taking a subsequence, may lead to undefined behaviour.
4613
4614 \sa sliced(), first(), last()
4615*/
4616// Exists for the benefit of date-time parsing, but could be used for anything
4617// else that doesn't do fractional parts, exponents or digit-grouping.
4618
4619/*!
4620 \fn qsizetype QLocaleData::DigitSequence::size()
4621
4622 Returns the number of ASCII characters describing the digit sequence.
4623
4624 This is the number of digits plus, if present, one for the sign. It is the
4625 number of characters \l transcribeTo() will transcribe. For the number of
4626 digits found, use \c {digits.size()}. Note that this may be less than the
4627 length of the text parsed, for example when the digits are surrogate pairs
4628 or the sign includes special Unicode markers, such as those for text
4629 direction.
4630
4631 \sa isEmpty()
4632*/
4633
4634/*!
4635 \fn void QLocaleData::DigitSequence::transcribeTo(CharBuff *buff)
4636
4637 Transcribes the ASCII form of this digit sequence to \a buff.
4638
4639 \sa size()
4640*/
4641
4642/*!
4643 \since 6.12
4644 \enum QLocaleData::DigitSequence::Option
4645
4646 Options to modify how digit sequences are parsed.
4647
4648 \value Default The null option value.
4649 \value AllowSign A leading sign character may be present.
4650
4651 In the numeric fields of a date, only a year field ever has a sign, all
4652 others use ungrouped digits. Zero-padding on the left of day and month
4653 fields is common (and it may also appear in year fields). The hour field of
4654 a zone-offset may also have a sign. Otherwise all numeric time fields are
4655 similar to numeric month and day fields.
4656
4657 In numeric fields of a time, the least-significant given (be it hour, minute
4658 or second) may have a fractional part in some formats. The handling of this
4659 is left for the caller to take care of. Likewise, the caller is expected to
4660 deal with leading and trailing space appropriately.
4661*/
4662
4663/*!
4664 \fn bool QLocaleData::DigitSequence::isEmpty() const
4665
4666 Returns true precisely if this digit sequence represents nothing.
4667
4668 This arises when the constructor found no digits and (when allowed) not even
4669 a sign. It may also result from extracting an empty subsequence of a digit
4670 sequence that was originally parsed. It is equivalent to \l
4671 {QLocaleData::DigitSequence::}{size()} == 0. To test whether any digits were
4672 found, use \c {digits.isEmpty()}, which may be true even though \c
4673 {isEmpty()} is false. That arises when only a sign was found (making
4674 \c{size() == 1}).
4675
4676 \sa size()
4677*/
4678
4679/*!
4680 \fn bool QLocaleData::DigitSequence::hasSign() const
4681
4682 Returns true precisely if the digit sequence parsed includes a leading sign.
4683 It is equivalent to \c{sign != '\0'}.
4684*/
4685
4686/*!
4687 \fn QStringView QLocaleData::DigitSequence::used(QStringView text, qsizetype from) const
4688 \fn QStringView QLocaleData::DigitSequence::used(QStringView text) const
4689
4690 Returns the slice of \a text described by this digit sequence.
4691
4692 The given \a text should be the one passed to the constructor either of this
4693 digit sequence or of one from which it was obtained by some combination of
4694 \l first(), \l sliced() and \l last(). In the directly-constructed case, or
4695 in the case of (optionally repeatedly) applying only \l first(), \a from may
4696 be passed: it should be the like-named offset passed to the original
4697 constructor, or 0 if no offset was passed. In that case, the whole text
4698 parsed for this digit sequence (alibeit possibly a prefix of the text
4699 originally parsed) is returned. Otherwise, \a from should be omitted and
4700 this function returns the text described by just the digits of this
4701 sequence, omitting (even when relevant) the sign.
4702
4703 \sa {QLocaleData::DigitSequence::}{DigitSequence()}
4704*/
4705
4706/*!
4707 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::first(qsizetype count) const
4708
4709 Returns a DigitSequence describing a prefix of this.
4710
4711 The result describes the first \a count ASCII characters to which the
4712 sequence corresponds and their positions within the parsed text. The value
4713 of \a count must not be negative or exceed \c size().
4714*/
4715
4716/*!
4717 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::last(qsizetype count) const
4718
4719 Returns a DigitSequence describing a tail of this.
4720
4721 The result describes the last \a count ASCII characters to which the
4722 sequence corresponds. The value of \a count must not be negative or exceed
4723 \c size(). The result is equivalent to \c{sliced(size() - count)}.
4724*/
4725
4726/*!
4727 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::sliced(qsizetype from) const
4728
4729 Returns a DigitSequence describing a tail of this.
4730
4731 This skips over the text to which the first \a from ASCII characters of the
4732 sequence correspond, to describe the remainder and their positions within
4733 the parsed text. The value of \a from must not be negative or exceed \c
4734 size().
4735*/
4736
4737/*!
4738 \overload
4739 \fn QLocaleData::DigitSequence QLocaleData::DigitSequence::sliced(qsizetype from, qsizetype count) const
4740
4741 Returns a DigitSequence describing a subsequence of this.
4742
4743 This skips over the portion of the text to which first \a from ASCII
4744 characters correspond and describes the portion described by the next \a
4745 count ASCII characters. The value of \a from must not be negative or exceed
4746 \c size(). The value of \a count must not be negative or exceed \c{size() -
4747 from}. The result is equivalent to \c{sliced(from).first(count)}.
4748*/
4749
4750/*!
4751 Scan \a text for an initial sequence of digits.
4752
4753 The given \a numeric provides data relevant to number-parsing, including
4754 what constitute digits. Options in \a flags control whether a leading sign
4755 may be included. If \a from is passed, the scan starts at this index in \a
4756 text, otherwise from the start.
4757
4758 The resulting \l {QLocaleData::}{DigitSequence} contains the parsed digit
4759 sequence, \c digits, describes the positions of digits within \a text, by \c
4760 digitBounds, and (where allowed) reports any sign. Differences between
4761 entries in digitBounds are the UTF-16 lengths of the successive digits in
4762 the source text. These may be any mixture of locale-appropriate digits and
4763 the C locale's ASCII digits.
4764
4765 The end of the text parsed is always \c {digitBounds.back()}. When \c digits
4766 is empty, this is \c digitBounds[0]: this is either where the sign ended,
4767 when \c hasSign(), or the value of \c from passed to the
4768 constructor. Otherwise, each \c{digits[i]} represents
4769 \c{text.first(digitBounds[i+1]).sliced(digitBounds[i])} and the whole text
4770 parsed is \c{text.first(digitBounds.back()).sliced(from)}. Either way, if \c
4771 hasSign(), its \c sign represents
4772 \c{text.first(digitBounds.front()).sliced(from)}.
4773
4774 \sa {QLocaleData::DigitSequence::}{used()}
4775*/
4776QLocaleData::DigitSequence::DigitSequence(QStringView text, NumericData &&numeric,
4777 Options flags, qsizetype from)
4778 : digitBounds({ from })
4779{
4780 NumericTokenizer tokens(text, std::move(numeric), IntegerMode, from);
4781 if (tokens.done())
4782 return;
4783 char currentToken = tokens.nextToken();
4784 if (!currentToken)
4785 return;
4786
4787 // Handle any leading sign:
4788 if (currentToken == '+' || currentToken == '-') {
4789 if (!flags.testFlag(Option::AllowSign))
4790 return;
4791 digitBounds[0] = tokens.index();
4792 sign = currentToken;
4793 currentToken = '\0';
4794 }
4795
4796 // Iterate what remains:
4797 while (currentToken || !tokens.done()) {
4798 if (!currentToken)
4799 currentToken = tokens.nextToken();
4800 if (!currentToken)
4801 return;
4802
4803 if (currentToken < '0' || currentToken > '9')
4804 return; // What we got was not a digit in our locale.
4805
4806 // We have a digit.
4807 digits.push_back(currentToken);
4808 digitBounds.push_back(tokens.index());
4809 currentToken = '\0';
4810 }
4811 Q_ASSERT(digitBounds.size() == digits.size() + 1); // Class invariant.
4812}
4813
4814/*!
4815 \internal
4816 QLocaleData::DigitSequence QLocaleData::digitSequence(QStringView text, QLocaleData::DigitSequence::Options, qsizetype from)
4817 \brief Returns a DigitSequence describing some portion of \a text starting at \a from.
4818
4819 As for the \l{QLocaleData::}{DigitSequence} constructor, supplying the
4820 \l{QLocaleData::}{NumericData} for this QLocaleData instance and the
4821 IntegerMode as the relevant argument to it.
4822*/
4823
4824/*
4825 Converts a number in locale representation to the C locale equivalent.
4826
4827 Only has to guarantee that a string that is a correct representation of a
4828 number will be converted. Checks signs, separators and digits appear in all
4829 the places they should, and nowhere else.
4830
4831 Returns true precisely if the number appears to be well-formed, modulo
4832 things a parser for C Locale strings (without digit-grouping separators;
4833 they're stripped) will catch. When it returns true, it records (and
4834 '\0'-terminates) the C locale representation in *result.
4835
4836 Note: only QString integer-parsing methods have a base parameter (hence need
4837 to cope with letters as possible digits); but these are now all routed via
4838 byteArrayToU?LongLong(), so no longer come via here. The QLocale
4839 number-parsers only work in decimal, so don't have to cope with any digits
4840 other than 0 through 9.
4841*/
4842bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
4843 NumberMode mode, CharBuff *result) const
4844{
4845 s = s.trimmed();
4846 if (s.size() < 1)
4847 return false;
4848 NumericTokenizer tokens(s, NumericData(this, mode), mode);
4849
4850 // Reflects order constraints on possible parts of a number:
4851 enum { Whole, Grouped, Fraction, Exponent, Name } stage = Whole;
4852 // Grouped is just Whole with some digit-grouping separators in it.
4853 // Name is Inf or NaN; excludes all others (so none can be after it).
4854
4855 // Fractional part *or* whole-number part can be empty, but not both, unless
4856 // we have Name. Exponent must have some digits in it.
4857 bool wantDigits = true;
4858
4859 // Digit-grouping details (all modes):
4860 bool needHigherGroup = false; // Set when first group is too short to be the only one
4861 qsizetype digitsInGroup = 0;
4862 const QLocaleData::GroupSizes &grouping = tokens.groupSizes();
4863 const auto badLeastGroup = [&]() {
4864 // In principle we could object to a complete absence of grouping, when
4865 // digitsInGroup >= qMax(grouping.first, grouping.least), unless the
4866 // locale itself would omit them. However, when merely not rejecting
4867 // grouping separators, we have historically accepted ungrouped digits,
4868 // so objecting now would break existing code.
4869 if (stage == Grouped) {
4870 Q_ASSERT(!number_options.testFlag(QLocale::RejectGroupSeparator));
4871 // First group was invalid if it was short and we've not seen a separator since:
4872 if (needHigherGroup)
4873 return true;
4874 // Were there enough digits since the last group separator?
4875 if (digitsInGroup != grouping.least)
4876 return true;
4877 }
4878 return false;
4879 };
4880
4881 char last = '\0';
4882 while (!tokens.done()) {
4883 char out = tokens.nextToken();
4884 if (out == 0)
4885 return false;
4886
4887 // Note that out can only be '.', 'e' or an inf/NaN character if the
4888 // mode allows it (else nextToken() would return 0 instead), so we don't
4889 // need to check mode.
4890 if (out == '.') {
4891 if (stage > Grouped) // Too late to start a fractional part.
4892 return false;
4893
4894 if (tokens.fractionGroupClash() && badLeastGroup()
4895 && digitsInGroup == grouping.higher) {
4896 // Reinterpret '.' as ',' (as they're indistinguishable) to
4897 // interpret the recent digits as a group, with the least to
4898 // follow (hopefully of a suitable length):
4899 out = ',';
4900 stage = Grouped;
4901 needHigherGroup = false;
4902 digitsInGroup = 0;
4903 } else {
4904 // That's the end of the integral part - check size of last group:
4905 if (badLeastGroup())
4906 return false;
4907 stage = Fraction;
4908 }
4909 } else if (out == 'e') {
4910 if (wantDigits || stage == Name || stage > Fraction)
4911 return false;
4912
4913 if (stage < Fraction) {
4914 // The 'e' ends the whole-number part, so check its last group:
4915 if (badLeastGroup())
4916 return false;
4917 } else if (number_options.testFlag(QLocale::RejectTrailingZeroesAfterDot)) {
4918 // In a fractional part, a 0 just before the exponent is trailing:
4919 if (last == '0')
4920 return false;
4921 }
4922 stage = Exponent;
4923 wantDigits = true; // We need some in the exponent
4924 } else if (out == ',') {
4925 // (If tokens.fractionGroupClash(), a comma only comes out of
4926 // nextToken() if there's a later separator, since the last is
4927 // always treated as dot. So if we have a comma here, treating it as
4928 // a dot wouldn't save the parse: the later dot-or-comma would make
4929 // the text malformed.)
4930 if (number_options.testFlag(QLocale::RejectGroupSeparator))
4931 return false;
4932
4933 switch (stage) {
4934 case Whole:
4935 // Check size of most significant group
4936 if (digitsInGroup == 0
4937 || digitsInGroup > qMax(grouping.first, grouping.higher)) {
4938 return false;
4939 }
4940 Q_ASSERT(!needHigherGroup);
4941 // First group is only allowed fewer than grouping.first digits
4942 // if it's followed by a grouping.higher group, i.e. there's a
4943 // later group separator:
4944 if (grouping.first > digitsInGroup)
4945 needHigherGroup = true;
4946 stage = Grouped;
4947 break;
4948 case Grouped:
4949 // Check size of group between two separators:
4950 if (digitsInGroup != grouping.higher)
4951 return false;
4952 needHigherGroup = false; // We just found it, if needed.
4953 break;
4954 // Only allow group chars within the whole-number part:
4955 case Fraction:
4956 case Exponent:
4957 case Name:
4958 return false;
4959 }
4960 digitsInGroup = 0;
4961 } else if (isAsciiDigit(out)) {
4962 if (stage == Name)
4963 return false;
4964 if (out == '0' && number_options.testFlag(QLocale::RejectLeadingZeroInExponent)
4965 && stage > Fraction && !tokens.done() && !isAsciiDigit(last)) {
4966 // After the exponent there can only be '+', '-' or digits. If
4967 // we find a '0' directly after some non-digit, then that is a
4968 // leading zero, acceptable only if it is the whole exponent.
4969 return false;
4970 }
4971 wantDigits = false;
4972 ++digitsInGroup;
4973 } else if (stage == Whole && tokens.isInfNanChar(out)) {
4974 if (!wantDigits) // Mixed digits with Inf/NaN
4975 return false;
4976 wantDigits = false;
4977 stage = Name;
4978 }
4979 // else: nothing special to do.
4980
4981 last = out;
4982 if (out != ',') // Leave group separators out of the result.
4983 result->append(out);
4984 }
4985 if (wantDigits)
4986 return false;
4987
4988 if (!number_options.testFlag(QLocale::RejectGroupSeparator)) {
4989 // If this is the end of the whole-part, check least significant group:
4990 if (stage < Fraction && badLeastGroup())
4991 return false;
4992 }
4993
4994 if (number_options.testFlag(QLocale::RejectTrailingZeroesAfterDot) && stage == Fraction) {
4995 // In the fractional part, a final zero is trailing:
4996 if (last == '0')
4997 return false;
4998 }
4999
5000 return true;
5001}
5002
5004QLocaleData::validateChars(QStringView str, NumberMode numMode, int decDigits,
5005 QLocale::NumberOptions number_options) const
5006{
5007 ParsingResult result;
5008 result.buff.reserve(str.size());
5009
5010 enum { Whole, Fractional, Exponent } state = Whole;
5011 const bool scientific = numMode == DoubleScientificMode;
5012 NumericTokenizer tokens(str, NumericData(this, numMode), numMode);
5013 char last = '\0';
5014
5015 while (!tokens.done()) {
5016 char c = tokens.nextToken();
5017
5018 if (isAsciiDigit(c)) {
5019 switch (state) {
5020 case Whole:
5021 // Nothing special to do (unless we want to check grouping sizes).
5022 break;
5023 case Fractional:
5024 // If a double has too many digits in its fractional part it is Invalid.
5025 if (decDigits-- == 0)
5026 return {};
5027 break;
5028 case Exponent:
5029 if (!isAsciiDigit(last)) {
5030 // This is the first digit in the exponent (there may have beena '+'
5031 // or '-' in before). If it's a zero, the exponent is zero-padded.
5032 if (c == '0' && (number_options & QLocale::RejectLeadingZeroInExponent))
5033 return {};
5034 }
5035 break;
5036 }
5037
5038 } else {
5039 switch (c) {
5040 case '.':
5041 // If an integer has a decimal point, it is Invalid.
5042 // A double can only have one, at the end of its whole-number part.
5043 if (numMode == IntegerMode || state != Whole)
5044 return {};
5045 // Even when decDigits is 0, we do allow the decimal point to be
5046 // present - just as long as no digits follow it.
5047
5048 state = Fractional;
5049 break;
5050
5051 case '+':
5052 case '-':
5053 // A sign can only appear at the start or after the e of scientific:
5054 if (last != '\0' && !(scientific && last == 'e'))
5055 return {};
5056 break;
5057
5058 case ',':
5059 // Grouping is only allowed after a digit in the whole-number portion:
5060 if ((number_options & QLocale::RejectGroupSeparator) || state != Whole
5061 || !isAsciiDigit(last)) {
5062 return {};
5063 }
5064 // We could check grouping sizes are correct, but fixup()s are
5065 // probably better off correcting any misplacement instead.
5066 break;
5067
5068 case 'e':
5069 // Only one e is allowed and only in scientific:
5070 if (!scientific || state == Exponent)
5071 return {};
5072 state = Exponent;
5073 break;
5074
5075 default:
5076 // Nothing else can validly appear in a number.
5077 // NumericTokenizer allows letters of "inf" and "nan", but
5078 // validators don't accept those values.
5079 // For anything else, tokens.nextToken() must have returned 0.
5080 Q_ASSERT(!c || c == 'a' || c == 'f' || c == 'i' || c == 'n');
5081 return {};
5082 }
5083 }
5084
5085 last = c;
5086 if (c != ',') // Skip grouping
5087 result.buff.append(c);
5088 }
5089
5091
5092 // Intermediate if it ends with any character that requires a digit after
5093 // it to be valid e.g. group separator, sign, or exponent
5094 if (last == ',' || last == '-' || last == '+' || last == 'e')
5096
5097 return result;
5098}
5099
5100double QLocaleData::stringToDouble(QStringView str, bool *ok,
5101 QLocale::NumberOptions number_options) const
5102{
5103 CharBuff buff;
5104 if (!numberToCLocale(str, number_options, DoubleScientificMode, &buff)) {
5105 if (ok != nullptr)
5106 *ok = false;
5107 return 0.0;
5108 }
5109 auto r = qt_asciiToDouble(buff.constData(), buff.size());
5110 if (ok != nullptr)
5111 *ok = r.ok();
5112 return r.result;
5113}
5114
5116QLocaleData::stringToLongLong(QStringView str, int base,
5117 QLocale::NumberOptions number_options) const
5118{
5119 CharBuff buff;
5120 if (!numberToCLocale(str, number_options, IntegerMode, &buff))
5121 return {};
5122
5123 return bytearrayToLongLong(QByteArrayView(buff), base);
5124}
5125
5127QLocaleData::stringToUnsLongLong(QStringView str, int base,
5128 QLocale::NumberOptions number_options) const
5129{
5130 CharBuff buff;
5131 if (!numberToCLocale(str, number_options, IntegerMode, &buff))
5132 return {};
5133
5134 return bytearrayToUnsLongLong(QByteArrayView(buff), base);
5135}
5136
5137static bool checkParsed(QByteArrayView num, qsizetype used)
5138{
5139 if (used <= 0)
5140 return false;
5141
5142 const qsizetype len = num.size();
5143 if (used < len && num[used] != '\0') {
5144 while (used < len && ascii_isspace(num[used]))
5145 ++used;
5146 }
5147
5148 if (used < len && num[used] != '\0')
5149 // we stopped at a non-digit character after converting some digits
5150 return false;
5151
5152 return true;
5153}
5154
5155QSimpleParsedNumber<qint64> QLocaleData::bytearrayToLongLong(QByteArrayView num, int base)
5156{
5157 auto r = qstrntoll(num.data(), num.size(), base);
5158 if (!checkParsed(num, r.used))
5159 return {};
5160 return r;
5161}
5162
5163QSimpleParsedNumber<quint64> QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base)
5164{
5165 auto r = qstrntoull(num.data(), num.size(), base);
5166 if (!checkParsed(num, r.used))
5167 return {};
5168 return r;
5169}
5170
5171/*!
5172 \since 4.8
5173
5174 \enum QLocale::CurrencySymbolFormat
5175
5176 Specifies the format of the currency symbol.
5177
5178 \value CurrencyIsoCode a ISO-4217 code of the currency.
5179 \value CurrencySymbol a currency symbol.
5180 \value CurrencyDisplayName a user readable name of the currency.
5181*/
5182
5183/*!
5184 \since 4.8
5185 Returns a currency symbol according to the \a format.
5186*/
5187QString QLocale::currencySymbol(CurrencySymbolFormat format) const
5188{
5189#ifndef QT_NO_SYSTEMLOCALE
5190 if (d->m_data == &systemLocaleData) {
5191 auto res = systemLocale()->query(QSystemLocale::CurrencySymbol, format).toString();
5192 if (!res.isEmpty())
5193 return res;
5194 }
5195#endif
5196 switch (format) {
5197 case CurrencySymbol:
5198 return d->m_data->currencySymbol().getData(currency_symbol_data);
5199 case CurrencyDisplayName:
5200 return d->m_data->currencyDisplayName().getData(currency_display_name_data);
5201 case CurrencyIsoCode: {
5202 const char *code = d->m_data->m_currency_iso_code;
5203 if (auto len = qstrnlen(code, 3))
5204 return QString::fromLatin1(code, qsizetype(len));
5205 break;
5206 }
5207 }
5208 return QString();
5209}
5210
5211/*!
5212 \since 4.8
5213
5214 Returns a localized string representation of \a value as a currency.
5215 If the \a symbol is provided it is used instead of the default currency symbol.
5216
5217 \sa currencySymbol()
5218*/
5219QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
5220{
5221#ifndef QT_NO_SYSTEMLOCALE
5222 if (d->m_data == &systemLocaleData) {
5223 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5224 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5225 QVariant::fromValue(arg)).toString();
5226 if (!res.isEmpty())
5227 return res;
5228 }
5229#endif
5230 QLocaleData::DataRange range = d->m_data->currencyFormatNegative();
5231 if (!range.size || value >= 0)
5232 range = d->m_data->currencyFormat();
5233 else
5234 value = -value;
5235 QString str = toString(value);
5236 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5237 if (sym.isEmpty())
5238 sym = currencySymbol(CurrencyIsoCode);
5239 return range.viewData(currency_format_data).arg(str, sym);
5240}
5241
5242/*!
5243 \since 4.8
5244 \overload
5245*/
5246QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
5247{
5248#ifndef QT_NO_SYSTEMLOCALE
5249 if (d->m_data == &systemLocaleData) {
5250 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5251 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5252 QVariant::fromValue(arg)).toString();
5253 if (!res.isEmpty())
5254 return res;
5255 }
5256#endif
5257 QString str = toString(value);
5258 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5259 if (sym.isEmpty())
5260 sym = currencySymbol(CurrencyIsoCode);
5261 return d->m_data->currencyFormat().getData(currency_format_data).arg(str, sym);
5262}
5263
5264/*!
5265 \since 5.7
5266 \overload toCurrencyString()
5267
5268 Returns a localized string representation of \a value as a currency.
5269 If the \a symbol is provided it is used instead of the default currency symbol.
5270 If the \a precision is provided it is used to set the precision of the currency value.
5271
5272 \sa currencySymbol()
5273 */
5274QString QLocale::toCurrencyString(double value, const QString &symbol, int precision) const
5275{
5276#ifndef QT_NO_SYSTEMLOCALE
5277 if (d->m_data == &systemLocaleData) {
5278 QSystemLocale::CurrencyToStringArgument arg(value, symbol);
5279 auto res = systemLocale()->query(QSystemLocale::CurrencyToString,
5280 QVariant::fromValue(arg)).toString();
5281 if (!res.isEmpty())
5282 return res;
5283 }
5284#endif
5285 QLocaleData::DataRange range = d->m_data->currencyFormatNegative();
5286 if (!range.size || value >= 0)
5287 range = d->m_data->currencyFormat();
5288 else
5289 value = -value;
5290 QString str = toString(value, 'f', precision == -1 ? d->m_data->m_currency_digits : precision);
5291 QString sym = symbol.isNull() ? currencySymbol() : symbol;
5292 if (sym.isEmpty())
5293 sym = currencySymbol(CurrencyIsoCode);
5294 return range.viewData(currency_format_data).arg(str, sym);
5295}
5296
5297/*!
5298 \fn QString QLocale::toCurrencyString(float i, const QString &symbol, int precision) const
5299 \overload toCurrencyString()
5300*/
5301
5302/*!
5303 \since 5.10
5304
5305 \enum QLocale::DataSizeFormat
5306
5307 Specifies the format for representation of data quantities.
5308
5309 \omitvalue DataSizeBase1000
5310 \omitvalue DataSizeSIQuantifiers
5311 \value DataSizeIecFormat format using base 1024 and IEC prefixes: KiB, MiB, GiB, ...
5312 \value DataSizeTraditionalFormat format using base 1024 and SI prefixes: kB, MB, GB, ...
5313 \value DataSizeSIFormat format using base 1000 and SI prefixes: kB, MB, GB, ...
5314
5315 \sa formattedDataSize()
5316*/
5317
5318/*!
5319 \since 5.10
5320
5321 Converts a size in bytes to a human-readable localized string, comprising a
5322 number and a quantified unit. The quantifier is chosen such that the number
5323 is at least one, and as small as possible. For example if \a bytes is
5324 16384, \a precision is 2, and \a format is \l DataSizeIecFormat (the
5325 default), this function returns "16.00 KiB"; for 1330409069609 bytes it
5326 returns "1.21 GiB"; and so on. If \a format is \l DataSizeIecFormat or
5327 \l DataSizeTraditionalFormat, the given number of bytes is divided by a
5328 power of 1024, with result less than 1024; for \l DataSizeSIFormat, it is
5329 divided by a power of 1000, with result less than 1000.
5330 \c DataSizeIecFormat uses the new IEC standard quantifiers Ki, Mi and so on,
5331 whereas \c DataSizeSIFormat uses the older SI quantifiers k, M, etc., and
5332 \c DataSizeTraditionalFormat abuses them.
5333*/
5334QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format) const
5335{
5336 int power, base = 1000;
5337 if (!bytes) {
5338 power = 0;
5339 } else if (format & DataSizeBase1000) {
5340 constexpr auto log10_1000 = 3; // std::log10(1000U)
5341 power = int(std::log10(QtPrivate::qUnsignedAbs(bytes))) / log10_1000;
5342 } else {
5343 constexpr auto log2_1024 = 10; // QtPrivate::log2i(1024U);
5344 power = QtPrivate::log2i(QtPrivate::qUnsignedAbs(bytes)) / log2_1024;
5345 base = 1024;
5346 }
5347 // Only go to doubles if we'll be using a quantifier:
5348 const QString number = power
5349 ? toString(bytes / std::pow(double(base), power), 'f', qMin(precision, 3 * power))
5350 : toString(bytes);
5351
5352 // We don't support sizes in units larger than exbibytes because
5353 // the number of bytes would not fit into qint64.
5354 Q_ASSERT(power <= 6 && power >= 0);
5355 QStringView unit;
5356 if (power > 0) {
5357 QLocaleData::DataRange range = (format & DataSizeSIQuantifiers)
5358 ? d->m_data->byteAmountSI() : d->m_data->byteAmountIEC();
5359 unit = range.viewListEntry(byte_unit_data, power - 1);
5360 } else {
5361 unit = d->m_data->byteCount().viewData(byte_unit_data);
5362 }
5363
5364 return number + u' ' + unit;
5365}
5366
5367/*!
5368 \since 4.8
5369 \brief List of locale names for use in selecting translations
5370
5371 Each entry in the returned list is the name of a locale suitable to the
5372 user's preferences for what to translate the UI into. Where a name in the
5373 list is composed of several tags, they are joined as indicated by \a
5374 separator. Prior to Qt 6.7 a dash was used as separator.
5375
5376 For example, using the default separator QLocale::TagSeparator::Dash, if the
5377 user has configured their system to use English as used in the USA, the list
5378 would be "en-Latn-US", "en-US", "en-Latn", "en". The order of entries is the
5379 order in which to check for translations; earlier items in the list are to
5380 be preferred over later ones. If your translation files (or other resources
5381 specific to locale) use underscores, rather than dashes, to separate locale
5382 tags, pass QLocale::TagSeparator::Underscore as \a separator.
5383
5384 Returns a list of locale names. This may include multiple languages,
5385 especially for the system locale when multiple UI translation languages are
5386 configured. The order of entries is significant. For example, for the system
5387 locale, it reflects user preferences.
5388
5389 Prior to Qt 6.9, the list only contained explicitly configured locales and
5390 their equivalents. This led some callers to add truncations (such as from
5391 'en-Latn-DE' to 'en') as fallbacks. This could sometimes result in
5392 inappropriate choices, especially if these were tried before later entries
5393 that would be more appropriate fallbacks.
5394
5395 Starting from Qt 6.9, reasonable truncations are included in the returned
5396 list \e after all entries equivalent to the explicitly specified
5397 locales. This change allows for more accurate fallback options without
5398 callers needing to do any truncation.
5399
5400 Users can explicitly include preferred fallback locales (such as en-US) in
5401 their system configuration to control the order of preference. You are
5402 advised to rely on the order of entries in uiLanguages() rather than using
5403 custom fallback methods.
5404
5405 Most likely you do not need to use this function directly, but just pass the
5406 QLocale object to the QTranslator::load() function.
5407
5408 \sa QTranslator, bcp47Name()
5409*/
5410QStringList QLocale::uiLanguages(TagSeparator separator) const
5411{
5412 const char sep = char(separator);
5413 QStringList uiLanguages;
5414 if (uchar(sep) > 0x7f) {
5415 badSeparatorWarning("uiLanguages", sep);
5416 return uiLanguages;
5417 }
5418 QList<QLocaleId> localeIds;
5419#ifdef QT_NO_SYSTEMLOCALE
5420 constexpr bool isSystem = false;
5421#else
5422 const bool isSystem = d->m_data == &systemLocaleData;
5423 if (isSystem) {
5424 uiLanguages = systemLocale()->query(QSystemLocale::UILanguages).toStringList();
5425 if (separator != TagSeparator::Dash) {
5426 // Map from default separator, Dash, used by backends:
5427 const QChar join = QLatin1Char(sep);
5428 uiLanguages.replaceInStrings(u"-", QStringView(&join, 1));
5429 }
5430 // ... but we need to include likely-adjusted forms of each of those, too.
5431 // For now, collect up locale Ids representing the entries, for later processing:
5432 for (const auto &entry : std::as_const(uiLanguages))
5433 localeIds.append(QLocaleId::fromName(entry));
5434 if (localeIds.isEmpty())
5435 localeIds.append(systemLocale()->fallbackLocale().d->m_data->id());
5436 /* Note: Darwin allows entirely independent choice of locale and of
5437 preferred languages, so it's possible the locale implied by
5438 LanguageId, ScriptId and TerritoryId is absent from the UILanguages
5439 list and that this faithfully reflects the user's wishes. None the
5440 less, we include it (if it isn't C) in the list below, after the last
5441 with the same language and script or (if none has) at the end, in
5442 case there is no better option available. (See, QTBUG-104930.)
5443 */
5444 const QString name = QString::fromLatin1(d->m_data->id().name(sep)); // Raw name
5445 if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) {
5446 // That uses contains(name) as a cheap pre-test, but there may be an
5447 // entry that matches this on purging likely subtags.
5448 const QLocaleId id = d->m_data->id();
5449 const QLocaleId max = id.withLikelySubtagsAdded();
5450 const QLocaleId mine = max.withLikelySubtagsRemoved();
5451 // Default to putting at the end:
5452 qsizetype lastAlike = uiLanguages.size() - 1;
5453 bool seen = false;
5454 for (qsizetype i = 0; !seen && i < uiLanguages.size(); ++i) {
5455 const auto its = QLocaleId::fromName(uiLanguages.at(i)).withLikelySubtagsAdded();
5456 seen = its.withLikelySubtagsRemoved() == mine;
5457 if (!seen && its.language_id == max.language_id && its.script_id == max.script_id)
5458 lastAlike = i;
5459 }
5460 if (!seen) {
5461 localeIds.insert(lastAlike + 1, id);
5462 uiLanguages.insert(lastAlike + 1, QString::fromLatin1(id.name(sep)));
5463 }
5464 }
5465 } else
5466#endif
5467 {
5468 localeIds.append(d->m_data->id());
5469 }
5470
5471 for (qsizetype i = localeIds.size(); i-- > 0; ) {
5472 const QLocaleId id = localeIds.at(i);
5473 Q_ASSERT(id.language_id);
5474 if (id.language_id == C) {
5475 if (!uiLanguages.contains(u"C"_s))
5476 uiLanguages.append(u"C"_s);
5477 // Attempt no likely sub-tag amendments to C.
5478 continue;
5479 }
5480
5481 qsizetype j;
5482 const QByteArray prior = id.name(sep);
5483 bool faithful = true; // prior matches uiLanguages.at(j - 1)
5484 if (isSystem && i < uiLanguages.size()) {
5485 // Adding likely-adjusted forms to system locale's list.
5486 faithful = uiLanguages.at(i) == QLatin1StringView(prior);
5487 Q_ASSERT(faithful
5488 // A legacy code may get mapped to an ID with a different name:
5489 || QLocaleId::fromName(uiLanguages.at(i)).name(sep) == prior);
5490 // Insert just after the entry we're supplementing:
5491 j = i + 1;
5492 } else {
5493 // Plain locale or empty system uiLanguages; just append.
5494 if (!uiLanguages.contains(QLatin1StringView(prior)))
5495 uiLanguages.append(QString::fromLatin1(prior));
5496 j = uiLanguages.size();
5497 }
5498
5499 const QLocaleId max = id.withLikelySubtagsAdded();
5500 Q_ASSERT(max.language_id);
5501 Q_ASSERT(max.language_id == id.language_id);
5502 // We can't say the same for script or territory, though.
5503
5504 // We have various candidates to consider.
5505 const auto addIfEquivalent = [&j, &uiLanguages, max, sep, &prior, faithful](QLocaleId cid) {
5506 if (cid.withLikelySubtagsAdded() == max) {
5507 if (const QByteArray name = cid.name(sep); name != prior)
5508 uiLanguages.insert(j, QString::fromLatin1(name));
5509 else if (faithful) // Later candidates are more specific, so go before.
5510 --j;
5511 }
5512 };
5513 // language
5514 addIfEquivalent({ max.language_id, 0, 0 });
5515 // language-script
5516 if (max.script_id)
5517 addIfEquivalent({ max.language_id, max.script_id, 0 });
5518 if (id.script_id && id.script_id != max.script_id)
5519 addIfEquivalent({ id.language_id, id.script_id, 0 });
5520 // language-territory
5521 if (max.territory_id)
5522 addIfEquivalent({ max.language_id, 0, max.territory_id });
5523 if (id.territory_id && id.territory_id != max.territory_id)
5524 addIfEquivalent({ id.language_id, 0, id.territory_id });
5525 // full
5526 if (max.territory_id && max.script_id)
5527 addIfEquivalent(max);
5528 if (max.territory_id && id.script_id && id.script_id != max.script_id)
5529 addIfEquivalent({ id.language_id, id.script_id, max.territory_id });
5530 if (max.script_id && id.territory_id && id.territory_id != max.territory_id)
5531 addIfEquivalent({ id.language_id, max.script_id, id.territory_id });
5532 if (id.territory_id && id.territory_id != max.territory_id
5533 && id.script_id && id.script_id != max.script_id) {
5534 addIfEquivalent(id);
5535 }
5536 }
5537
5538 // Second pass: deduplicate.
5539 // Can't use QStringList::removeDuplicates() here, because we still need
5540 // the QDuplicateTracker, later.
5541 QDuplicateTracker<QString> known(uiLanguages.size());
5542 uiLanguages.removeIf([&](const QString &s) { return known.hasSeen(s); });
5543
5544 // Third pass: add truncations, when not already present.
5545 // Cubic in list length, but hopefully that's at most a dozen or so.
5546 const QLatin1Char cut(sep);
5547 const auto hasPrefix = [cut](auto name, QStringView stem) {
5548 // A prefix only counts if it's either full or followed by a separator.
5549 return name.startsWith(stem)
5550 && (name.size() == stem.size() || name.at(stem.size()) == cut);
5551 };
5552 // As we now forward-traverse the list, we need to keep track of the
5553 // positions just after (a) the block of things added above that are
5554 // equivalent to the current entry and (b) the block of truncations (if any)
5555 // added just after this block. All truncations of entries in (a) belong at
5556 // the end of (b); once i advances to the end of (a) it must jump to just
5557 // after (b). The more specific entries in (a) may well have truncations
5558 // that can also arise from less specific ones later in (a); for the
5559 // purposes of determining whether such truncations go at the end of (b) or
5560 // the end of the list, we thus need to ignore these matches.
5561 qsizetype afterEquivs = 0;
5562 qsizetype afterTruncs = 0;
5563 // From here onwards, we only have the truncations we're adding, whose
5564 // truncations should all have been included already.
5565 // If advancing i brings us to the end of block (a), jump to the end of (b):
5566 for (qsizetype i = 0; i < uiLanguages.size(); ++i >= afterEquivs && (i = afterTruncs)) {
5567 const QString entry = uiLanguages.at(i);
5568 const QLocaleId max = QLocaleId::fromName(entry).withLikelySubtagsAdded();
5569 // Keep track of our two blocks:
5570 if (i >= afterEquivs) {
5571 Q_ASSERT(i >= afterTruncs); // i.e. we just skipped past the end of a block
5572 afterEquivs = i + 1;
5573 // Advance past equivalents of entry:
5574 while (afterEquivs < uiLanguages.size()
5575 && QLocaleId::fromName(uiLanguages.at(afterEquivs))
5576 .withLikelySubtagsAdded() == max) {
5577 ++afterEquivs;
5578 }
5579 // We'll add any truncations starting there:
5580 afterTruncs = afterEquivs;
5581 }
5582 if (hasPrefix(entry, u"C") || hasPrefix(entry, u"und"))
5583 continue;
5584 qsizetype stopAt = uiLanguages.size();
5585 qsizetype at = entry.size(); // if 0, calls lastIndexOf(cut, -1), which is in-contract
5586 while ((at = entry.lastIndexOf(cut, at - 1)) > 0) {
5587 QString prefix = entry.first(at);
5588 // Don't test with hasSeen() as we might defer adding to later, when
5589 // we'll need known to see the later entry's offering of this prefix
5590 // as a new entry.
5591 bool found = known.contains(prefix);
5592 /* By default we append but if no later entry has this as a prefix
5593 and the locale it implies would use the same script as entry, put
5594 it after the block of consecutive equivalents of which entry is a
5595 part instead. Thus [en-NL, nl-NL, en-GB] will append en but
5596 [en-NL, en-GB, nl-NL] will put it before nl-NL, for example. We
5597 require a script match so we don't pick translations that the
5598 user cannot read, despite knowing the language. (Ideally that
5599 would be a constraint the caller can opt into / out of. See
5600 QTBUG-112765.)
5601 */
5602 bool justAfter
5603 = (QLocaleId::fromName(prefix).withLikelySubtagsAdded().script_id == max.script_id);
5604 for (qsizetype j = afterTruncs; !found && j < stopAt; ++j) {
5605 QString later = uiLanguages.at(j);
5606 if (!later.startsWith(prefix)) {
5607 const QByteArray laterFull =
5608 QLocaleId::fromName(later.replace(cut, u'-')
5609 ).withLikelySubtagsAdded().name(sep);
5610 // When prefix matches a later entry's max, it belongs later.
5611 if (hasPrefix(QLatin1StringView(laterFull), prefix))
5612 justAfter = false;
5613 continue;
5614 }
5615 // The duplicate tracker would already have spotted if equal:
5616 Q_ASSERT(later.size() > prefix.size());
5617 if (later.at(prefix.size()) == cut) {
5618 justAfter = false;
5619 // Prefix match. Shall produce the same prefix, but possibly
5620 // after prefixes of other entries in the list. If later has
5621 // a longer prefix not yet in the list, we want that before
5622 // this shorter prefix, so leave this for later, otherwise,
5623 // we include this prefix right away.
5624 QStringView head{later};
5625 for (qsizetype as = head.lastIndexOf(cut);
5626 !found && as > prefix.size(); as = head.lastIndexOf(cut)) {
5627 head = head.first(as);
5628 bool seen = false;
5629 for (qsizetype k = j + 1; !seen && k < uiLanguages.size(); ++k)
5630 seen = uiLanguages.at(k) == head;
5631 if (!seen)
5632 found = true;
5633 }
5634 }
5635 }
5636 if (found) // Don't duplicate.
5637 continue; // Some shorter truncations may still be missing.
5638 // Now we're committed to adding it, get it into known:
5639 (void) known.hasSeen(prefix);
5640 if (justAfter) {
5641 uiLanguages.insert(afterTruncs++, std::move(prefix));
5642 ++stopAt; // All later entries have moved one step later.
5643 } else {
5644 uiLanguages.append(std::move(prefix));
5645 }
5646 }
5647 }
5648
5649 return uiLanguages;
5650}
5651
5652/*!
5653 \since 5.13
5654
5655 Returns the locale to use for collation.
5656
5657 The result is usually this locale; however, the system locale (which is
5658 commonly the default locale) will return the system collation locale.
5659 The result is suitable for passing to QCollator's constructor.
5660
5661 \sa QCollator
5662*/
5663QLocale QLocale::collation() const
5664{
5665#ifndef QT_NO_SYSTEMLOCALE
5666 if (d->m_data == &systemLocaleData) {
5667 const auto res = systemLocale()->query(QSystemLocale::Collation).toString();
5668 if (!res.isEmpty())
5669 return QLocale(res);
5670 }
5671#endif
5672 return *this;
5673}
5674
5675/*!
5676 \since 4.8
5677
5678 Returns a native name of the language for the locale. For example
5679 "Schweizer Hochdeutsch" for the Swiss-German locale.
5680
5681 \sa nativeTerritoryName(), languageToString()
5682*/
5683QString QLocale::nativeLanguageName() const
5684{
5685#ifndef QT_NO_SYSTEMLOCALE
5686 if (d->m_data == &systemLocaleData) {
5687 auto res = systemLocale()->query(QSystemLocale::NativeLanguageName).toString();
5688 if (!res.isEmpty())
5689 return res;
5690 }
5691#endif
5692 return d->m_data->endonymLanguage().getData(endonyms_data);
5693}
5694
5695/*!
5696 \since 6.2
5697
5698 Returns a native name of the territory for the locale. For example
5699 "España" for Spanish/Spain locale.
5700
5701 \sa nativeLanguageName(), territoryToString()
5702*/
5703QString QLocale::nativeTerritoryName() const
5704{
5705#ifndef QT_NO_SYSTEMLOCALE
5706 if (d->m_data == &systemLocaleData) {
5707 auto res = systemLocale()->query(QSystemLocale::NativeTerritoryName).toString();
5708 if (!res.isEmpty())
5709 return res;
5710 }
5711#endif
5712 return d->m_data->endonymTerritory().getData(endonyms_data);
5713}
5714
5715#if QT_DEPRECATED_SINCE(6, 6)
5716/*!
5717 \deprecated [6.6] Use \l nativeTerritoryName() instead.
5718 \since 4.8
5719
5720 Returns a native name of the territory for the locale. For example
5721 "España" for Spanish/Spain locale.
5722
5723 \sa nativeLanguageName(), territoryToString()
5724*/
5725QString QLocale::nativeCountryName() const
5726{
5727 return nativeTerritoryName();
5728}
5729#endif
5730
5731#ifndef QT_NO_DEBUG_STREAM
5732QDebug operator<<(QDebug dbg, const QLocale &l)
5733{
5734 QDebugStateSaver saver(dbg);
5735 const bool isSys = l == QLocale::system();
5736 dbg.nospace().noquote()
5737 << (isSys ? "QLocale::system()/* " : "QLocale(")
5738 << QLocale::languageToString(l.language()) << ", "
5739 << QLocale::scriptToString(l.script()) << ", "
5740 << QLocale::territoryToString(l.territory()) << (isSys ? " */" : ")");
5741 return dbg;
5742}
5743#endif
5744QT_END_NAMESPACE
5745
5746#ifndef QT_NO_QOBJECT
5747#include "moc_qlocale.cpp"
5748#endif
const QLocaleData *const m_data
Definition qlocale_p.h:713
QLocale::MeasurementSystem measurementSystem() const
Definition qlocale.cpp:3531
QByteArray bcp47Name(char separator='-') const
Definition qlocale.cpp:498
char32_t next(char32_t invalidAs=QChar::ReplacementCharacter)
bool hasNext() const
Combined button and popup list for selecting options.
Definition qcompare.h:111
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames, { { Qt::DisplayRole, "display" }, { Qt::DecorationRole, "decoration" }, { Qt::EditRole, "edit" }, { Qt::ToolTipRole, "toolTip" }, { Qt::StatusTipRole, "statusTip" }, { Qt::WhatsThisRole, "whatsThis" }, }) const QHash< int
static unsigned calculateFlags(int fieldWidth, char32_t fillChar, const QLocale &locale)
Definition qlocale.cpp:2213
static QString calculateFiller(qsizetype padding, char32_t fillChar, qsizetype fieldWidth, const QLocaleData *localeData)
Definition qlocale.cpp:2227
QDebug operator<<(QDebug dbg, const QLocale &l)
Definition qlocale.cpp:5732
static QLocalePrivate * findLocalePrivate(QLocale::Language language, QLocale::Script script, QLocale::Territory territory)
Definition qlocale.cpp:978
static std::optional< QString > systemLocaleString(const QLocaleData *that, QSystemLocale::QueryType type)
Definition qlocale.cpp:1025
static const QSystemLocale * systemLocale()
Definition qlocale.cpp:833
static bool checkParsed(QByteArrayView num, qsizetype used)
Definition qlocale.cpp:5137
static QString rawWeekDayName(const QLocaleData *data, const int day, QLocale::FormatType type)
Definition qlocale.cpp:3333
QDataStream & operator>>(QDataStream &ds, QLocale &l)
Definition qlocale.cpp:956
#define CheckCandidate(id)
static Q_DECL_COLD_FUNCTION void badSeparatorWarning(const char *method, char sep)
Definition qlocale.cpp:1514
static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day, QLocale::FormatType type)
Definition qlocale.cpp:3357
static constexpr QLocale::NumberOptions defaultNumberOptions(QLocale::Language forLanguage)
Definition qlocale.cpp:772
static QStringView findTag(QStringView name) noexcept
Definition qlocale.cpp:646
static bool validTag(QStringView tag)
Definition qlocale.cpp:655
static qsizetype scriptIndex(QStringView code, Qt::CaseSensitivity cs) noexcept
Definition qlocale.cpp:187
static const QCalendarLocale & getMonthDataFor(const QLocalePrivate *loc, const QCalendarLocale *table)
Definition qlocale.cpp:3280
static T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
Definition qlocale.cpp:1562
static bool timeFormatContainsAP(QStringView format)
Definition qlocale.cpp:2430
size_t qHash(const QLocale &key, size_t seed) noexcept
Definition qlocale.cpp:1295
bool comparesEqual(const QLocale &loc, QLocale::Language lang)
Definition qlocale.cpp:999
static qsizetype findLocaleIndexById(QLocaleId localeId) noexcept
Definition qlocale.cpp:508
static constexpr qsizetype locale_data_size
Definition qlocale.cpp:527
static void updateSystemPrivate()
Definition qlocale.cpp:845
static QString rawMonthName(const QCalendarLocale &localeData, const char16_t *monthsData, int month, QLocale::FormatType type)
Definition qlocale.cpp:3307
static qsizetype stringWidth(QStringView text)
Definition qlocale.cpp:2202
static QLocalePrivate * c_private() noexcept
Definition qlocale.cpp:766
static const QLocaleData * defaultData()
Definition qlocale.cpp:920
static QString rawStandaloneMonthName(const QCalendarLocale &localeData, const char16_t *monthsData, int month, QLocale::FormatType type)
Definition qlocale.cpp:3319
static QString localeString(const QLocaleData *that, QSystemLocale::QueryType type, QLocaleData::DataRange range)
Definition qlocale.cpp:1043
static const QLocaleData * systemData(qsizetype *sysIndex=nullptr)
Definition qlocale.cpp:880
static QString offsetFromAbbreviation(QString &&text)
Definition qlocale.cpp:3742
static qsizetype defaultIndex()
Definition qlocale.cpp:927
static constexpr char16_t single_character_data[]
static constexpr char16_t days_data[]
static constexpr QLocaleData locale_data[]
static constexpr QLocaleId likely_subtags[]
static constexpr unsigned char territory_code_list[]
static constexpr unsigned char script_code_list[]
bool qt_splitLocaleName(QStringView name, QStringView *lang=nullptr, QStringView *script=nullptr, QStringView *cntry=nullptr) noexcept
Definition qlocale.cpp:666
QString qt_readEscapedFormatString(QStringView format, qsizetype *idx)
Definition qlocale.cpp:729
#define QStringLiteral(str)
Definition qstring.h:1865
char32_t ucsFirst(const char16_t *table) const
Definition qlocale_p.h:586
Descriptor for a digit sequence within a text.
Definition qlocale_p.h:453
const GroupSizes grouping
Definition qlocale_p.h:371
QString positiveSign() const
Definition qlocale.cpp:1097
QString groupSeparator() const
Definition qlocale.cpp:1056
QSimpleParsedNumber< qint64 > stringToLongLong(QStringView str, int base, QLocale::NumberOptions options) const
Definition qlocale.cpp:5116
Q_AUTOTEST_EXPORT char32_t zeroUcs() const
Definition qlocale.cpp:1076
QString zeroDigit() const
Definition qlocale.cpp:1071
bool numberToCLocale(QStringView s, QLocale::NumberOptions number_options, NumberMode mode, CharBuff *result) const
Returns a DigitSequence describing some portion of text starting at from.
Definition qlocale.cpp:4842
QString decimalPoint() const
Definition qlocale.cpp:1051
QString doubleToString(double d, int precision=-1, DoubleForm form=DFSignificantDigits, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4052
QLocaleId id() const
Definition qlocale_p.h:549
QString listSeparator() const
Definition qlocale.cpp:1066
QString percentSign() const
Definition qlocale.cpp:1061
@ AddTrailingZeroes
Definition qlocale_p.h:267
double stringToDouble(QStringView str, bool *ok, QLocale::NumberOptions options) const
Definition qlocale.cpp:5100
QString longLongToString(qint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4295
@ DoubleScientificMode
Definition qlocale_p.h:281
@ DFSignificantDigits
Definition qlocale_p.h:261
QString exponentSeparator() const
Definition qlocale.cpp:1102
QString negativeSign() const
Definition qlocale.cpp:1092
QSimpleParsedNumber< quint64 > stringToUnsLongLong(QStringView str, int base, QLocale::NumberOptions options) const
Definition qlocale.cpp:5127
QString unsLongLongToString(quint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:4310
QLocaleId withLikelySubtagsAdded() const noexcept
Definition qlocale.cpp:330
QLocaleId withLikelySubtagsRemoved() const noexcept
Definition qlocale.cpp:419
ushort script_id
Definition qlocale_p.h:242
bool operator==(QLocaleId other) const noexcept
Definition qlocale_p.h:211
ushort territory_id
Definition qlocale_p.h:242
ushort language_id
Definition qlocale_p.h:242