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