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