diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2024-01-17 18:45:07 +0100 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2024-01-19 15:38:25 +0100 |
commit | fcd2a219c4c222309152f1ea2a3124ddc17d4ea5 (patch) | |
tree | 5004cd0541294a6af6046acc7cf8e4df8d009ea3 /src/corelib/text/qlocale_win.cpp | |
parent | cfc385ce3fc674d48ea2bfbaac6d3f907795b1a5 (diff) |
Make QLocale self-consistent on Windows
The constructor and update() method for the system locale were using
GetUserDefaultLCID(), where query() and the fallback locale first
checked the LANG environment variable, leading to inconsistent results
if the user set the environment variable to something different from
the system's configured locale.
Break out the logic of parsing %LANG% into a static helper, replace
the existing parsing with a call to this and add a helper to get the
right ID to use, possibly via it, using GetUserDefaultLCID() as
fall-back. Drive-by: initialize substititionType in its declaration.
Also look up %LANG% each time we want it; it's not that expensive,
given how rarely this code is called, and client code could change its
value at runtime. Partially inspired by a patch from Wladimir
Leuschner <wladimir.leuschner@qt.io>
Pick-to: 6.5 6.6 6.7
Fixes: QTBUG-120961
Change-Id: Ie706c7089bd2b3757a3eab627723ec34a5e2b07f
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/text/qlocale_win.cpp')
-rw-r--r-- | src/corelib/text/qlocale_win.cpp | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp index 0cd6249b7f..89779bcd2f 100644 --- a/src/corelib/text/qlocale_win.cpp +++ b/src/corelib/text/qlocale_win.cpp @@ -31,6 +31,41 @@ 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); @@ -111,7 +146,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); @@ -133,9 +168,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) @@ -720,7 +754,7 @@ QVariant QSystemLocalePrivate::nativeTerritoryName() void QSystemLocalePrivate::update() { - lcid = GetUserDefaultLCID(); + lcid = getDefaultWinId(); substitutionType = SUnknown; zero.resize(0); } @@ -1123,20 +1157,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)))) { - // See if we have a Windows locale code instead of a locale name: - auto [id, used] = qstrntoll(result.data(), result.size(), 0); - if (used <= 0 || 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()) |