Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qlocale_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2016 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
5#include "qlocale_p.h"
6#include "qlocale_tools_p.h"
7
8#include "qstringlist.h"
9#include "qvariant.h"
10#include "qdatetime.h"
11#include "qdebug.h"
12
13#include "QtCore/private/qgregoriancalendar_p.h" // for yearSharingWeekDays()
14
15#include <q20algorithm.h>
16
17// TODO QTBUG-121193: port away from the use of LCID to always use names.
18#include <qt_windows.h>
19#include <time.h>
20
21#if QT_CONFIG(cpp_winrt)
22# include <QtCore/private/qt_winrtbase_p.h>
23
24# include <winrt/Windows.Foundation.h>
25# include <winrt/Windows.Foundation.Collections.h>
26# include <winrt/Windows.System.UserProfile.h>
27#endif // QT_CONFIG(cpp_winrt)
28
30
31using namespace Qt::StringLiterals;
32
33// Shared interpretation of %LANG%
34static auto scanLangEnv()
35{
36 struct R
37 {
38 QByteArray name; // empty means unknown; lookup from id may work
39 LCID id = 0; // 0 means unknown; lookup from name may work
40 } result;
41 const QByteArray lang = qgetenv("LANG");
42 if (lang.size() && (lang == "C" || qt_splitLocaleName(QString::fromLocal8Bit(lang)))) {
43 // See if we have a Windows locale code instead of a locale name:
44 const auto [id, used] = qstrntoll(lang.data(), lang.size(), 0);
45 if (used > 0 && id && INT_MIN <= id && id <= INT_MAX)
46 return R {QByteArray(), static_cast<LCID>(id)};
47 return R {lang, 0};
48 }
49 return R{};
50}
51
52static auto getDefaultWinId()
53{
54 const auto [name, id] = scanLangEnv();
55 if (id)
56 return id;
57
58 if (!name.isEmpty()) {
59 LCID id = LocaleNameToLCID(static_cast<LPCWSTR>(
60 QString::fromUtf8(name).toStdWString().data()), 0);
61 if (id)
62 return id;
63 }
64
65 return GetUserDefaultLCID();
66}
67
68static QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT);
69
70#ifndef QT_NO_SYSTEMLOCALE
71
72#ifndef MUI_LANGUAGE_NAME
73#define MUI_LANGUAGE_NAME 0x8
74#endif
75#ifndef LOCALE_SSHORTESTDAYNAME1
76# define LOCALE_SSHORTESTDAYNAME1 0x0060
77# define LOCALE_SSHORTESTDAYNAME2 0x0061
78# define LOCALE_SSHORTESTDAYNAME3 0x0062
79# define LOCALE_SSHORTESTDAYNAME4 0x0063
80# define LOCALE_SSHORTESTDAYNAME5 0x0064
81# define LOCALE_SSHORTESTDAYNAME6 0x0065
82# define LOCALE_SSHORTESTDAYNAME7 0x0066
83#endif
84#ifndef LOCALE_SNATIVELANGUAGENAME
85# define LOCALE_SNATIVELANGUAGENAME 0x00000004
86#endif
87#ifndef LOCALE_SNATIVECOUNTRYNAME
88# define LOCALE_SNATIVECOUNTRYNAME 0x00000008
89#endif
90#ifndef LOCALE_SSHORTTIME
91# define LOCALE_SSHORTTIME 0x00000079
92#endif
93
94namespace {
95template <typename T>
96static QVariant nullIfEmpty(T &&value)
97{
98 // For use where we should fall back to CLDR if we got an empty value.
99 if (value.isEmpty())
100 return {};
101 return std::move(value);
102}
103}
104
106{
108
133
134 void update();
135
136private:
137 enum SubstitutionType {
138 SUnknown,
139 SContext,
140 SAlways,
141 SNever
142 };
143
144 // cached values:
145 LCID lcid;
146 SubstitutionType substitutionType = SUnknown;
147 QString zero; // cached value for zeroDigit()
148
149 int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
150 QVariant getLocaleInfo(LCTYPE type);
151 int getLocaleInfo_int(LCTYPE type);
152
153 int getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size);
154 int getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size);
155 int getTimeFormat(DWORD flags, const SYSTEMTIME *date, LPCWSTR format, LPWSTR data, int size);
156
157 SubstitutionType substitution();
158 QString substituteDigits(QString &&string);
159 QString correctDigits(QString &&string);
160 QString yearFix(int year, int fakeYear, QString &&formatted);
161
162 static QString winToQtFormat(QStringView sys_fmt);
163
164};
165Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate)
166
171
172inline int QSystemLocalePrivate::getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size)
173{
174 return GetCurrencyFormat(lcid, flags, value, format, data, size);
175}
176
177inline int QSystemLocalePrivate::getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size)
178{
179 return GetDateFormat(lcid, flags, date, format, data, size);
180}
181
182inline int QSystemLocalePrivate::getTimeFormat(DWORD flags, const SYSTEMTIME *date, LPCWSTR format, LPWSTR data, int size)
183{
184 return GetTimeFormat(lcid, flags, date, format, data, size);
185}
186
187inline int QSystemLocalePrivate::getLocaleInfo(LCTYPE type, LPWSTR data, int size)
188{
189 return GetLocaleInfo(lcid, type, data, size);
190}
191
192QVariant QSystemLocalePrivate::getLocaleInfo(LCTYPE type)
193{
194 // https://docs.microsoft.com/en-us/windows/win32/intl/locale-spositivesign
195 // says empty for LOCALE_SPOSITIVESIGN means "+", although GetLocaleInfo()
196 // is documented to return 0 only on failure, so it's not clear how it
197 // returns empty to mean this; hence the two checks for it below.
198 const QString plus = QStringLiteral("+");
199 QVarLengthArray<wchar_t, 64> buf(64);
200 // Need to distinguish empty QString packaged as (non-null) QVariant from null QVariant:
201 if (!getLocaleInfo(type, buf.data(), buf.size())) {
202 const auto lastError = GetLastError();
203 if (type == LOCALE_SPOSITIVESIGN && lastError == ERROR_SUCCESS)
204 return plus;
205 if (lastError != ERROR_INSUFFICIENT_BUFFER)
206 return {};
207 int cnt = getLocaleInfo(type, 0, 0);
208 if (cnt == 0)
209 return {};
210 buf.resize(cnt);
211 if (!getLocaleInfo(type, buf.data(), buf.size()))
212 return {};
213 }
214 if (type == LOCALE_SPOSITIVESIGN && !buf[0])
215 return plus;
216 return QString::fromWCharArray(buf.data());
217}
218
219int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type)
220{
221 DWORD value;
222 int r = GetLocaleInfo(lcid, type | LOCALE_RETURN_NUMBER,
223 reinterpret_cast<wchar_t *>(&value),
224 sizeof(value) / sizeof(wchar_t));
225 return r == sizeof(value) / sizeof(wchar_t) ? value : 0;
226}
227
228QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
229{
230 if (substitutionType == SUnknown) {
231 wchar_t buf[8];
232 if (!getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, buf, 8)) {
233 substitutionType = SNever;
234 return substitutionType;
235 }
236 if (buf[0] == '1')
237 substitutionType = SNever;
238 else if (buf[0] == '0')
239 substitutionType = SContext;
240 else if (buf[0] == '2')
241 substitutionType = SAlways;
242 else {
243 wchar_t digits[11]; // See zeroDigit() for why 11.
244 if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
245 substitutionType = SNever;
246 return substitutionType;
247 }
248 if (buf[0] == digits[0] + 2)
249 substitutionType = SAlways;
250 else
251 substitutionType = SNever;
252 }
253 }
254 return substitutionType;
255}
256
257QString QSystemLocalePrivate::substituteDigits(QString &&string)
258{
259 zeroDigit(); // Ensure zero is set.
260 switch (zero.size()) {
261 case 1: {
262 ushort z = zero.at(0).unicode();
263 if (z == '0') // Nothing to do
264 break;
265 Q_ASSERT(z > '9');
266 ushort *const qch = reinterpret_cast<ushort *>(string.data());
267 for (qsizetype i = 0, stop = string.size(); i < stop; ++i) {
268 ushort &ch = qch[i];
269 if (ch >= '0' && ch <= '9')
270 ch = unicodeForDigit(ch - '0', z);
271 }
272 break;
273 }
274 case 2: {
275 // Surrogate pair (high, low):
276 char32_t z = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
277 for (int i = 0; i < 10; i++) {
278 char32_t digit = unicodeForDigit(i, z);
279 const QChar s[2] = { QChar::highSurrogate(digit), QChar::lowSurrogate(digit) };
280 string.replace(QString(QLatin1Char('0' + i)), QString(s, 2));
281 }
282 break;
283 }
284 default:
285 Q_ASSERT(!"Expected zero digit to be a single UCS2 code-point or a surrogate pair");
286 case 0: // Apparently this locale info was not available.
287 break;
288 }
289 return std::move(string);
290}
291
292QString QSystemLocalePrivate::correctDigits(QString &&string)
293{
294 return substitution() == SAlways ? substituteDigits(std::move(string)) : std::move(string);
295}
296
298{
299 if (zero.isEmpty()) {
300 /* Ten digits plus a terminator.
301
302 https://docs.microsoft.com/en-us/windows/win32/intl/locale-snative-constants
303 "Native equivalents of ASCII 0 through 9. The maximum number of
304 characters allowed for this string is eleven, including a terminating
305 null character."
306 */
307 wchar_t digits[11];
308 if (getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
309 // assert all(digits[i] == i + digits[0] for i in range(1, 10)),
310 // assumed above (unless digits[0] is 0x3007; see QTBUG-85409).
312 }
313 }
314 return nullIfEmpty(zero); // Do not std::move().
315}
316
318{
319 return nullIfEmpty(getLocaleInfo(LOCALE_SDECIMAL).toString());
320}
321
323{
324 return getLocaleInfo(LOCALE_STHOUSAND); // Empty means don't group digits.
325}
326
328{
329 return nullIfEmpty(getLocaleInfo(LOCALE_SNEGATIVESIGN).toString());
330}
331
333{
334 return nullIfEmpty(getLocaleInfo(LOCALE_SPOSITIVESIGN).toString());
335}
336
338{
339 switch (type) {
341 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE).toString()));
343 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE).toString()));
345 break;
346 }
347 return QVariant();
348}
349
351{
352 switch (type) {
354 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTTIME).toString()));
356 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT).toString()));
358 break;
359 }
360 return {};
361}
362
364{
366 if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString)
367 return QString(d.toString() + u' ' + t.toString());
368 return {};
369}
370
372{
373 if (day < 1 || day > 7)
374 return {};
375
376 static constexpr LCTYPE short_day_map[]
377 = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
378 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
379 LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 };
380
381 static constexpr LCTYPE long_day_map[]
382 = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2,
383 LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5,
384 LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 };
385
386 static constexpr LCTYPE narrow_day_map[]
391
392 return nullIfEmpty(getLocaleInfo(
393 (type == QLocale::LongFormat ? long_day_map
394 : type == QLocale::NarrowFormat ? narrow_day_map
395 : short_day_map)[day - 1]).toString());
396}
397
399{
400 static constexpr LCTYPE short_month_map[]
401 = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
402 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
403 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
404 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
405
406 static constexpr LCTYPE long_month_map[]
407 = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
408 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
409 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
410 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 };
411
412 if (month < 1 || month > 12)
413 return {};
414
415 // Month is Jan = 1, ... Dec = 12; adjust by 1 to match array indexing from 0:
416 return nullIfEmpty(getLocaleInfo(
417 (type == QLocale::LongFormat ? long_month_map : short_month_map)[month - 1]).toString());
418}
419
421{
422 SYSTEMTIME st = {};
423 st.wYear = 2001;
424 st.wMonth = month;
425 st.wDay = 10;
426
427 const DWORD flags{}; // Must be clear when passing a format string.
428 // MS's docs for the LOCALE_SMONTHNAME* say to include the day in a format.
429 // Educated guess: this works for the LOCALE_SABBREVMONTHNAME*, too, in so
430 // far as the abbreviated plain name might differ from abbreviated
431 // standalone one.
432 const wchar_t *const format = type == QLocale::LongFormat ? L"ddMMMM" : L"ddMMM";
433 wchar_t buf[255];
434 if (getDateFormat(flags, &st, format, buf, 255) > 2) {
435 // Elide the two digits of day number
436 return nullIfEmpty(correctDigits(QString::fromWCharArray(buf + 2)));
437 }
438 return {};
439}
440
441static QString fourDigitYear(int year)
442{
443 // Return year formatted as an (at least) four digit number:
444 return QStringLiteral("%1").arg(year, 4, 10, QChar(u'0'));
445}
446
447QString QSystemLocalePrivate::yearFix(int year, int fakeYear, QString &&formatted)
448{
449 // Replace our ersatz fakeYear (that MS formats faithfully) with the correct
450 // form of year. We know the two-digit short form of fakeYear can not be
451 // mistaken for the month or day-of-month in the formatted date.
452 Q_ASSERT(fakeYear >= 1970 && fakeYear <= 2400);
453 const bool matchTwo = year >= 0 && year % 100 == fakeYear % 100;
454 auto yearUsed = fourDigitYear(fakeYear);
455 QString sign(year < 0 ? 1 : 0, u'-');
456 auto trueYear = fourDigitYear(year < 0 ? -year : year);
457 if (formatted.contains(yearUsed))
458 return std::move(formatted).replace(yearUsed, sign + trueYear);
459
460 auto tail = QStringView{yearUsed}.last(2);
461 Q_ASSERT(!matchTwo || tail == QString(sign + trueYear.last(2)));
462 if (formatted.contains(tail)) {
463 if (matchTwo)
464 return std::move(formatted);
465 return std::move(formatted).replace(tail.toString(), sign + trueYear.last(2));
466 }
467
468 // Localized digits (regardless of SAlways), perhaps ?
469 // First call to substituteDigits() ensures zero is initialized:
470 trueYear = substituteDigits(std::move(trueYear));
471 if (zero != u'0') {
472 yearUsed = substituteDigits(std::move(yearUsed));
473 if (year < 0)
475
476 if (formatted.contains(yearUsed))
477 return std::move(formatted).replace(yearUsed, sign + trueYear);
478
479 const qsizetype twoDigits = 2 * zero.size();
480 tail = QStringView{yearUsed}.last(twoDigits);
481 if (formatted.contains(tail)) {
482 if (matchTwo)
483 return std::move(formatted);
484 return std::move(formatted).replace(tail.toString(), sign + trueYear.last(twoDigits));
485 }
486 }
487 qWarning("Failed to fix up year in formatted date-string using %d for %d", fakeYear, year);
488 return std::move(formatted);
489}
490
492{
493 SYSTEMTIME st = {};
494 const int year = date.year();
495 // st.wYear is unsigned; and GetDateFormat() is documented to not handle
496 // dates before 1601.
497 const bool fixup = year < 1601;
498 st.wYear = fixup ? QGregorianCalendar::yearSharingWeekDays(date) : year;
499 st.wMonth = date.month();
500 st.wDay = date.day();
501
502 Q_ASSERT(!fixup || st.wYear % 100 != st.wMonth);
503 Q_ASSERT(!fixup || st.wYear % 100 != st.wDay);
504 // i.e. yearFix() can trust a match of its fakeYear's last two digits to not
505 // be the month or day part of the formatted date.
506
507 DWORD flags = (type == QLocale::LongFormat ? DATE_LONGDATE : DATE_SHORTDATE);
508 wchar_t buf[255];
509 if (getDateFormat(flags, &st, NULL, buf, 255)) {
511 if (fixup)
512 text = yearFix(year, st.wYear, std::move(text));
513 return nullIfEmpty(correctDigits(std::move(text)));
514 }
515 return {};
516}
517
519{
520 SYSTEMTIME st = {};
521 st.wHour = time.hour();
522 st.wMinute = time.minute();
523 st.wSecond = time.second();
524 st.wMilliseconds = 0;
525
526 DWORD flags = 0;
527 // keep the same conditional as timeFormat() above
529 ? getLocaleInfo(LOCALE_SSHORTTIME).toString()
530 : QString();
531 auto formatStr = reinterpret_cast<const wchar_t *>(format.isEmpty() ? nullptr : format.utf16());
532
533 wchar_t buf[255];
534 if (getTimeFormat(flags, &st, formatStr, buf, int(std::size(buf))))
535 return nullIfEmpty(correctDigits(QString::fromWCharArray(buf)));
536 return {};
537}
538
540{
541 QVariant d = toString(dt.date(), type), t = toString(dt.time(), type);
542 if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString)
543 return QString(d.toString() + u' ' + t.toString());
544 return {};
545}
546
548{
549 wchar_t output[2];
550
551 if (getLocaleInfo(LOCALE_IMEASURE, output, 2)) {
552 if (output[0] == L'1' && !output[1])
554 }
555
557}
558
560{
561 return getLocaleInfo(LOCALE_SSORTLOCALE);
562}
563
565{
566 wchar_t output[15]; // maximum length including terminating zero character for Win2003+
567
568 if (getLocaleInfo(LOCALE_S1159, output, 15))
569 return nullIfEmpty(QString::fromWCharArray(output));
570
571 return QVariant();
572}
573
575{
576 wchar_t output[15]; // maximum length including terminating zero character for Win2003+
577
578 if (getLocaleInfo(LOCALE_S2359, output, 15))
579 return nullIfEmpty(QString::fromWCharArray(output));
580
581 return QVariant();
582}
583
585{
586 wchar_t output[4]; // maximum length including terminating zero character for Win2003+
587
588 if (getLocaleInfo(LOCALE_IFIRSTDAYOFWEEK, output, 4))
589 return QString::fromWCharArray(output).toUInt()+1;
590
591 return 1;
592}
593
595{
596 wchar_t buf[13];
597 switch (format) {
599 // Some locales do have empty currency symbol. All the same, fall back
600 // to CLDR for confirmation if MS claims that applies.
601 if (getLocaleInfo(LOCALE_SCURRENCY, buf, 13))
602 return nullIfEmpty(QString::fromWCharArray(buf));
603 break;
605 if (getLocaleInfo(LOCALE_SINTLSYMBOL, buf, 9))
606 return nullIfEmpty(QString::fromWCharArray(buf));
607 break;
609 QVarLengthArray<wchar_t, 64> buf(64);
610 if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) {
611 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
612 break;
613 buf.resize(255); // should be large enough, right?
614 if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size()))
615 break;
616 }
617 return nullIfEmpty(QString::fromWCharArray(buf.data()));
618 }
619 default:
620 break;
621 }
622 return QVariant();
623}
624
626{
628 switch (arg.value.typeId()) {
629 case QMetaType::Int:
630 value = QLocaleData::c()->longLongToString(
631 arg.value.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
632 break;
633 case QMetaType::UInt:
634 value = QLocaleData::c()->unsLongLongToString(
635 arg.value.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
636 break;
637 case QMetaType::Double:
638 value = QLocaleData::c()->doubleToString(
639 arg.value.toDouble(), -1, QLocaleData::DFDecimal, -1, QLocale::OmitGroupSeparator);
640 break;
641 case QMetaType::LongLong:
642 value = QLocaleData::c()->longLongToString(
643 arg.value.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
644 break;
645 case QMetaType::ULongLong:
646 value = QLocaleData::c()->unsLongLongToString(
647 arg.value.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
648 break;
649 default:
650 return QVariant();
651 }
652
653 QVarLengthArray<wchar_t, 64> out(64);
654
655 QString decimalSep;
656 QString thousandSep;
657 CURRENCYFMT format;
658 CURRENCYFMT *pformat = NULL;
659 if (!arg.symbol.isEmpty()) {
660 format.NumDigits = getLocaleInfo_int(LOCALE_ICURRDIGITS);
661 format.LeadingZero = getLocaleInfo_int(LOCALE_ILZERO);
662 decimalSep = getLocaleInfo(LOCALE_SMONDECIMALSEP).toString();
663 format.lpDecimalSep = (wchar_t *)decimalSep.utf16();
664 thousandSep = getLocaleInfo(LOCALE_SMONTHOUSANDSEP).toString();
665 format.lpThousandSep = (wchar_t *)thousandSep.utf16();
666 format.NegativeOrder = getLocaleInfo_int(LOCALE_INEGCURR);
667 format.PositiveOrder = getLocaleInfo_int(LOCALE_ICURRENCY);
668 format.lpCurrencySymbol = (wchar_t *)arg.symbol.utf16();
669
670 // grouping is complicated and ugly:
671 // int(0) == "123456789.00" == string("0")
672 // int(3) == "123,456,789.00" == string("3;0")
673 // int(30) == "123456,789.00" == string("3;0;0")
674 // int(32) == "12,34,56,789.00" == string("3;2;0")
675 // int(320)== "1234,56,789.00" == string("3;2")
676 QString groupingStr = getLocaleInfo(LOCALE_SMONGROUPING).toString();
677 format.Grouping = groupingStr.remove(u';').toInt();
678 if (format.Grouping % 10 == 0) // magic
679 format.Grouping /= 10;
680 else
681 format.Grouping *= 10;
682 pformat = &format;
683 }
684
685 int ret = getCurrencyFormat(0, reinterpret_cast<const wchar_t *>(value.utf16()),
686 pformat, out.data(), out.size());
687 if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
688 ret = getCurrencyFormat(0, reinterpret_cast<const wchar_t *>(value.utf16()),
689 pformat, out.data(), 0);
690 out.resize(ret);
691 getCurrencyFormat(0, reinterpret_cast<const wchar_t *>(value.utf16()),
692 pformat, out.data(), out.size());
693 }
694
695 return nullIfEmpty(correctDigits(QString::fromWCharArray(out.data())));
696}
697
699{
701#if QT_CONFIG(cpp_winrt)
702 using namespace winrt;
703 using namespace Windows::System::UserProfile;
704 QT_TRY {
705 auto languages = GlobalizationPreferences::Languages();
706 for (const auto &lang : languages)
707 result << QString::fromStdString(winrt::to_string(lang));
708 } QT_CATCH(...) {
709 // pass, just fall back to WIN32 API implementation
710 }
711 if (!result.isEmpty())
712 return result; // else just fall back to WIN32 API implementation
713#endif // QT_CONFIG(cpp_winrt)
714 // mingw and clang still have to use Win32 API
715 unsigned long cnt = 0;
716 QVarLengthArray<wchar_t, 64> buf(64);
717# if !defined(QT_BOOTSTRAPPED) // Not present in MinGW 4.9/bootstrap builds.
718 unsigned long size = buf.size();
719 if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) {
720 size = 0;
721 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
722 GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) {
723 buf.resize(size);
724 if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size))
725 return {};
726 }
727 }
728# endif // !QT_BOOTSTRAPPED
729 result.reserve(cnt);
730 const wchar_t *str = buf.constData();
731 for (; cnt > 0; --cnt) {
733 if (s.isEmpty())
734 break; // something is wrong
735 result.append(s);
736 str += s.size() + 1;
737 }
738 return nullIfEmpty(std::move(result));
739}
740
745
750
751
753{
754 lcid = getDefaultWinId();
755 substitutionType = SUnknown;
756 zero.resize(0);
757}
758
759QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt)
760{
762 qsizetype i = 0;
763
764 while (i < sys_fmt.size()) {
765 if (sys_fmt.at(i).unicode() == u'\'') {
767 if (text == "'"_L1)
768 result += "''"_L1;
769 else
770 result += u'\'' + text + u'\'';
771 continue;
772 }
773
774 QChar c = sys_fmt.at(i);
775 qsizetype repeat = qt_repeatCount(sys_fmt.mid(i));
776
777 switch (c.unicode()) {
778 // Date
779 case 'y':
780 if (repeat > 5)
781 repeat = 5;
782 else if (repeat == 3)
783 repeat = 2;
784 switch (repeat) {
785 case 1:
786 result += "yy"_L1; // "y" unsupported by Qt, use "yy"
787 break;
788 case 5:
789 result += "yyyy"_L1; // "yyyyy" same as "yyyy" on Windows
790 break;
791 default:
792 result += QString(repeat, u'y');
793 break;
794 }
795 break;
796 case 'g':
797 if (repeat > 2)
798 repeat = 2;
799 switch (repeat) {
800 case 2:
801 break; // no equivalent of "gg" in Qt
802 default:
803 result += u'g';
804 break;
805 }
806 break;
807 case 't':
808 if (repeat > 2)
809 repeat = 2;
810 result += "AP"_L1; // "t" unsupported, use "AP"
811 break;
812 default:
813 result += QString(repeat, c);
814 break;
815 }
816
817 i += repeat;
818 }
819
820 return result;
821}
822
824{
826}
827
828QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
829{
830 QSystemLocalePrivate *d = systemLocalePrivate();
831 switch(type) {
832 case DecimalPoint:
833 return d->decimalPoint();
834 case GroupSeparator:
835 return d->groupSeparator();
836 case NegativeSign:
837 return d->negativeSign();
838 case PositiveSign:
839 return d->positiveSign();
840 case DateFormatLong:
841 return d->dateFormat(QLocale::LongFormat);
842 case DateFormatShort:
843 return d->dateFormat(QLocale::ShortFormat);
844 case TimeFormatLong:
845 return d->timeFormat(QLocale::LongFormat);
846 case TimeFormatShort:
847 return d->timeFormat(QLocale::ShortFormat);
849 return d->dateTimeFormat(QLocale::LongFormat);
851 return d->dateTimeFormat(QLocale::ShortFormat);
852 case DayNameLong:
853 return d->dayName(in.toInt(), QLocale::LongFormat);
854 case DayNameShort:
855 return d->dayName(in.toInt(), QLocale::ShortFormat);
856 case DayNameNarrow:
857 return d->dayName(in.toInt(), QLocale::NarrowFormat);
861 // Windows does not provide standalone day names, so fall back to CLDR
862 return QVariant();
863 case MonthNameLong:
864 return d->monthName(in.toInt(), QLocale::LongFormat);
866 return d->standaloneMonthName(in.toInt(), QLocale::LongFormat);
867 case MonthNameShort:
868 return d->monthName(in.toInt(), QLocale::ShortFormat);
870 return d->standaloneMonthName(in.toInt(), QLocale::ShortFormat);
871 case MonthNameNarrow:
873 // Windows provides no narrow month names, so we fall back to CLDR
874 return QVariant();
876 return d->toString(in.toDate(), QLocale::ShortFormat);
877 case DateToStringLong:
878 return d->toString(in.toDate(), QLocale::LongFormat);
880 return d->toString(in.toTime(), QLocale::ShortFormat);
881 case TimeToStringLong:
882 return d->toString(in.toTime(), QLocale::LongFormat);
884 return d->toString(in.toDateTime(), QLocale::ShortFormat);
886 return d->toString(in.toDateTime(), QLocale::LongFormat);
887 case ZeroDigit:
888 return d->zeroDigit();
889 case LanguageId:
890 case ScriptId:
891 case TerritoryId: {
893 if (type == LanguageId)
894 return lid.language_id;
895 if (type == ScriptId)
896 return lid.script_id ? lid.script_id : ushort(fallbackLocale().script());
897 return lid.territory_id ? lid.territory_id : ushort(fallbackLocale().territory());
898 }
900 return d->measurementSystem();
901 case Collation:
902 return d->collation();
903 case AMText:
904 return d->amText();
905 case PMText:
906 return d->pmText();
907 case FirstDayOfWeek:
908 return d->firstDayOfWeek();
909 case CurrencySymbol:
910 return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
911 case CurrencyToString:
912 return d->toCurrencyString(in.value<CurrencyToStringArgument>());
913 case UILanguages:
914 return d->uiLanguages();
915 case LocaleChanged:
916 d->update();
917 break;
919 return d->nativeLanguageName();
921 return d->nativeTerritoryName();
922 default:
923 break;
924 }
925 return QVariant();
926}
927#endif // QT_NO_SYSTEMLOCALE
928
933
934namespace {
935struct ByWindowsCode {
936 constexpr bool operator()(int lhs, WindowsToISOListElt rhs) const noexcept
937 { return lhs < int(rhs.windows_code); }
938 constexpr bool operator()(WindowsToISOListElt lhs, int rhs) const noexcept
939 { return int(lhs.windows_code) < rhs; }
940 constexpr bool operator()(WindowsToISOListElt lhs, WindowsToISOListElt rhs) const noexcept
941 { return lhs.windows_code < rhs.windows_code; }
942};
943} // unnamed namespace
944
946 { 0x0401, "ar_SA" },
947 { 0x0402, "bg\0 " },
948 { 0x0403, "ca\0 " },
949 { 0x0404, "zh_TW" },
950 { 0x0405, "cs\0 " },
951 { 0x0406, "da\0 " },
952 { 0x0407, "de\0 " },
953 { 0x0408, "el\0 " },
954 { 0x0409, "en_US" },
955 { 0x040a, "es\0 " },
956 { 0x040b, "fi\0 " },
957 { 0x040c, "fr\0 " },
958 { 0x040d, "he\0 " },
959 { 0x040e, "hu\0 " },
960 { 0x040f, "is\0 " },
961 { 0x0410, "it\0 " },
962 { 0x0411, "ja\0 " },
963 { 0x0412, "ko\0 " },
964 { 0x0413, "nl\0 " },
965 { 0x0414, "no\0 " },
966 { 0x0415, "pl\0 " },
967 { 0x0416, "pt_BR" },
968 { 0x0418, "ro\0 " },
969 { 0x0419, "ru\0 " },
970 { 0x041a, "hr\0 " },
971 { 0x041c, "sq\0 " },
972 { 0x041d, "sv\0 " },
973 { 0x041e, "th\0 " },
974 { 0x041f, "tr\0 " },
975 { 0x0420, "ur\0 " },
976 { 0x0421, "in\0 " },
977 { 0x0422, "uk\0 " },
978 { 0x0423, "be\0 " },
979 { 0x0425, "et\0 " },
980 { 0x0426, "lv\0 " },
981 { 0x0427, "lt\0 " },
982 { 0x0429, "fa\0 " },
983 { 0x042a, "vi\0 " },
984 { 0x042d, "eu\0 " },
985 { 0x042f, "mk\0 " },
986 { 0x0436, "af\0 " },
987 { 0x0438, "fo\0 " },
988 { 0x0439, "hi\0 " },
989 { 0x043e, "ms\0 " },
990 { 0x0458, "mt\0 " },
991 { 0x0801, "ar_IQ" },
992 { 0x0804, "zh_CN" },
993 { 0x0807, "de_CH" },
994 { 0x0809, "en_GB" },
995 { 0x080a, "es_MX" },
996 { 0x080c, "fr_BE" },
997 { 0x0810, "it_CH" },
998 { 0x0812, "ko\0 " },
999 { 0x0813, "nl_BE" },
1000 { 0x0814, "no\0 " },
1001 { 0x0816, "pt\0 " },
1002 { 0x081a, "sr\0 " },
1003 { 0x081d, "sv_FI" },
1004 { 0x0c01, "ar_EG" },
1005 { 0x0c04, "zh_HK" },
1006 { 0x0c07, "de_AT" },
1007 { 0x0c09, "en_AU" },
1008 { 0x0c0a, "es\0 " },
1009 { 0x0c0c, "fr_CA" },
1010 { 0x0c1a, "sr\0 " },
1011 { 0x1001, "ar_LY" },
1012 { 0x1004, "zh_SG" },
1013 { 0x1007, "de_LU" },
1014 { 0x1009, "en_CA" },
1015 { 0x100a, "es_GT" },
1016 { 0x100c, "fr_CH" },
1017 { 0x1401, "ar_DZ" },
1018 { 0x1407, "de_LI" },
1019 { 0x1409, "en_NZ" },
1020 { 0x140a, "es_CR" },
1021 { 0x140c, "fr_LU" },
1022 { 0x1801, "ar_MA" },
1023 { 0x1809, "en_IE" },
1024 { 0x180a, "es_PA" },
1025 { 0x1c01, "ar_TN" },
1026 { 0x1c09, "en_ZA" },
1027 { 0x1c0a, "es_DO" },
1028 { 0x2001, "ar_OM" },
1029 { 0x2009, "en_JM" },
1030 { 0x200a, "es_VE" },
1031 { 0x2401, "ar_YE" },
1032 { 0x2409, "en\0 " },
1033 { 0x240a, "es_CO" },
1034 { 0x2801, "ar_SY" },
1035 { 0x2809, "en_BZ" },
1036 { 0x280a, "es_PE" },
1037 { 0x2c01, "ar_JO" },
1038 { 0x2c09, "en_TT" },
1039 { 0x2c0a, "es_AR" },
1040 { 0x3001, "ar_LB" },
1041 { 0x300a, "es_EC" },
1042 { 0x3401, "ar_KW" },
1043 { 0x340a, "es_CL" },
1044 { 0x3801, "ar_AE" },
1045 { 0x380a, "es_UY" },
1046 { 0x3c01, "ar_BH" },
1047 { 0x3c0a, "es_PY" },
1048 { 0x4001, "ar_QA" },
1049 { 0x400a, "es_BO" },
1050 { 0x440a, "es_SV" },
1051 { 0x480a, "es_HN" },
1052 { 0x4c0a, "es_NI" },
1053 { 0x500a, "es_PR" }
1054};
1055
1056static_assert(q20::is_sorted(std::begin(windows_to_iso_list), std::end(windows_to_iso_list),
1057 ByWindowsCode{}));
1058
1059static const char *winLangCodeToIsoName(int code)
1060{
1061 int cmp = code - windows_to_iso_list[0].windows_code;
1062 if (cmp < 0)
1063 return nullptr;
1064
1065 if (cmp == 0)
1066 return windows_to_iso_list[0].iso_name;
1067
1068 const auto it = std::lower_bound(std::begin(windows_to_iso_list),
1069 std::end(windows_to_iso_list),
1070 code,
1071 ByWindowsCode{});
1072 if (it != std::end(windows_to_iso_list) && !ByWindowsCode{}(code, *it))
1073 return it->iso_name;
1074
1075 return nullptr;
1076
1077}
1078
1079LCID qt_inIsoNametoLCID(const char *name)
1080{
1081 if (!name)
1082 return LOCALE_USER_DEFAULT;
1083 // handle norwegian manually, the list above will fail
1084 if (!strncmp(name, "nb", 2))
1085 return 0x0414;
1086 if (!strncmp(name, "nn", 2))
1087 return 0x0814;
1088
1089 char n[64];
1090 strncpy(n, name, sizeof(n));
1091 n[sizeof(n)-1] = 0;
1092 char *c = n;
1093 while (*c) {
1094 if (*c == '-')
1095 *c = '_';
1096 ++c;
1097 }
1098
1100 if (!strcmp(n, i.iso_name))
1101 return i.windows_code;
1102 }
1103 return LOCALE_USER_DEFAULT;
1104}
1105
1106
1108{
1110
1111 // Windows returns the wrong ISO639 for some languages, we need to detect them here using
1112 // the language code
1113 QString lang_code;
1114 wchar_t out[256];
1115 if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255))
1116 lang_code = QString::fromWCharArray(out);
1117
1118 if (!lang_code.isEmpty()) {
1119 const QByteArray latin1 = std::move(lang_code).toLatin1();
1120 const auto [i, used] = qstrntoull(latin1.data(), latin1.size(), 16);
1121 if (used >= latin1.size() || (used > 0 && latin1[used] == '\0')) {
1122 switch (i) {
1123 case 0x814:
1124 result = u"nn"_s; // Nynorsk
1125 break;
1126 default:
1127 break;
1128 }
1129 }
1130 }
1131
1132 if (!result.isEmpty())
1133 return result;
1134
1135 // not one of the problematic languages - do the usual lookup
1136 if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME, out, 255))
1138
1139 return result;
1140}
1141
1143{
1145
1146 wchar_t out[256];
1147 if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255))
1149
1150 return result;
1151}
1152
1154{
1156 if (id == LOCALE_USER_DEFAULT) {
1157 const auto [name, lcid] = scanLangEnv();
1158 if (!name.isEmpty())
1159 return name;
1160 if (lcid)
1161 return winLangCodeToIsoName(lcid);
1162
1163 id = GetUserDefaultLCID();
1164 }
1165
1166 QString resultusage = winIso639LangName(id);
1167 QString country = winIso3116CtryName(id);
1168 if (!country.isEmpty())
1169 resultusage += u'_' + country;
1170
1171 return std::move(resultusage).toLatin1();
1172}
1173
1174// Helper for plugins/platforms/windows/
1175Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
1176{
1178}
1179
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
\inmodule QtCore
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore \reentrant
Definition qdatetime.h:29
int month() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int day() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static int yearSharingWeekDays(QDate date)
@ MetricSystem
Definition qlocale.h:868
@ ImperialSystem
Definition qlocale.h:871
CurrencySymbolFormat
Definition qlocale.h:896
@ CurrencySymbol
Definition qlocale.h:898
@ CurrencyIsoCode
Definition qlocale.h:897
@ CurrencyDisplayName
Definition qlocale.h:899
@ LongFormat
Definition qlocale.h:875
@ NarrowFormat
Definition qlocale.h:875
@ ShortFormat
Definition qlocale.h:875
@ OmitGroupSeparator
Definition qlocale.h:879
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView last(qsizetype n) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLatin1() const &
Definition qstring.h:630
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromStdString(const std::string &s)
Definition qstring.h:1447
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2668
@ DateTimeToStringShort
Definition qlocale_p.h:148
@ StandaloneMonthNameLong
Definition qlocale_p.h:166
@ StandaloneDayNameNarrow
Definition qlocale_p.h:171
@ StandaloneMonthNameNarrow
Definition qlocale_p.h:168
@ StandaloneDayNameShort
Definition qlocale_p.h:170
@ StandaloneDayNameLong
Definition qlocale_p.h:169
@ StandaloneMonthNameShort
Definition qlocale_p.h:167
virtual QLocale fallbackLocale() const
virtual QVariant query(QueryType type, QVariant &&in=QVariant()) const
\inmodule QtCore \reentrant
Definition qdatetime.h:215
int hour() const
Returns the hour part (0 to 23) of the time.
int minute() const
Returns the minute part (0 to 59) of the time.
int second() const
Returns the second part (0 to 59) of the time.
\inmodule QtCore
Definition qvariant.h:65
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
QString str
[2]
QString text
QDate date
[1]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr bool is_sorted(ForwardIterator first, ForwardIterator last, BinaryPredicate p={})
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define QT_CATCH(A)
#define QT_TRY
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
qsizetype qt_repeatCount(QStringView s)
Definition qlocale.cpp:675
bool qt_splitLocaleName(QStringView name, QStringView *lang, QStringView *script, QStringView *land)
Definition qlocale.cpp:567
QString qt_readEscapedFormatString(QStringView format, qsizetype *idx)
Definition qlocale.cpp:625
static constexpr int digits(int number)
QSimpleParsedNumber< qlonglong > qstrntoll(const char *begin, qsizetype size, int base)
QSimpleParsedNumber< qulonglong > qstrntoull(const char *begin, qsizetype size, int base)
UcsInt unicodeForDigit(uint digit, UcsInt zero)
static QByteArray getWinLocaleName(LCID id=LOCALE_USER_DEFAULT)
static QString fourDigitYear(int year)
#define LOCALE_SSHORTESTDAYNAME2
static auto scanLangEnv()
#define LOCALE_SSHORTTIME
#define LOCALE_SSHORTESTDAYNAME4
#define LOCALE_SSHORTESTDAYNAME3
#define LOCALE_SSHORTESTDAYNAME7
static constexpr WindowsToISOListElt windows_to_iso_list[]
#define LOCALE_SSHORTESTDAYNAME5
#define LOCALE_SNATIVELANGUAGENAME
Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
static QString winIso3116CtryName(LCID id)
#define LOCALE_SSHORTESTDAYNAME6
#define LOCALE_SNATIVECOUNTRYNAME
static auto getDefaultWinId()
#define MUI_LANGUAGE_NAME
LCID qt_inIsoNametoLCID(const char *name)
static const char * winLangCodeToIsoName(int code)
#define LOCALE_SSHORTESTDAYNAME1
static QString winIso639LangName(LCID id)
#define qWarning
Definition qlogging.h:166
return ret
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLuint name
GLfloat n
GLint GLsizei GLsizei GLenum format
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint in
GLuint64EXT * result
[6]
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned short ushort
Definition qtypes.h:33
QT_BEGIN_NAMESPACE typedef uchar * output
static int sign(int x)
QTextStream out(stdout)
[7]
QObject::connect nullptr
\inmodule QtCore \reentrant
Definition qchar.h:18
static const QLocaleData * c()
Definition qlocale.cpp:856
static Q_AUTOTEST_EXPORT QLocaleId fromName(QStringView name)
Definition qlocale.cpp:611
QVariant dateFormat(QLocale::FormatType)
QVariant toString(QDate, QLocale::FormatType)
QVariant dayName(int, QLocale::FormatType)
QVariant monthName(int, QLocale::FormatType)
QVariant currencySymbol(QLocale::CurrencySymbolFormat)
QVariant nativeLanguageName()
QVariant standaloneMonthName(int, QLocale::FormatType)
QVariant nativeTerritoryName()
QVariant dateTimeFormat(QLocale::FormatType)
QVariant measurementSystem()
QVariant timeFormat(QLocale::FormatType)
QVariant toCurrencyString(const QSystemLocale::CurrencyToStringArgument &)