summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qlocale_win.cpp
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2024-01-17 18:45:07 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2024-01-19 15:38:25 +0100
commitfcd2a219c4c222309152f1ea2a3124ddc17d4ea5 (patch)
tree5004cd0541294a6af6046acc7cf8e4df8d009ea3 /src/corelib/text/qlocale_win.cpp
parentcfc385ce3fc674d48ea2bfbaac6d3f907795b1a5 (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.cpp61
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())