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