diff options
Diffstat (limited to 'src/corelib/text/qlocale_win.cpp')
-rw-r--r-- | src/corelib/text/qlocale_win.cpp | 308 |
1 files changed, 174 insertions, 134 deletions
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp index f97d910451..9fdb46a4c9 100644 --- a/src/corelib/text/qlocale_win.cpp +++ b/src/corelib/text/qlocale_win.cpp @@ -12,32 +12,60 @@ #include "QtCore/private/qgregoriancalendar_p.h" // for yearSharingWeekDays() -#ifdef Q_OS_WIN -# include <qt_windows.h> -# include <time.h> -#endif +#include <q20algorithm.h> + +// TODO QTBUG-121193: port away from the use of LCID to always use names. +#include <qt_windows.h> +#include <time.h> + +#if QT_CONFIG(cpp_winrt) +# include <QtCore/private/qt_winrtbase_p.h> -#if QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG) -# include <winrt/base.h> -// Workaround for Windows SDK bug. -// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47 -namespace winrt::impl -{ - template <typename Async> - auto wait_for(Async const& async, Windows::Foundation::TimeSpan const& timeout); -} # include <winrt/Windows.Foundation.h> # include <winrt/Windows.Foundation.Collections.h> # include <winrt/Windows.System.UserProfile.h> -#endif // QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG) +#endif // QT_CONFIG(cpp_winrt) QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +// Shared interpretation of %LANG% +static auto scanLangEnv() +{ + struct R + { + QByteArray name; // empty means unknown; lookup from id may work + LCID id = 0; // 0 means unknown; lookup from name may work + } result; + const QByteArray lang = qgetenv("LANG"); + if (lang.size() && (lang == "C" || qt_splitLocaleName(QString::fromLocal8Bit(lang)))) { + // See if we have a Windows locale code instead of a locale name: + const auto [id, used] = qstrntoll(lang.data(), lang.size(), 0); + if (used > 0 && id && INT_MIN <= id && id <= INT_MAX) + return R {QByteArray(), static_cast<LCID>(id)}; + return R {lang, 0}; + } + return R{}; +} + +static auto getDefaultWinId() +{ + const auto [name, id] = scanLangEnv(); + if (id) + return id; + + if (!name.isEmpty()) { + LCID id = LocaleNameToLCID(static_cast<LPCWSTR>( + QString::fromUtf8(name).toStdWString().data()), 0); + if (id) + return id; + } + + return GetUserDefaultLCID(); +} + static QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT); -static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT); -static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT); #ifndef QT_NO_SYSTEMLOCALE @@ -63,6 +91,17 @@ static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT); # define LOCALE_SSHORTTIME 0x00000079 #endif +namespace { +template <typename T> +static QVariant nullIfEmpty(T &&value) +{ + // For use where we should fall back to CLDR if we got an empty value. + if (value.isEmpty()) + return {}; + return std::move(value); +} +} + struct QSystemLocalePrivate { QSystemLocalePrivate(); @@ -104,7 +143,7 @@ private: // cached values: LCID lcid; - SubstitutionType substitutionType; + SubstitutionType substitutionType = SUnknown; QString zero; // cached value for zeroDigit() int getLocaleInfo(LCTYPE type, LPWSTR data, int size); @@ -117,6 +156,7 @@ private: SubstitutionType substitution(); QString substituteDigits(QString &&string); + QString correctDigits(QString &&string); QString yearFix(int year, int fakeYear, QString &&formatted); static QString winToQtFormat(QStringView sys_fmt); @@ -125,9 +165,8 @@ private: Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate) QSystemLocalePrivate::QSystemLocalePrivate() - : substitutionType(SUnknown) + : lcid(getDefaultWinId()) { - lcid = GetUserDefaultLCID(); } inline int QSystemLocalePrivate::getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size) @@ -179,10 +218,11 @@ QVariant QSystemLocalePrivate::getLocaleInfo(LCTYPE type) int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type) { - const QString str = getLocaleInfo(type).toString(); - bool ok = false; - const int v = str.toInt(&ok); - return ok ? v : 0; + DWORD value; + int r = GetLocaleInfo(lcid, type | LOCALE_RETURN_NUMBER, + reinterpret_cast<wchar_t *>(&value), + sizeof(value) / sizeof(wchar_t)); + return r == sizeof(value) / sizeof(wchar_t) ? value : 0; } QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution() @@ -190,25 +230,25 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution() if (substitutionType == SUnknown) { wchar_t buf[8]; if (!getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, buf, 8)) { - substitutionType = QSystemLocalePrivate::SNever; + substitutionType = SNever; return substitutionType; } if (buf[0] == '1') - substitutionType = QSystemLocalePrivate::SNever; + substitutionType = SNever; else if (buf[0] == '0') - substitutionType = QSystemLocalePrivate::SContext; + substitutionType = SContext; else if (buf[0] == '2') - substitutionType = QSystemLocalePrivate::SAlways; + substitutionType = SAlways; else { wchar_t digits[11]; // See zeroDigit() for why 11. if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) { - substitutionType = QSystemLocalePrivate::SNever; + substitutionType = SNever; return substitutionType; } if (buf[0] == digits[0] + 2) - substitutionType = QSystemLocalePrivate::SAlways; + substitutionType = SAlways; else - substitutionType = QSystemLocalePrivate::SNever; + substitutionType = SNever; } } return substitutionType; @@ -224,7 +264,7 @@ QString QSystemLocalePrivate::substituteDigits(QString &&string) break; Q_ASSERT(z > '9'); ushort *const qch = reinterpret_cast<ushort *>(string.data()); - for (int i = 0, stop = string.size(); i < stop; ++i) { + for (qsizetype i = 0, stop = string.size(); i < stop; ++i) { ushort &ch = qch[i]; if (ch >= '0' && ch <= '9') ch = unicodeForDigit(ch - '0', z); @@ -249,6 +289,11 @@ QString QSystemLocalePrivate::substituteDigits(QString &&string) return std::move(string); } +QString QSystemLocalePrivate::correctDigits(QString &&string) +{ + return substitution() == SAlways ? substituteDigits(std::move(string)) : std::move(string); +} + QVariant QSystemLocalePrivate::zeroDigit() { if (zero.isEmpty()) { @@ -266,36 +311,36 @@ QVariant QSystemLocalePrivate::zeroDigit() zero = QString::fromWCharArray(digits, 1); } } - return zero; + return nullIfEmpty(zero); // Do not std::move(). } QVariant QSystemLocalePrivate::decimalPoint() { - return getLocaleInfo(LOCALE_SDECIMAL); + return nullIfEmpty(getLocaleInfo(LOCALE_SDECIMAL).toString()); } QVariant QSystemLocalePrivate::groupSeparator() { - return getLocaleInfo(LOCALE_STHOUSAND); + return getLocaleInfo(LOCALE_STHOUSAND); // Empty means don't group digits. } QVariant QSystemLocalePrivate::negativeSign() { - return getLocaleInfo(LOCALE_SNEGATIVESIGN); + return nullIfEmpty(getLocaleInfo(LOCALE_SNEGATIVESIGN).toString()); } QVariant QSystemLocalePrivate::positiveSign() { - return getLocaleInfo(LOCALE_SPOSITIVESIGN); + return nullIfEmpty(getLocaleInfo(LOCALE_SPOSITIVESIGN).toString()); } QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type) { switch (type) { case QLocale::ShortFormat: - return winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE).toString()); + return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE).toString())); case QLocale::LongFormat: - return winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE).toString()); + return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE).toString())); case QLocale::NarrowFormat: break; } @@ -306,9 +351,9 @@ QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type) { switch (type) { case QLocale::ShortFormat: - return winToQtFormat(getLocaleInfo(LOCALE_SSHORTTIME).toString()); + return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTTIME).toString())); case QLocale::LongFormat: - return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT).toString()); + return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT).toString())); case QLocale::NarrowFormat: break; } @@ -317,48 +362,48 @@ QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type) QVariant QSystemLocalePrivate::dateTimeFormat(QLocale::FormatType type) { - return QString(dateFormat(type).toString() + u' ' + timeFormat(type).toString()); + QVariant d = dateFormat(type), t = timeFormat(type); + if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString) + return QString(d.toString() + u' ' + t.toString()); + return {}; } QVariant QSystemLocalePrivate::dayName(int day, QLocale::FormatType type) { if (day < 1 || day > 7) - return QString(); + return {}; - static const LCTYPE short_day_map[] + static constexpr LCTYPE short_day_map[] = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 }; - static const LCTYPE long_day_map[] + static constexpr LCTYPE long_day_map[] = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 }; - static const LCTYPE narrow_day_map[] + static constexpr LCTYPE narrow_day_map[] = { LOCALE_SSHORTESTDAYNAME1, LOCALE_SSHORTESTDAYNAME2, LOCALE_SSHORTESTDAYNAME3, LOCALE_SSHORTESTDAYNAME4, LOCALE_SSHORTESTDAYNAME5, LOCALE_SSHORTESTDAYNAME6, LOCALE_SSHORTESTDAYNAME7 }; - day -= 1; - - if (type == QLocale::LongFormat) - return getLocaleInfo(long_day_map[day]); - if (type == QLocale::NarrowFormat) - return getLocaleInfo(narrow_day_map[day]); - return getLocaleInfo(short_day_map[day]); + return nullIfEmpty(getLocaleInfo( + (type == QLocale::LongFormat ? long_day_map + : type == QLocale::NarrowFormat ? narrow_day_map + : short_day_map)[day - 1]).toString()); } QVariant QSystemLocalePrivate::standaloneMonthName(int month, QLocale::FormatType type) { - static const LCTYPE short_month_map[] + static constexpr LCTYPE short_month_map[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 }; - static const LCTYPE long_month_map[] + static constexpr LCTYPE long_month_map[] = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, @@ -368,8 +413,8 @@ QVariant QSystemLocalePrivate::standaloneMonthName(int month, QLocale::FormatTyp return {}; // Month is Jan = 1, ... Dec = 12; adjust by 1 to match array indexing from 0: - return getLocaleInfo( - (type == QLocale::LongFormat ? long_month_map : short_month_map)[month - 1]); + return nullIfEmpty(getLocaleInfo( + (type == QLocale::LongFormat ? long_month_map : short_month_map)[month - 1]).toString()); } QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type) @@ -388,10 +433,7 @@ QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type) wchar_t buf[255]; if (getDateFormat(flags, &st, format, buf, 255) > 2) { // Elide the two digits of day number - QString text = QString::fromWCharArray(buf + 2); - if (substitution() == SAlways) - text = substituteDigits(std::move(text)); - return text; + return nullIfEmpty(correctDigits(QString::fromWCharArray(buf + 2))); } return {}; } @@ -423,7 +465,7 @@ QString QSystemLocalePrivate::yearFix(int year, int fakeYear, QString &&formatte return std::move(formatted).replace(tail.toString(), sign + trueYear.last(2)); } - // Localized digits, perhaps ? + // Localized digits (regardless of SAlways), perhaps ? // First call to substituteDigits() ensures zero is initialized: trueYear = substituteDigits(std::move(trueYear)); if (zero != u'0') { @@ -434,7 +476,7 @@ QString QSystemLocalePrivate::yearFix(int year, int fakeYear, QString &&formatte if (formatted.contains(yearUsed)) return std::move(formatted).replace(yearUsed, sign + trueYear); - const int twoDigits = 2 * zero.size(); + const qsizetype twoDigits = 2 * zero.size(); tail = QStringView{yearUsed}.last(twoDigits); if (formatted.contains(tail)) { if (matchTwo) @@ -468,9 +510,7 @@ QVariant QSystemLocalePrivate::toString(QDate date, QLocale::FormatType type) QString text = QString::fromWCharArray(buf); if (fixup) text = yearFix(year, st.wYear, std::move(text)); - if (substitution() == SAlways) - text = substituteDigits(std::move(text)); - return text; + return nullIfEmpty(correctDigits(std::move(text))); } return {}; } @@ -485,23 +525,23 @@ QVariant QSystemLocalePrivate::toString(QTime time, QLocale::FormatType type) DWORD flags = 0; // keep the same conditional as timeFormat() above - if (type == QLocale::ShortFormat) - flags = TIME_NOSECONDS; + const QString format = type == QLocale::ShortFormat + ? getLocaleInfo(LOCALE_SSHORTTIME).toString() + : QString(); + auto formatStr = reinterpret_cast<const wchar_t *>(format.isEmpty() ? nullptr : format.utf16()); wchar_t buf[255]; - if (getTimeFormat(flags, &st, NULL, buf, 255)) { - QString text = QString::fromWCharArray(buf); - if (substitution() == SAlways) - text = substituteDigits(std::move(text)); - return text; - } + if (getTimeFormat(flags, &st, formatStr, buf, int(std::size(buf)))) + return nullIfEmpty(correctDigits(QString::fromWCharArray(buf))); return {}; } QVariant QSystemLocalePrivate::toString(const QDateTime &dt, QLocale::FormatType type) { - return QString(toString(dt.date(), type).toString() + u' ' - + toString(dt.time(), type).toString()); + QVariant d = toString(dt.date(), type), t = toString(dt.time(), type); + if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString) + return QString(d.toString() + u' ' + t.toString()); + return {}; } QVariant QSystemLocalePrivate::measurementSystem() @@ -526,7 +566,7 @@ QVariant QSystemLocalePrivate::amText() wchar_t output[15]; // maximum length including terminating zero character for Win2003+ if (getLocaleInfo(LOCALE_S1159, output, 15)) - return QString::fromWCharArray(output); + return nullIfEmpty(QString::fromWCharArray(output)); return QVariant(); } @@ -536,7 +576,7 @@ QVariant QSystemLocalePrivate::pmText() wchar_t output[15]; // maximum length including terminating zero character for Win2003+ if (getLocaleInfo(LOCALE_S2359, output, 15)) - return QString::fromWCharArray(output); + return nullIfEmpty(QString::fromWCharArray(output)); return QVariant(); } @@ -556,12 +596,14 @@ QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat form wchar_t buf[13]; switch (format) { case QLocale::CurrencySymbol: + // Some locales do have empty currency symbol. All the same, fall back + // to CLDR for confirmation if MS claims that applies. if (getLocaleInfo(LOCALE_SCURRENCY, buf, 13)) - return QString::fromWCharArray(buf); + return nullIfEmpty(QString::fromWCharArray(buf)); break; case QLocale::CurrencyIsoCode: if (getLocaleInfo(LOCALE_SINTLSYMBOL, buf, 9)) - return QString::fromWCharArray(buf); + return nullIfEmpty(QString::fromWCharArray(buf)); break; case QLocale::CurrencyDisplayName: { QVarLengthArray<wchar_t, 64> buf(64); @@ -572,7 +614,7 @@ QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat form if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) break; } - return QString::fromWCharArray(buf.data()); + return nullIfEmpty(QString::fromWCharArray(buf.data())); } default: break; @@ -650,24 +692,25 @@ QVariant QSystemLocalePrivate::toCurrencyString(const QSystemLocale::CurrencyToS pformat, out.data(), out.size()); } - value = QString::fromWCharArray(out.data()); - if (substitution() == SAlways) - value = substituteDigits(std::move(value)); - return value; + return nullIfEmpty(correctDigits(QString::fromWCharArray(out.data()))); } QVariant QSystemLocalePrivate::uiLanguages() { QStringList result; -#if QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG) +#if QT_CONFIG(cpp_winrt) using namespace winrt; using namespace Windows::System::UserProfile; - auto languages = GlobalizationPreferences::Languages(); - for (const auto &lang : languages) - result << QString::fromStdString(winrt::to_string(lang)); + QT_TRY { + auto languages = GlobalizationPreferences::Languages(); + for (const auto &lang : languages) + result << QString::fromStdString(winrt::to_string(lang)); + } QT_CATCH(...) { + // pass, just fall back to WIN32 API implementation + } if (!result.isEmpty()) return result; // else just fall back to WIN32 API implementation -#endif // QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG) +#endif // QT_CONFIG(cpp_winrt) // mingw and clang still have to use Win32 API unsigned long cnt = 0; QVarLengthArray<wchar_t, 64> buf(64); @@ -679,7 +722,7 @@ QVariant QSystemLocalePrivate::uiLanguages() GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) { buf.resize(size); if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) - return QStringList(); + return {}; } } # endif // !QT_BOOTSTRAPPED @@ -692,7 +735,7 @@ QVariant QSystemLocalePrivate::uiLanguages() result.append(s); str += s.size() + 1; } - return result; + return nullIfEmpty(std::move(result)); } QVariant QSystemLocalePrivate::nativeLanguageName() @@ -708,7 +751,7 @@ QVariant QSystemLocalePrivate::nativeTerritoryName() void QSystemLocalePrivate::update() { - lcid = GetUserDefaultLCID(); + lcid = getDefaultWinId(); substitutionType = SUnknown; zero.resize(0); } @@ -716,7 +759,7 @@ void QSystemLocalePrivate::update() QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt) { QString result; - int i = 0; + qsizetype i = 0; while (i < sys_fmt.size()) { if (sys_fmt.at(i).unicode() == u'\'') { @@ -729,7 +772,7 @@ QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt) } QChar c = sys_fmt.at(i); - int repeat = qt_repeatCount(sys_fmt.mid(i)); + qsizetype repeat = qt_repeatCount(sys_fmt.mid(i)); switch (c.unicode()) { // Date @@ -782,7 +825,7 @@ QLocale QSystemLocale::fallbackLocale() const return QLocale(QString::fromLatin1(getWinLocaleName())); } -QVariant QSystemLocale::query(QueryType type, QVariant in) const +QVariant QSystemLocale::query(QueryType type, QVariant &&in) const { QSystemLocalePrivate *d = systemLocalePrivate(); switch(type) { @@ -866,7 +909,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const case CurrencySymbol: return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())); case CurrencyToString: - return d->toCurrencyString(in.value<QSystemLocale::CurrencyToStringArgument>()); + return d->toCurrencyString(in.value<CurrencyToStringArgument>()); case UILanguages: return d->uiLanguages(); case LocaleChanged: @@ -888,8 +931,18 @@ struct WindowsToISOListElt { char iso_name[6]; }; -/* NOTE: This array should be sorted by the first column! */ -static const WindowsToISOListElt windows_to_iso_list[] = { +namespace { +struct ByWindowsCode { + constexpr bool operator()(int lhs, WindowsToISOListElt rhs) const noexcept + { return lhs < int(rhs.windows_code); } + constexpr bool operator()(WindowsToISOListElt lhs, int rhs) const noexcept + { return int(lhs.windows_code) < rhs; } + constexpr bool operator()(WindowsToISOListElt lhs, WindowsToISOListElt rhs) const noexcept + { return lhs.windows_code < rhs.windows_code; } +}; +} // unnamed namespace + +static constexpr WindowsToISOListElt windows_to_iso_list[] = { { 0x0401, "ar_SA" }, { 0x0402, "bg\0 " }, { 0x0403, "ca\0 " }, @@ -1000,40 +1053,33 @@ static const WindowsToISOListElt windows_to_iso_list[] = { { 0x500a, "es_PR" } }; -static const int windows_to_iso_count - = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt); +static_assert(q20::is_sorted(std::begin(windows_to_iso_list), std::end(windows_to_iso_list), + ByWindowsCode{})); static const char *winLangCodeToIsoName(int code) { int cmp = code - windows_to_iso_list[0].windows_code; if (cmp < 0) - return 0; + return nullptr; if (cmp == 0) return windows_to_iso_list[0].iso_name; - int begin = 0; - int end = windows_to_iso_count; - - while (end - begin > 1) { - uint mid = (begin + end)/2; - - const WindowsToISOListElt *elt = windows_to_iso_list + mid; - int cmp = code - elt->windows_code; - if (cmp < 0) - end = mid; - else if (cmp > 0) - begin = mid; - else - return elt->iso_name; - } + const auto it = std::lower_bound(std::begin(windows_to_iso_list), + std::end(windows_to_iso_list), + code, + ByWindowsCode{}); + if (it != std::end(windows_to_iso_list) && !ByWindowsCode{}(code, *it)) + return it->iso_name; - return 0; + return nullptr; } LCID qt_inIsoNametoLCID(const char *name) { + if (!name) + return LOCALE_USER_DEFAULT; // handle norwegian manually, the list above will fail if (!strncmp(name, "nb", 2)) return 0x0414; @@ -1070,11 +1116,9 @@ static QString winIso639LangName(LCID id) lang_code = QString::fromWCharArray(out); if (!lang_code.isEmpty()) { - const char *endptr; - bool ok; - QByteArray latin1_lang_code = std::move(lang_code).toLatin1(); - int i = qstrntoull(latin1_lang_code.data(), latin1_lang_code.size(), &endptr, 16, &ok); - if (ok && *endptr == '\0') { + const QByteArray latin1 = std::move(lang_code).toLatin1(); + const auto [i, used] = qstrntoull(latin1.data(), latin1.size(), 16); + if (used >= latin1.size() || (used > 0 && latin1[used] == '\0')) { switch (i) { case 0x814: result = u"nn"_s; // Nynorsk @@ -1110,20 +1154,15 @@ static QByteArray getWinLocaleName(LCID id) { QByteArray result; if (id == LOCALE_USER_DEFAULT) { - static const QByteArray langEnvVar = qgetenv("LANG"); - result = langEnvVar; - if (result == "C" - || (!result.isEmpty() && qt_splitLocaleName(QString::fromLocal8Bit(result)))) { - bool ok = false; // See if we have a Windows locale code instead of a locale name: - long id = qstrntoll(result.data(), result.size(), 0, 0, &ok); - if (!ok || id == 0 || id < INT_MIN || id > INT_MAX) // Assume real locale name - return result; - return winLangCodeToIsoName(int(id)); - } - } + const auto [name, lcid] = scanLangEnv(); + if (!name.isEmpty()) + return name; + if (lcid) + return winLangCodeToIsoName(lcid); - if (id == LOCALE_USER_DEFAULT) id = GetUserDefaultLCID(); + } + QString resultusage = winIso639LangName(id); QString country = winIso3116CtryName(id); if (!country.isEmpty()) @@ -1132,6 +1171,7 @@ static QByteArray getWinLocaleName(LCID id) return std::move(resultusage).toLatin1(); } +// Helper for plugins/platforms/windows/ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id) { return QLocale(QString::fromLatin1(getWinLocaleName(id))); |