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