14#include "QtCore/private/qgregoriancalendar_p.h"
16#include <q20algorithm.h>
19#include <qt_windows.h>
22#if QT_CONFIG(cpp_winrt)
23# include <QtCore/private/qt_winrtbase_p.h>
25# include <winrt/Windows.Foundation.h>
26# include <winrt/Windows.Foundation.Collections.h>
27# include <winrt/Windows.System.UserProfile.h>
32using namespace Qt::StringLiterals;
42 const QByteArray lang = qgetenv(
"LANG");
43 if (lang.size() && (lang ==
"C" || qt_splitLocaleName(QString::fromLocal8Bit(lang)))) {
45 const auto [id, used] = qstrntoll(lang.data(), lang.size(), 0);
46 if (used > 0 && id && INT_MIN <= id && id <= INT_MAX)
47 return R {QByteArray(),
static_cast<LCID>(id)};
55 const auto [name, id] = scanLangEnv();
59 if (!name.isEmpty()) {
60 LCID id = LocaleNameToLCID(
static_cast<LPCWSTR>(
61 QString::fromUtf8(name).toStdWString().data()), 0);
66 return GetUserDefaultLCID();
71#ifndef QT_NO_SYSTEMLOCALE
73#ifndef MUI_LANGUAGE_NAME
74#define MUI_LANGUAGE_NAME 0x8
76#ifndef LOCALE_SSHORTESTDAYNAME1
77# define LOCALE_SSHORTESTDAYNAME1 0x0060
78# define LOCALE_SSHORTESTDAYNAME2 0x0061
79# define LOCALE_SSHORTESTDAYNAME3 0x0062
80# define LOCALE_SSHORTESTDAYNAME4 0x0063
81# define LOCALE_SSHORTESTDAYNAME5 0x0064
82# define LOCALE_SSHORTESTDAYNAME6 0x0065
83# define LOCALE_SSHORTESTDAYNAME7 0x0066
85#ifndef LOCALE_SNATIVELANGUAGENAME
86# define LOCALE_SNATIVELANGUAGENAME 0x00000004
88#ifndef LOCALE_SNATIVECOUNTRYNAME
89# define LOCALE_SNATIVECOUNTRYNAME 0x00000008
91#ifndef LOCALE_SSHORTTIME
92# define LOCALE_SSHORTTIME 0x00000079
97static QVariant nullIfEmpty(T &&value)
102 return std::forward<T>(value);
139 enum SubstitutionType {
148 SubstitutionType substitutionType = SUnknown;
152 int getLocaleInfo(LCTYPE type, LPWSTR data,
int size);
153 QVariant getLocaleInfo(LCTYPE type);
154 int getLocaleInfo_int(LCTYPE type);
156 int getCurrencyFormat(DWORD flags, LPCWSTR value,
const CURRENCYFMTW *format, LPWSTR data,
int size);
157 int getDateFormat(DWORD flags,
const SYSTEMTIME * date, LPCWSTR format, LPWSTR data,
int size);
158 int getTimeFormat(DWORD flags,
const SYSTEMTIME *date, LPCWSTR format, LPWSTR data,
int size);
160 SubstitutionType substitution();
161 QString substituteDigits(QString &&string);
162 QString correctDigits(QString &&string);
163 QString yearFix(
int year,
int fakeYear, QString &&formatted);
165 static QString winToQtFormat(QStringView sys_fmt);
170QSystemLocalePrivate::QSystemLocalePrivate()
171 : lcid(getDefaultWinId())
175inline int QSystemLocalePrivate::getCurrencyFormat(DWORD flags, LPCWSTR value,
const CURRENCYFMTW *format, LPWSTR data,
int size)
177 return GetCurrencyFormat(lcid, flags, value, format, data, size);
180inline int QSystemLocalePrivate::getDateFormat(DWORD flags,
const SYSTEMTIME * date, LPCWSTR format, LPWSTR data,
int size)
182 return GetDateFormat(lcid, flags, date, format, data, size);
185inline int QSystemLocalePrivate::getTimeFormat(DWORD flags,
const SYSTEMTIME *date, LPCWSTR format, LPWSTR data,
int size)
187 return GetTimeFormat(lcid, flags, date, format, data, size);
192 return GetLocaleInfo(lcid, type, data, size);
202 QVarLengthArray<
wchar_t, 64> buf(64);
204 if (!getLocaleInfo(type, buf.data(), buf.size())) {
205 const auto lastError = GetLastError();
206 if (type == LOCALE_SPOSITIVESIGN && lastError == ERROR_SUCCESS)
208 if (lastError != ERROR_INSUFFICIENT_BUFFER)
210 int cnt = getLocaleInfo(type, 0, 0);
214 if (!getLocaleInfo(type, buf.data(), buf.size()))
217 if (type == LOCALE_SPOSITIVESIGN && !buf[0])
219 return QString::fromWCharArray(buf.data());
225 int r = GetLocaleInfo(lcid, type | LOCALE_RETURN_NUMBER,
226 reinterpret_cast<
wchar_t *>(&value),
227 sizeof(value) /
sizeof(
wchar_t));
228 return r ==
sizeof(value) /
sizeof(
wchar_t) ? value : 0;
233 if (substitutionType == SUnknown) {
235 if (!getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, buf, 8)) {
236 substitutionType = SNever;
237 return substitutionType;
240 substitutionType = SNever;
241 else if (buf[0] ==
'0')
242 substitutionType = SContext;
243 else if (buf[0] ==
'2')
244 substitutionType = SAlways;
247 if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
248 substitutionType = SNever;
249 return substitutionType;
251 if (buf[0] == digits[0] + 2)
252 substitutionType = SAlways;
254 substitutionType = SNever;
257 return substitutionType;
263 switch (zero.size()) {
265 ushort z = zero.at(0).unicode();
269 ushort *
const qch =
reinterpret_cast<ushort *>(string.data());
270 for (qsizetype i = 0, stop = string.size(); i < stop; ++i) {
272 if (ch >=
'0' && ch <=
'9')
273 ch = unicodeForDigit(ch -
'0', z);
279 char32_t z = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
280 for (
int i = 0; i < 10; i++) {
281 char32_t digit = unicodeForDigit(i, z);
282 const QChar s[2] = { QChar::highSurrogate(digit), QChar::lowSurrogate(digit) };
283 string.replace(QString(QLatin1Char(
'0' + i)), QString(s, 2));
288 Q_ASSERT(!
"Expected zero digit to be a single UCS2 code-point or a surrogate pair");
292 return std::move(string);
297 return substitution() == SAlways ? substituteDigits(std::move(string)) : std::move(string);
302 if (zero.isEmpty()) {
304
305
306
307
308
309
311 if (getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
314 zero = QString::fromWCharArray(digits, 1);
317 return nullIfEmpty(zero);
322 return nullIfEmpty(getLocaleInfo(LOCALE_SDECIMAL).toString());
328 wchar_t grouping[10];
330
331
332
333
334
335
336
337 int dataSize = getLocaleInfo(LOCALE_SGROUPING, grouping,
int(std::size(grouping)));
340 auto tokenized = QStringView{grouping, dataSize}.tokenize(u';');
341 int width[2] = {0, 0};
343 for (
const auto tok : tokenized) {
345 int value = tok.toInt(&ok);
346 if (!ok || !value || index >= 2)
348 width[index++] = value;
361 return QVariant::fromValue(sizes);
366 return getLocaleInfo(LOCALE_STHOUSAND);
371 return nullIfEmpty(getLocaleInfo(LOCALE_SNEGATIVESIGN).toString());
376 return nullIfEmpty(getLocaleInfo(LOCALE_SPOSITIVESIGN).toString());
382 case QLocale::ShortFormat:
383 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE).toString()));
384 case QLocale::LongFormat:
385 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE).toString()));
386 case QLocale::NarrowFormat:
395 case QLocale::ShortFormat:
397 case QLocale::LongFormat:
398 return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT).toString()));
399 case QLocale::NarrowFormat:
407 QVariant d = dateFormat(type), t = timeFormat(type);
408 if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString)
409 return QString(d.toString() + u' ' + t.toString());
415 if (day < 1 || day > 7)
418 static constexpr LCTYPE short_day_map[]
419 = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
420 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
421 LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 };
423 static constexpr LCTYPE long_day_map[]
424 = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2,
425 LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5,
426 LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 };
428 static constexpr LCTYPE narrow_day_map[]
434 return nullIfEmpty(getLocaleInfo(
435 (type == QLocale::LongFormat ? long_day_map
436 : type == QLocale::NarrowFormat ? narrow_day_map
437 : short_day_map)[day - 1]).toString());
442 static constexpr LCTYPE short_month_map[]
443 = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
444 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
445 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
446 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
448 static constexpr LCTYPE long_month_map[]
449 = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
450 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
451 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
452 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 };
454 if (month < 1 || month > 12)
458 return nullIfEmpty(getLocaleInfo(
459 (type == QLocale::LongFormat ? long_month_map : short_month_map)[month - 1]).toString());
474 const wchar_t *
const format = type == QLocale::LongFormat ? L"ddMMMM" : L"ddMMM";
476 if (getDateFormat(flags, &st, format, buf, 255) > 2) {
478 return nullIfEmpty(correctDigits(QString::fromWCharArray(buf + 2)));
494 Q_ASSERT(fakeYear >= 1970 && fakeYear <= 2400);
495 const bool matchTwo = year >= 0 && year % 100 == fakeYear % 100;
496 auto yearUsed = fourDigitYear(fakeYear);
497 QString sign(year < 0 ? 1 : 0, u'-');
498 auto trueYear = fourDigitYear(year < 0 ? -year : year);
499 if (formatted.contains(yearUsed))
500 return std::move(formatted).replace(yearUsed, sign + trueYear);
502 auto tail = QStringView{yearUsed}.last(2);
503 Q_ASSERT(!matchTwo || tail == QString(sign + trueYear.last(2)));
504 if (formatted.contains(tail)) {
506 return std::move(formatted);
507 return std::move(formatted).replace(tail.toString(), sign + trueYear.last(2));
512 trueYear = substituteDigits(std::move(trueYear));
514 yearUsed = substituteDigits(std::move(yearUsed));
516 sign = negativeSign().toString();
518 if (formatted.contains(yearUsed))
519 return std::move(formatted).replace(yearUsed, sign + trueYear);
521 const qsizetype twoDigits = 2 * zero.size();
522 tail = QStringView{yearUsed}.last(twoDigits);
523 if (formatted.contains(tail)) {
525 return std::move(formatted);
526 return std::move(formatted).replace(tail.toString(), sign + trueYear.last(twoDigits));
529 qWarning(
"Failed to fix up year in formatted date-string using %d for %d", fakeYear, year);
530 return std::move(formatted);
536 const int year = date.year();
539 const bool fixup = year < 1601;
540 st.wYear = fixup ? QGregorianCalendar::yearSharingWeekDays(date) : year;
541 st.wMonth = date.month();
542 st.wDay = date.day();
544 Q_ASSERT(!fixup || st.wYear % 100 != st.wMonth);
545 Q_ASSERT(!fixup || st.wYear % 100 != st.wDay);
549 DWORD flags = (type == QLocale::LongFormat ? DATE_LONGDATE : DATE_SHORTDATE);
551 if (getDateFormat(flags, &st, NULL, buf, 255)) {
552 QString text = QString::fromWCharArray(buf);
554 text = yearFix(year, st.wYear, std::move(text));
555 return nullIfEmpty(correctDigits(std::move(text)));
563 st.wHour = time.hour();
564 st.wMinute = time.minute();
565 st.wSecond = time.second();
566 st.wMilliseconds = 0;
570 const QString format = type == QLocale::ShortFormat
573 auto formatStr =
reinterpret_cast<
const wchar_t *>(format.isEmpty() ?
nullptr : format.utf16());
576 if (getTimeFormat(flags, &st, formatStr, buf,
int(std::size(buf))))
577 return nullIfEmpty(correctDigits(QString::fromWCharArray(buf)));
583 QVariant d = toString(dt.date(), type), t = toString(dt.time(), type);
584 if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString)
585 return QString(d.toString() + u' ' + t.toString());
593 if (getLocaleInfo(LOCALE_IMEASURE, output, 2)) {
594 if (output[0] == L'1' && !output[1])
595 return QLocale::ImperialSystem;
598 return QLocale::MetricSystem;
603 return getLocaleInfo(LOCALE_SSORTLOCALE);
610 if (getLocaleInfo(LOCALE_S1159, output, 15))
611 return nullIfEmpty(QString::fromWCharArray(output));
620 if (getLocaleInfo(LOCALE_S2359, output, 15))
621 return nullIfEmpty(QString::fromWCharArray(output));
630 if (getLocaleInfo(LOCALE_IFIRSTDAYOFWEEK, output, 4))
631 return QString::fromWCharArray(output).toUInt()+1;
640 case QLocale::CurrencySymbol:
643 if (getLocaleInfo(LOCALE_SCURRENCY, buf, 13))
644 return nullIfEmpty(QString::fromWCharArray(buf));
646 case QLocale::CurrencyIsoCode:
647 if (getLocaleInfo(LOCALE_SINTLSYMBOL, buf, 9))
648 return nullIfEmpty(QString::fromWCharArray(buf));
650 case QLocale::CurrencyDisplayName: {
651 QVarLengthArray<
wchar_t, 64> buf(64);
652 if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) {
653 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
656 if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size()))
659 return nullIfEmpty(QString::fromWCharArray(buf.data()));
670 switch (arg.value.typeId()) {
672 value = QLocaleData::c()->longLongToString(
673 arg.value.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
675 case QMetaType::UInt:
676 value = QLocaleData::c()->unsLongLongToString(
677 arg.value.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
679 case QMetaType::Double:
680 value = QLocaleData::c()->doubleToString(
681 arg.value.toDouble(), -1, QLocaleData::DFDecimal, -1, QLocale::OmitGroupSeparator);
683 case QMetaType::LongLong:
684 value = QLocaleData::c()->longLongToString(
685 arg.value.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
687 case QMetaType::ULongLong:
688 value = QLocaleData::c()->unsLongLongToString(
689 arg.value.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
695 QVarLengthArray<
wchar_t, 64> out(64);
700 CURRENCYFMT *pformat = NULL;
701 if (!arg.symbol.isEmpty()) {
702 format.NumDigits = getLocaleInfo_int(LOCALE_ICURRDIGITS);
703 format.LeadingZero = getLocaleInfo_int(LOCALE_ILZERO);
704 decimalSep = getLocaleInfo(LOCALE_SMONDECIMALSEP).toString();
705 format.lpDecimalSep =
reinterpret_cast<
wchar_t *>(decimalSep.data());
706 thousandSep = getLocaleInfo(LOCALE_SMONTHOUSANDSEP).toString();
707 format.lpThousandSep =
reinterpret_cast<
wchar_t *>(thousandSep.data());
708 format.NegativeOrder = getLocaleInfo_int(LOCALE_INEGCURR);
709 format.PositiveOrder = getLocaleInfo_int(LOCALE_ICURRENCY);
710 format.lpCurrencySymbol = (
wchar_t *)arg.symbol.utf16();
718 QString groupingStr = getLocaleInfo(LOCALE_SMONGROUPING).toString();
719 format.Grouping = groupingStr.remove(u';').toInt();
720 if (format.Grouping % 10 == 0)
721 format.Grouping /= 10;
723 format.Grouping *= 10;
727 int ret = getCurrencyFormat(0,
reinterpret_cast<
const wchar_t *>(value.utf16()),
728 pformat, out.data(), out.size());
729 if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
730 ret = getCurrencyFormat(0,
reinterpret_cast<
const wchar_t *>(value.utf16()),
731 pformat, out.data(), 0);
733 getCurrencyFormat(0,
reinterpret_cast<
const wchar_t *>(value.utf16()),
734 pformat, out.data(), out.size());
737 return nullIfEmpty(correctDigits(QString::fromWCharArray(out.data())));
743#if QT_CONFIG(cpp_winrt)
744 using namespace winrt::Windows::System::UserProfile;
746 auto languages = GlobalizationPreferences::Languages();
747 for (
const auto &lang : languages)
748 result << QString::fromStdString(winrt::to_string(lang));
752 if (!result.isEmpty())
756 unsigned long cnt = 0;
757 QVarLengthArray<
wchar_t, 64> buf(64);
758# if !defined(QT_BOOTSTRAPPED)
759 unsigned long size = buf.size();
762 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
771 const wchar_t *str = buf.constData();
772 for (; cnt > 0; --cnt) {
773 QString s = QString::fromWCharArray(str);
779 return nullIfEmpty(
std::move(result));
795 lcid = getDefaultWinId();
796 substitutionType = SUnknown;
805 while (i < sys_fmt.size()) {
806 if (sys_fmt.at(i).unicode() == u'\'') {
807 QString text = qt_readEscapedFormatString(sys_fmt, &i);
811 result += u'\'' + text + u'\'';
815 QChar c = sys_fmt.at(i);
816 qsizetype repeat = qt_repeatCount(sys_fmt.mid(i));
818 switch (c.unicode()) {
823 else if (repeat == 3)
833 result += QString(repeat, u'y');
854 result += QString(repeat, c);
864QLocale QSystemLocale::fallbackLocale()
const
866 return QLocale(QString::fromLatin1(getWinLocaleName()));
869QVariant QSystemLocale::query(QueryType type, QVariant &&in)
const
871 QSystemLocalePrivate *d = systemLocalePrivate();
876 return d->decimalPoint();
878 return d->groupingSizes();
880 return d->groupSeparator();
882 return d->negativeSign();
884 return d->positiveSign();
886 return d->dateFormat(QLocale::LongFormat);
887 case DateFormatShort:
888 return d->dateFormat(QLocale::ShortFormat);
890 return d->timeFormat(QLocale::LongFormat);
891 case TimeFormatShort:
892 return d->timeFormat(QLocale::ShortFormat);
893 case DateTimeFormatLong:
894 return d->dateTimeFormat(QLocale::LongFormat);
895 case DateTimeFormatShort:
896 return d->dateTimeFormat(QLocale::ShortFormat);
898 return d->dayName(in.toInt(), QLocale::LongFormat);
900 return d->dayName(in.toInt(), QLocale::ShortFormat);
902 return d->dayName(in.toInt(), QLocale::NarrowFormat);
903 case StandaloneDayNameLong:
904 case StandaloneDayNameShort:
905 case StandaloneDayNameNarrow:
909 return d->monthName(in.toInt(), QLocale::LongFormat);
910 case StandaloneMonthNameLong:
911 return d->standaloneMonthName(in.toInt(), QLocale::LongFormat);
913 return d->monthName(in.toInt(), QLocale::ShortFormat);
914 case StandaloneMonthNameShort:
915 return d->standaloneMonthName(in.toInt(), QLocale::ShortFormat);
916 case MonthNameNarrow:
917 case StandaloneMonthNameNarrow:
920 case DateToStringShort:
921 return d->toString(in.toDate(), QLocale::ShortFormat);
922 case DateToStringLong:
923 return d->toString(in.toDate(), QLocale::LongFormat);
924 case TimeToStringShort:
925 return d->toString(in.toTime(), QLocale::ShortFormat);
926 case TimeToStringLong:
927 return d->toString(in.toTime(), QLocale::LongFormat);
928 case DateTimeToStringShort:
929 return d->toString(in.toDateTime(), QLocale::ShortFormat);
930 case DateTimeToStringLong:
931 return d->toString(in.toDateTime(), QLocale::LongFormat);
933 return d->zeroDigit();
937 QLocaleId lid = QLocaleId::fromName(QString::fromLatin1(getWinLocaleName()));
938 if (type == LanguageId)
939 return lid.language_id;
940 if (type == ScriptId)
941 return lid.script_id ? lid.script_id : ushort(fallbackLocale().script());
942 return lid.territory_id ? lid.territory_id : ushort(fallbackLocale().territory());
944 case MeasurementSystem:
945 return d->measurementSystem();
947 return d->collation();
953 return d->firstDayOfWeek();
955 return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
956 case CurrencyToString:
957 return d->toCurrencyString(in.value<CurrencyToStringArgument>());
959 return d->uiLanguages();
963 case NativeLanguageName:
964 return d->nativeLanguageName();
965 case NativeTerritoryName:
966 return d->nativeTerritoryName();
980struct ByWindowsCode {
1013 { 0x0416,
"pt_BR" },
1037 { 0x0801,
"ar_IQ" },
1038 { 0x0804,
"zh_CN" },
1039 { 0x0807,
"de_CH" },
1040 { 0x0809,
"en_GB" },
1041 { 0x080a,
"es_MX" },
1042 { 0x080c,
"fr_BE" },
1043 { 0x0810,
"it_CH" },
1045 { 0x0813,
"nl_BE" },
1050 { 0x081d,
"sv_FI" },
1051 { 0x0c01,
"ar_EG" },
1052 { 0x0c04,
"zh_HK" },
1053 { 0x0c07,
"de_AT" },
1054 { 0x0c09,
"en_AU" },
1056 { 0x0c0c,
"fr_CA" },
1058 { 0x1001,
"ar_LY" },
1059 { 0x1004,
"zh_SG" },
1060 { 0x1007,
"de_LU" },
1061 { 0x1009,
"en_CA" },
1062 { 0x100a,
"es_GT" },
1063 { 0x100c,
"fr_CH" },
1064 { 0x1401,
"ar_DZ" },
1065 { 0x1407,
"de_LI" },
1066 { 0x1409,
"en_NZ" },
1067 { 0x140a,
"es_CR" },
1068 { 0x140c,
"fr_LU" },
1069 { 0x1801,
"ar_MA" },
1070 { 0x1809,
"en_IE" },
1071 { 0x180a,
"es_PA" },
1072 { 0x1c01,
"ar_TN" },
1073 { 0x1c09,
"en_ZA" },
1074 { 0x1c0a,
"es_DO" },
1075 { 0x2001,
"ar_OM" },
1076 { 0x2009,
"en_JM" },
1077 { 0x200a,
"es_VE" },
1078 { 0x2401,
"ar_YE" },
1080 { 0x240a,
"es_CO" },
1081 { 0x2801,
"ar_SY" },
1082 { 0x2809,
"en_BZ" },
1083 { 0x280a,
"es_PE" },
1084 { 0x2c01,
"ar_JO" },
1085 { 0x2c09,
"en_TT" },
1086 { 0x2c0a,
"es_AR" },
1087 { 0x3001,
"ar_LB" },
1088 { 0x300a,
"es_EC" },
1089 { 0x3401,
"ar_KW" },
1090 { 0x340a,
"es_CL" },
1091 { 0x3801,
"ar_AE" },
1092 { 0x380a,
"es_UY" },
1093 { 0x3c01,
"ar_BH" },
1094 { 0x3c0a,
"es_PY" },
1095 { 0x4001,
"ar_QA" },
1096 { 0x400a,
"es_BO" },
1097 { 0x440a,
"es_SV" },
1098 { 0x480a,
"es_HN" },
1099 { 0x4c0a,
"es_NI" },
1120 return it->iso_name;
1129 return LOCALE_USER_DEFAULT;
1130 if (std::strlen(name) >=
sizeof(WindowsToISOListElt::iso_name))
1131 return LOCALE_USER_DEFAULT;
1136 strncpy(n, name,
sizeof(n));
1148 return LOCALE_USER_DEFAULT;
1160 if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255))
1161 lang_code = QString::fromWCharArray(out);
1163 if (!lang_code.isEmpty()) {
1164 const QByteArray latin1 =
std::move(lang_code).toLatin1();
1165 const auto [i, used] = qstrntoull(latin1.data(), latin1.size(), 16);
1166 if (used >= latin1.size() || (used > 0 && latin1[used] ==
'\0')) {
1177 if (!result.isEmpty())
1181 if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME, out, 255))
1182 result = QString::fromWCharArray(out);
1192 if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255))
1193 result = QString::fromWCharArray(out);
1200 if (id == LOCALE_USER_DEFAULT) {
1201 const auto [name, lcid] = scanLangEnv();
1202 if (!name.isEmpty())
1205 return winLangCodeToIsoName(lcid);
1207 id = GetUserDefaultLCID();
1210 QString resultusage = winIso639LangName(id);
1211 QString country = winIso3116CtryName(id);
1212 if (!country.isEmpty())
1213 resultusage += u'_' + country;
1215 return std::move(resultusage).toLatin1();
1221 return QLocale(QString::fromLatin1(getWinLocaleName(id)));
1226static QString localeConvertString(
const QString &localeID,
const QString &str,
bool *ok,
1230 LCID lcid = LocaleNameToLCID(
reinterpret_cast<
const wchar_t *>(localeID.constData()), 0);
1232 const int size = LCMapStringW(lcid, flags,
reinterpret_cast<
const wchar_t *>(str.constData()),
1234 QString buf(size, Qt::Uninitialized);
1235 if (lcid == 0 || size == 0
1236 || LCMapStringW(lcid, flags,
reinterpret_cast<
const wchar_t *>(str.constData()), str.size(),
1237 reinterpret_cast<
wchar_t *>(buf.data()), buf.size()) == 0) {
1247QString QLocalePrivate::toLower(
const QString &str,
bool *ok)
const
1249 return localeConvertString(QString::fromUtf8(bcp47Name()), str, ok,
1250 LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING);
1253QString QLocalePrivate::toUpper(
const QString &str,
bool *ok)
const
1255 return localeConvertString(QString::fromUtf8(bcp47Name()), str, ok,
1256 LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING);
Combined button and popup list for selecting options.
LCID qt_inIsoNametoLCID(const char *name)
static constexpr WindowsToISOListElt windows_to_iso_list[]
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
#define LOCALE_SSHORTESTDAYNAME5
#define LOCALE_SNATIVELANGUAGENAME
static QString winIso3116CtryName(LCID id)
#define LOCALE_SSHORTESTDAYNAME6
#define LOCALE_SNATIVECOUNTRYNAME
static auto getDefaultWinId()
#define MUI_LANGUAGE_NAME
static const char * winLangCodeToIsoName(int code)
#define LOCALE_SSHORTESTDAYNAME1
static QString winIso639LangName(LCID id)
#define QStringLiteral(str)
QVariant dateFormat(QLocale::FormatType)
QVariant toString(QDate, QLocale::FormatType)
QVariant dayName(int, QLocale::FormatType)
QVariant firstDayOfWeek()
QVariant monthName(int, QLocale::FormatType)
QVariant currencySymbol(QLocale::CurrencySymbolFormat)
QVariant nativeLanguageName()
QVariant toString(QTime, QLocale::FormatType)
QVariant standaloneMonthName(int, QLocale::FormatType)
QVariant nativeTerritoryName()
QVariant dateTimeFormat(QLocale::FormatType)
QVariant toString(const QDateTime &, QLocale::FormatType)
QVariant measurementSystem()
QVariant groupSeparator()
QVariant timeFormat(QLocale::FormatType)
QVariant toCurrencyString(const QSystemLocale::CurrencyToStringArgument &)