From 0aba9fe11251d7ab9ebf3c0e6ef25f609f620079 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 27 Feb 2021 17:52:08 +0100 Subject: [PATCH 01/15] Remove useless fallback from wxLocale::Init() There is no need to try setting "loc.UTF-8" and "loc.UTF8" when we had just called wxSetlocaleTryUTF8() which tried these variants and also their lower-case equivalents already. --- src/common/intl.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index df38f5d8ee..906efdbae6 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -471,26 +471,6 @@ bool wxLocale::Init(int language, int flags) retloc = wxSetlocaleTryUTF8(LC_ALL, langOnly); } -#if wxUSE_FONTMAP - // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but - // require the full xx_YY.encoding form, so try using UTF-8 because this is - // the only thing we can do generically - // - // TODO: add encodings applicable to each language to the lang DB and try - // them all in turn here - if ( !retloc ) - { - const wxChar **names = - wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); - while ( *names ) - { - retloc = wxSetlocale(LC_ALL, locale + wxS('.') + *names++); - if ( retloc ) - break; - } - } -#endif // wxUSE_FONTMAP - if ( !retloc ) { // Some C libraries (namely glibc) still use old ISO 639, From 7b6894ea4133ecb089e2bc4bf90ab1b3806d3f01 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 01:02:59 +0100 Subject: [PATCH 02/15] Reuse Unix branch of wxLocale::Init() for macOS too There doesn't seem to be any reason to partially duplicate Unix-specific code in a separate Mac branch when we can just use the same code. Parts of it which are not necessary under Mac, such as trying ".UTF-8" locales in wxSetlocaleTryUTF8(), can be separately disabled there (even though they are harmless), but other parts are probably needed, e.g. setting Norwegian locale failed under macOS before because we didn't translate nb_NO that we use to no_NO actually supported under macOS. --- src/common/intl.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 906efdbae6..264ffeaf88 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -385,14 +385,16 @@ bool wxLocale::DoCommonPostInit(bool success, return success; } -#if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) +#if defined(__UNIX__) static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) { const char *l = NULL; // NB: We prefer to set UTF-8 locale if it's possible and only fall back to - // non-UTF-8 locale if it fails - + // non-UTF-8 locale if it fails, but this is not necessary under the + // supported macOS versions where xx_YY locales are just aliases to + // xx_YY.UTF-8 anyhow. +#if wxUSE_UNICODE && !defined(__WXMAC__) if ( !lc.empty() ) { wxString buf(lc); @@ -418,13 +420,12 @@ static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) // if we can't set UTF-8 locale, try non-UTF-8 one: if ( !l ) +#endif // wxUSE_UNICODE && !__WXMAC__ l = wxSetlocale(c, lc); return l; } -#else -#define wxSetlocaleTryUTF8(c, lc) wxSetlocale(c, lc) -#endif +#endif // __UNIX__ bool wxLocale::Init(int language, int flags) { @@ -459,7 +460,7 @@ bool wxLocale::Init(int language, int flags) DoInit(name, info->CanonicalName, lang); // Set the locale: -#if defined(__UNIX__) && !defined(__WXMAC__) +#if defined(__UNIX__) const wxString& locale = info->CanonicalName; const char *retloc = wxSetlocaleTryUTF8(LC_ALL, locale); @@ -552,16 +553,6 @@ bool wxLocale::Init(int language, int flags) } } #endif // CRT not handling Unicode-only languages -#elif defined(__WXMAC__) - const wxString& locale = info->CanonicalName; - - const char *retloc = wxSetlocale(LC_ALL, locale); - - if ( !retloc ) - { - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocale(LC_ALL, ExtractLang(locale)); - } #else wxUnusedVar(flags); return false; From 5fd85d422fca0502f09c3017d4961bb17ccdc9b0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 01:07:47 +0100 Subject: [PATCH 03/15] Add a trivial test for setting default locale Initializing wxLocale using wxLANGUAGE_DEFAULT should work, unless LC_ALL is explicitly set to an invalid value. --- tests/intl/intltest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/intl/intltest.cpp b/tests/intl/intltest.cpp index a7e90e71bb..4c6b473b71 100644 --- a/tests/intl/intltest.cpp +++ b/tests/intl/intltest.cpp @@ -226,4 +226,11 @@ void IntlTestCase::IsAvailable() CPPUNIT_ASSERT_EQUAL( origLocale, setlocale(LC_ALL, NULL) ); } +TEST_CASE("wxLocale::Default", "[locale]") +{ + wxLocale loc; + + REQUIRE( loc.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ); +} + #endif // wxUSE_INTL From d029279227bbe45515ef10a9f2eb86f229beecef Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 01:11:34 +0100 Subject: [PATCH 04/15] Rename local variable to a more consistent name Call the info->CanonicalName "shortName", as it's done in many other places in the code instead of using "locale" for it here, even though we do use it as a name of locale. No real changes. --- src/common/intl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 264ffeaf88..d9f4718c3e 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -461,11 +461,11 @@ bool wxLocale::Init(int language, int flags) // Set the locale: #if defined(__UNIX__) - const wxString& locale = info->CanonicalName; + const wxString& shortName = info->CanonicalName; const char *retloc = wxSetlocaleTryUTF8(LC_ALL, locale); - const wxString langOnly = ExtractLang(locale); + const wxString langOnly = ExtractLang(shortName); if ( !retloc ) { // Some C libraries don't like xx_YY form and require xx only @@ -478,11 +478,11 @@ bool wxLocale::Init(int language, int flags) // so will translate the abbrev for them wxString localeAlt; if ( langOnly == wxS("he") ) - localeAlt = wxS("iw") + ExtractNotLang(locale); + localeAlt = wxS("iw") + ExtractNotLang(shortName); else if ( langOnly == wxS("id") ) - localeAlt = wxS("in") + ExtractNotLang(locale); + localeAlt = wxS("in") + ExtractNotLang(shortName); else if ( langOnly == wxS("yi") ) - localeAlt = wxS("ji") + ExtractNotLang(locale); + localeAlt = wxS("ji") + ExtractNotLang(shortName); else if ( langOnly == wxS("nb") ) localeAlt = wxS("no_NO"); else if ( langOnly == wxS("nn") ) From 3e395f9b5f003d4077c00d095fc712f2934a1423 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 01:12:57 +0100 Subject: [PATCH 05/15] Micro optimization for wxLANGUAGE_UNKNOWN in GetLanguageInfo() Don't bother iterating over all the languages if we can be sure we're not going to find anything anyhow. --- src/common/intl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index d9f4718c3e..88ee2e0bfe 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -952,6 +952,9 @@ const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang) if ( lang == wxLANGUAGE_DEFAULT ) lang = GetSystemLanguage(); + if ( lang == wxLANGUAGE_UNKNOWN ) + return NULL; + const size_t count = ms_languagesDB->GetCount(); for ( size_t i = 0; i < count; i++ ) { From 18bf718f607ad0f11a5e4c5e48916d73c50a16a0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 20:00:27 +0100 Subject: [PATCH 06/15] Support wxLANGUAGE_DEFAULT in wxLocale even when it is unknown Don't give an error if we can't recognize the current system language, as we may still be able to use it even in this case. Closes #19082. --- src/common/intl.cpp | 59 ++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 88ee2e0bfe..cb76d6fedf 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -427,43 +427,44 @@ static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) } #endif // __UNIX__ -bool wxLocale::Init(int language, int flags) +bool wxLocale::Init(int lang, int flags) { #if WXWIN_COMPATIBILITY_2_8 wxASSERT_MSG( !(flags & wxLOCALE_CONV_ENCODING), wxS("wxLOCALE_CONV_ENCODING is no longer supported, add charset to your catalogs") ); #endif - int lang = language; - if (lang == wxLANGUAGE_DEFAULT) - { - // auto detect the language - lang = GetSystemLanguage(); - } - - // We failed to detect system language, so we will use English: - if (lang == wxLANGUAGE_UNKNOWN) - { - return false; - } + wxString name, shortName; const wxLanguageInfo *info = GetLanguageInfo(lang); // Unknown language: if (info == NULL) { - wxLogError(wxS("Unknown language %i."), lang); - return false; + // This could have happened because some concrete language has been + // requested and we just don't know anything about it. In this case, we + // have no choice but to simply give up. + if ( lang != wxLANGUAGE_DEFAULT ) + { + wxLogError(wxS("Unknown language %i."), lang); + return false; + } + + // However in case we didn't recognize the default system language, we + // can still try to use it, even though we don't know anything about it + // because setlocale() still might. + } + else + { + name = info->Description; + shortName = info->CanonicalName; } - const wxString& name = info->Description; - DoInit(name, info->CanonicalName, lang); + DoInit(name, shortName, lang); // Set the locale: #if defined(__UNIX__) - const wxString& shortName = info->CanonicalName; - - const char *retloc = wxSetlocaleTryUTF8(LC_ALL, locale); + const char *retloc = wxSetlocaleTryUTF8(LC_ALL, shortName); const wxString langOnly = ExtractLang(shortName); if ( !retloc ) @@ -510,11 +511,18 @@ bool wxLocale::Init(int language, int flags) #endif // __AIX__ #elif defined(__WIN32__) - const char *retloc = "C"; - if ( info->WinLang == 0 ) + const char *retloc; + if ( !info ) + { + // We're using the system language, but we don't know what it is, so + // just use setlocale() to deal with it. + retloc = wxSetlocale(LC_ALL, ""); + } + else if ( info->WinLang == 0 ) { wxLogWarning(wxS("Locale '%s' not supported by OS."), name); - // retloc already set to "C" + + retloc = "C"; } else // language supported by Windows { @@ -560,14 +568,11 @@ bool wxLocale::Init(int language, int flags) #endif #ifndef WX_NO_LOCALE_SUPPORT - // NB: don't use 'lang' here, 'language' return DoCommonPostInit ( retloc != NULL, name, - language == wxLANGUAGE_DEFAULT - ? wxString() - : info->CanonicalName, + shortName, flags & wxLOCALE_LOAD_DEFAULT ); #endif // !WX_NO_LOCALE_SUPPORT From 91ec90003430ad0f2ea93619a33990c6df5370fb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 20:04:33 +0100 Subject: [PATCH 07/15] Explicitly disallow wxLANGUAGE_UNKNOWN in wxLocale::Init() This value doesn't make here, so be upfront about it. --- interface/wx/intl.h | 8 +++++--- src/common/intl.cpp | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/wx/intl.h b/interface/wx/intl.h index 7d7b7b26f9..92902c1b7d 100644 --- a/interface/wx/intl.h +++ b/interface/wx/intl.h @@ -459,9 +459,11 @@ public: try to translate the messages using the message catalogs for this locale. @param language - ::wxLanguage identifier of the locale. - @c wxLANGUAGE_DEFAULT has special meaning -- wxLocale will use system's - default language (see GetSystemLanguage()). + ::wxLanguage identifier of the locale. It can be either some + concrete language, e.g. @c wxLANGUAGE_ESPERANTO, or a special value + @c wxLANGUAGE_DEFAULT which means that wxLocale should use system's + default language (see GetSystemLanguage()). Notice that the value + @c wxLANGUAGE_UNKNOWN is not allowed here. @param flags Combination of the following: - wxLOCALE_LOAD_DEFAULT: Load the message catalog for the given locale diff --git a/src/common/intl.cpp b/src/common/intl.cpp index cb76d6fedf..a9a6835f08 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -434,6 +434,10 @@ bool wxLocale::Init(int lang, int flags) wxS("wxLOCALE_CONV_ENCODING is no longer supported, add charset to your catalogs") ); #endif + wxCHECK_MSG( lang != wxLANGUAGE_UNKNOWN, false, + wxS("Initializing unknown locale doesn't make sense, did you ") + wxS("mean to use wxLANGUAGE_DEFAULT perhaps?") ); + wxString name, shortName; const wxLanguageInfo *info = GetLanguageInfo(lang); From 2e8e0197d7af9782936d97c8bcbcf0ea183664e1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 22:46:09 +0100 Subject: [PATCH 08/15] Add wxSetlocaleTryAll() helper to simplify Unix locale code Define the function calling setlocale("xx_YY") first and then just setlocale("xx") if the former failed, instead of doing the same thing manually in 3 different places. Also avoid attempting the second setlocale() call completely if there is no "_YY" part in the first place. No real changes. --- src/common/intl.cpp | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index a9a6835f08..86e2edb428 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -386,6 +386,9 @@ bool wxLocale::DoCommonPostInit(bool success, } #if defined(__UNIX__) + +// Helper of wxSetlocaleTryAll() below which tries setting the given locale +// with and without UTF-8 suffix. Don't use this one directly. static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) { const char *l = NULL; @@ -425,6 +428,22 @@ static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) return l; } + +// Try setting all possible versions of the given locale, i.e. with and without +// UTF-8 encoding, and with or without the "_territory" part. +static const char *wxSetlocaleTryAll(int c, const wxString& lc) +{ + const char* l = wxSetlocaleTryUTF8(c, lc); + if ( !l ) + { + const wxString& lcOnlyLang = ExtractLang(lc); + if ( lcOnlyLang != lc ) + l = wxSetlocaleTryUTF8(c, lcOnlyLang); + } + + return l; +} + #endif // __UNIX__ bool wxLocale::Init(int lang, int flags) @@ -468,20 +487,14 @@ bool wxLocale::Init(int lang, int flags) // Set the locale: #if defined(__UNIX__) - const char *retloc = wxSetlocaleTryUTF8(LC_ALL, shortName); - - const wxString langOnly = ExtractLang(shortName); - if ( !retloc ) - { - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocaleTryUTF8(LC_ALL, langOnly); - } + const char *retloc = wxSetlocaleTryAll(LC_ALL, shortName); if ( !retloc ) { // Some C libraries (namely glibc) still use old ISO 639, // so will translate the abbrev for them wxString localeAlt; + const wxString& langOnly = ExtractLang(shortName); if ( langOnly == wxS("he") ) localeAlt = wxS("iw") + ExtractNotLang(shortName); else if ( langOnly == wxS("id") ) @@ -494,11 +507,7 @@ bool wxLocale::Init(int lang, int flags) localeAlt = wxS("no_NY"); if ( !localeAlt.empty() ) - { - retloc = wxSetlocaleTryUTF8(LC_ALL, localeAlt); - if ( !retloc ) - retloc = wxSetlocaleTryUTF8(LC_ALL, ExtractLang(localeAlt)); - } + retloc = wxSetlocaleTryAll(LC_ALL, localeAlt); } #ifdef __AIX__ @@ -1096,11 +1105,7 @@ bool wxLocale::IsAvailable(int lang) // Test if setting the locale works, then set it back. char * const oldLocale = wxStrdupA(setlocale(LC_ALL, NULL)); - // Some platforms don't like xx_YY form and require xx only so test for - // it too. - const bool - available = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName) || - wxSetlocaleTryUTF8(LC_ALL, ExtractLang(info->CanonicalName)); + const bool available = wxSetlocaleTryAll(LC_ALL, info->CanonicalName); // restore the original locale wxSetlocale(LC_ALL, oldLocale); From 73b41dda9175bd06526364faa34a63a0c7dad815 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 22:50:35 +0100 Subject: [PATCH 09/15] Remove redundant #if/#endif in Unix locale code Put both Unix-only functions inside the same #ifdef __UNIX__. No real changes. --- src/common/intl.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 86e2edb428..c376c1dcaa 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -89,15 +89,12 @@ namespace { #if defined(__UNIX__) + // get just the language part ("en" in "en_GB") inline wxString ExtractLang(const wxString& langFull) { return langFull.BeforeFirst('_'); } -#endif - -// helper functions of GetSystemLanguage() -#ifdef __UNIX__ // get everything else (including the leading '_') inline wxString ExtractNotLang(const wxString& langFull) From d03f1937192ed20aee39a4b9a475849e3dab1a92 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2021 23:39:20 +0100 Subject: [PATCH 10/15] Recognize "ll_LL" as at language "ll" in GetSystemLanguage() If we can't find an exact match for the system locale in the database, try to at least find the corresponding language. This is almost certainly what the intention of the original code was, as otherwise the entire loop was useless because it couldn't find anything that wouldn't have been found in the loop just above. This allows to correctly load German translations when using unsupported locale such as "de_IT", for example. See #19082. --- src/common/intl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index c376c1dcaa..9598f0ec12 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -732,7 +732,7 @@ inline bool wxGetNonEmptyEnvVar(const wxString& name, wxString* value) { for ( i = 0; i < count; i++ ) { - if ( ms_languagesDB->Item(i).CanonicalName == lang ) + if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) == lang ) { break; } From b8f63fc7c51e27da9b9fbba44069c6d6a0ee87bf Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 1 Mar 2021 00:22:39 +0100 Subject: [PATCH 11/15] Skip wxLocale wxLANGUAGE_DEFAULT test in ANSI builds The test fails there, but we don't really care about it, Unicode is required for any level of acceptable locale support anyhow. --- tests/intl/intltest.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/intl/intltest.cpp b/tests/intl/intltest.cpp index 4c6b473b71..c19628b4c0 100644 --- a/tests/intl/intltest.cpp +++ b/tests/intl/intltest.cpp @@ -226,6 +226,10 @@ void IntlTestCase::IsAvailable() CPPUNIT_ASSERT_EQUAL( origLocale, setlocale(LC_ALL, NULL) ); } +// The test may fail in ANSI builds because of unsupported encoding, but we +// don't really care about this build anyhow, so just skip it there. +#if wxUSE_UNICODE + TEST_CASE("wxLocale::Default", "[locale]") { wxLocale loc; @@ -233,4 +237,6 @@ TEST_CASE("wxLocale::Default", "[locale]") REQUIRE( loc.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ); } +#endif // wxUSE_UNICODE + #endif // wxUSE_INTL From 9600c29ff2ca13ef66b76eabadaac5ec8654b792 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 2 Mar 2021 17:03:12 +0100 Subject: [PATCH 12/15] Fix default language determination in wxLocale under MSW We must use GetUserDefaultUILanguage() and not GetUserDefaultLCID(). Although still not ideal, this is much better when the UI language and the locale differ: when everything is in some language, it's better to use this language and wrong date/number format than use correct date/number format but a wrong language. See #11594. --- src/common/intl.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 9598f0ec12..9053bb4102 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -50,6 +50,9 @@ #ifndef LOCALE_SNAME #define LOCALE_SNAME 0x5c #endif + #ifndef LOCALE_CUSTOM_UI_DEFAULT + #define LOCALE_CUSTOM_UI_DEFAULT 0x1400 + #endif #endif #include "wx/file.h" @@ -768,11 +771,11 @@ inline bool wxGetNonEmptyEnvVar(const wxString& name, wxString* value) } } #elif defined(__WIN32__) - LCID lcid = GetUserDefaultLCID(); - if ( lcid != 0 ) + const LANGID langid = ::GetUserDefaultUILanguage(); + if ( langid != LOCALE_CUSTOM_UI_DEFAULT ) { - wxUint32 lang = PRIMARYLANGID(LANGIDFROMLCID(lcid)); - wxUint32 sublang = SUBLANGID(LANGIDFROMLCID(lcid)); + wxUint32 lang = PRIMARYLANGID(langid); + wxUint32 sublang = SUBLANGID(langid); for ( i = 0; i < count; i++ ) { From 9c4ab145e9c9d79f81fb20a9a41a876effa1778c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 2 Mar 2021 18:03:30 +0100 Subject: [PATCH 13/15] Add SetThreadUILanguage() wrapper Make it possible to reuse the code dynamically loading this function from elsewhere. No real changes. --- src/common/intl.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 9053bb4102..85d8019e92 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -446,6 +446,28 @@ static const char *wxSetlocaleTryAll(int c, const wxString& lc) #endif // __UNIX__ +#ifdef __WIN32__ + +// Trivial wrapper for ::SetThreadUILanguage(). +// +// TODO-XP: Drop this when we don't support XP any longer. +static void wxMSWSetThreadUILanguage(LANGID langid) +{ + // SetThreadUILanguage() is available on XP, but with unclear + // behavior, so avoid calling it there. + if ( wxGetWinVersion() >= wxWinVersion_Vista ) + { + wxLoadedDLL dllKernel32(wxS("kernel32.dll")); + typedef LANGID(WINAPI *SetThreadUILanguage_t)(LANGID); + SetThreadUILanguage_t pfnSetThreadUILanguage = NULL; + wxDL_INIT_FUNC(pfn, SetThreadUILanguage, dllKernel32); + if (pfnSetThreadUILanguage) + pfnSetThreadUILanguage(langid); + } +} + +#endif // __WIN32__ + bool wxLocale::Init(int lang, int flags) { #if WXWIN_COMPATIBILITY_2_8 @@ -544,17 +566,7 @@ bool wxLocale::Init(int lang, int flags) // change locale used by Windows functions ::SetThreadLocale(lcid); - // SetThreadUILanguage() is available on XP, but with unclear - // behavior, so avoid calling it there. - if ( wxGetWinVersion() >= wxWinVersion_Vista ) - { - wxLoadedDLL dllKernel32(wxS("kernel32.dll")); - typedef LANGID(WINAPI *SetThreadUILanguage_t)(LANGID); - SetThreadUILanguage_t pfnSetThreadUILanguage = NULL; - wxDL_INIT_FUNC(pfn, SetThreadUILanguage, dllKernel32); - if (pfnSetThreadUILanguage) - pfnSetThreadUILanguage(LANGIDFROMLCID(lcid)); - } + wxMSWSetThreadUILanguage(LANGIDFROMLCID(lcid)); // and also call setlocale() to change locale used by the CRT retloc = info->TrySetLocale(); From 502114261ac3577a613802f34600a12971c78cff Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 2 Mar 2021 18:06:48 +0100 Subject: [PATCH 14/15] Handle wxLANGUAGE_DEFAULT in wxLocale specially under MSW too Even if we do know about the system language, it's still better to let OS/CRT handle it, as we may not know enough about it. E.g. "system language" may actually be a mix of the different languages and formats and we don't handle this case at all, while OS/CRT do just fine. --- src/common/intl.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 85d8019e92..32191a40f0 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -547,10 +547,14 @@ bool wxLocale::Init(int lang, int flags) #elif defined(__WIN32__) const char *retloc; - if ( !info ) + if ( lang == wxLANGUAGE_DEFAULT ) { - // We're using the system language, but we don't know what it is, so - // just use setlocale() to deal with it. + ::SetThreadLocale(LOCALE_USER_DEFAULT); + wxMSWSetThreadUILanguage(LANG_USER_DEFAULT); + + // We're using the system language, so let setlocale() deal with it: it + // does it better than we do and we might not even know about this + // language in the first place. retloc = wxSetlocale(LC_ALL, ""); } else if ( info->WinLang == 0 ) From e9ea0f53f606759520fb0b600761a6ec1618a662 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 2 Mar 2021 18:14:58 +0100 Subject: [PATCH 15/15] Refactor platform checks in wxLocale::Init() Avoid the need for ugly WX_NO_LOCALE_SUPPORT macro at the cost of a couple of extra #ifs, which seems to be a worthy trade-off. This also allows making the code calling setlocale("") for the default language platform-independent. No real changes. --- src/common/intl.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 32191a40f0..0b0d8798f4 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -508,8 +508,18 @@ bool wxLocale::Init(int lang, int flags) DoInit(name, shortName, lang); // Set the locale: + +#if defined(__UNIX__) || defined(__WIN32__) + + // We prefer letting the CRT to set its locale on its own when using + // default locale, as it does a better job of it than we do. We also have + // to do this when we didn't recognize the default language at all. + const char *retloc = lang == wxLANGUAGE_DEFAULT ? wxSetlocale(LC_ALL, "") + : NULL; + #if defined(__UNIX__) - const char *retloc = wxSetlocaleTryAll(LC_ALL, shortName); + if ( !retloc ) + retloc = wxSetlocaleTryAll(LC_ALL, shortName); if ( !retloc ) { @@ -546,16 +556,12 @@ bool wxLocale::Init(int lang, int flags) #endif // __AIX__ #elif defined(__WIN32__) - const char *retloc; if ( lang == wxLANGUAGE_DEFAULT ) { ::SetThreadLocale(LOCALE_USER_DEFAULT); wxMSWSetThreadUILanguage(LANG_USER_DEFAULT); - // We're using the system language, so let setlocale() deal with it: it - // does it better than we do and we might not even know about this - // language in the first place. - retloc = wxSetlocale(LC_ALL, ""); + // CRT locale already set above. } else if ( info->WinLang == 0 ) { @@ -591,12 +597,9 @@ bool wxLocale::Init(int lang, int flags) } #endif // CRT not handling Unicode-only languages #else - wxUnusedVar(flags); - return false; - #define WX_NO_LOCALE_SUPPORT + #error "Unsupported platform" #endif -#ifndef WX_NO_LOCALE_SUPPORT return DoCommonPostInit ( retloc != NULL, @@ -604,7 +607,10 @@ bool wxLocale::Init(int lang, int flags) shortName, flags & wxLOCALE_LOAD_DEFAULT ); -#endif // !WX_NO_LOCALE_SUPPORT +#else // !(__UNIX__ || __WIN32__) + wxUnusedVar(flags); + return false; +#endif } namespace