Re: #11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later

310 views
Skip to first unread message

wxTrac

unread,
Oct 29, 2018, 4:56:06 PM10/29/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------
Changes (by kgschlosser):

* cc: drschlosser@… (added)


Comment:

Since this problem is already reported I figured I would put some code in
to be able to replicate the issue at hand. and give explicit instruction
on how to replicate.

the code below is in Python and will require wxPython to be used. the
issue actually lies in wxWidgets \src\common\intl.cpp line 789

What I have personally tested and does not work properly
Windows Versions: 7, 10
Python Versions: 2.7, 3.5
wxPython Versions: 3.0.2, 4.0.3

{{{
from __future__ import print_function
import wx
import ctypes
import locale
from ctypes.wintypes import (
DWORD,
WORD,
INT,
WCHAR,
HANDLE
)

LOCALE_NAME_MAX_LENGTH = 85

LOCALE_INVARIANT = 0x007F
LOCALE_USER_DEFAULT =- 0x0400
LOCALE_SYSTEM_DEFAULT = 0x0800

KL_NAMELENGTH = 9

kernel32 = ctypes.windll.Kernel32
user32 = ctypes.windll.User32


if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
ULONG_PTR = ctypes.c_ulong
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
ULONG_PTR = ctypes.c_ulonglong
else:
ULONG_PTR =ctypes. c_ulong


LCID = DWORD
LANGID = WORD
GEOTYPE = DWORD
HKL = HANDLE
DWORD_PTR = ULONG_PTR
PWSTR = ctypes.POINTER(WCHAR)


# LCID GetUserDefaultLCID();
GetUserDefaultLCID = kernel32.GetUserDefaultLCID
GetUserDefaultLCID.restype = LCID

user_default_lcid = GetUserDefaultLCID()
print('kernel32.GetUserDefaultLCID:', user_default_lcid)
if user_default_lcid in locale.windows_locale:
print(
'kernel32.GetUserDefaultLCID canonical name:',
locale.windows_locale[user_default_lcid]
)

else:
print('kernel32.GetUserDefaultLCID canonical name: None')
# LCID GetSystemDefaultLCID();
GetSystemDefaultLCID = kernel32.GetSystemDefaultLCID
GetSystemDefaultLCID.restype = LCID

system_default_lcid = GetSystemDefaultLCID()
print()
print('kernel32.GetSystemDefaultLCID:', system_default_lcid)
if system_default_lcid in locale.windows_locale:
print(
'kernel32.GetSystemDefaultLCID canonical name:',
locale.windows_locale[system_default_lcid]
)

else:
print('kernel32.GetSystemDefaultLCID canonical name: None')
# int GetUserDefaultLocaleName(
# LPWSTR lpLocaleName,
# int cchLocaleName
# );
GetUserDefaultLocaleName = kernel32.GetUserDefaultLocaleName
GetUserDefaultLocaleName.restype = INT

user_locale_name = (WCHAR * LOCALE_NAME_MAX_LENGTH)()
GetUserDefaultLocaleName(
ctypes.byref(user_locale_name),
LOCALE_NAME_MAX_LENGTH
)

print()

print('kernel32.GetUserDefaultLocaleName:', user_locale_name.value)

# int GetSystemDefaultLocaleName(
# LPWSTR lpLocaleName,
# int cchLocaleName
# );
GetSystemDefaultLocaleName = kernel32.GetSystemDefaultLocaleName
GetSystemDefaultLocaleName.restype = INT

system_locale_name = (WCHAR * LOCALE_NAME_MAX_LENGTH)()
GetSystemDefaultLocaleName(
ctypes.byref(system_locale_name),
LOCALE_NAME_MAX_LENGTH
)

print('kernel32.GetSystemDefaultLocaleName:', system_locale_name.value)

# LANGID GetUserDefaultUILanguage();
GetUserDefaultUILanguage = kernel32.GetUserDefaultUILanguage
GetUserDefaultUILanguage.restype = LANGID

user_default_ui_language = GetUserDefaultUILanguage()

print()
print('kernel32.GetUserDefaultUILanguage:', user_default_ui_language)
if user_default_ui_language in locale.windows_locale:
print(
'kernel32.GetUserDefaultUILanguage canonical name:',
locale.windows_locale[user_default_ui_language]
)

else:
print('kernel32.GetUserDefaultUILanguage canonical name: None')


print()
# LANGID GetSystemDefaultUILanguage();
GetSystemDefaultUILanguage = kernel32.GetSystemDefaultUILanguage
GetSystemDefaultUILanguage.restype = LANGID

system_default_ui_language = GetSystemDefaultUILanguage()

print('kernel32.GetSystemDefaultUILanguage:', system_default_ui_language)

if system_default_ui_language in locale.windows_locale:
print(
'kernel32.GetSystemDefaultUILanguage canonical name:',
locale.windows_locale[system_default_ui_language]
)
else:
print('kernel32.GetSystemDefaultUILanguage canonical name: None')


# LANGID GetUserDefaultLangID();
GetUserDefaultLangID = kernel32.GetUserDefaultLangID
GetUserDefaultLangID.restype = LANGID

user_default_langid = GetUserDefaultLangID()

print()
print('kernel32.GetUserDefaultLangID:', user_default_langid)

if user_default_langid in locale.windows_locale:
print(
'kernel32.GetUserDefaultLangID canonical name:',
locale.windows_locale[user_default_langid]
)

else:
print('kernel32.GetUserDefaultLangID canonical name: None')

# LANGID GetSystemDefaultLangID();
GetSystemDefaultLangID = kernel32.GetSystemDefaultLangID
GetSystemDefaultLangID.restype = LANGID

system_default_langid = GetSystemDefaultLangID()
print()
print('kernel32.GetSystemDefaultLangID:', system_default_langid)

if system_default_langid in locale.windows_locale:
print(
'kernel32.GetSystemDefaultLangID canonical name:',
locale.windows_locale[system_default_langid]
)
else:
print('kernel32.GetSystemDefaultLangID canonical name: None')


# HKL GetKeyboardLayout(
# DWORD idThread
# );

GetKeyboardLayout = user32.GetKeyboardLayout
GetKeyboardLayout.restype = HKL

def LOWORD(l):
return WORD(DWORD_PTR(l).value & 0xffff)


keyboard_layout = GetKeyboardLayout(DWORD(0))
keyboard_langid = LANGID(LOWORD(keyboard_layout).value)
print()
print('user32.GetKeyboardLayout:', keyboard_langid.value)
# BOOL GetKeyboardLayoutNameW(
# LPWSTR pwszKLID
# );

if keyboard_langid.value in locale.windows_locale:
print(
'user32.GetKeyboardLayout canonical name:',
locale.windows_locale[keyboard_langid.value]
)

else:
print('user32.GetKeyboardLayout canonical name: None')


wx_default = wx.Locale.GetSystemLanguage()
print('\n')
print('wx.Locale.GetSystemLanguage: ' + str(wx_default))

lang_info = wx.Locale.GetLanguageInfo(wx_default)

print('wx.LanguageInfo.LocaleName:', lang_info.GetLocaleName())
print('wx.LanguageInfo.CanonicalName:', lang_info.CanonicalName)
print('wx.LanguageInfo.Description:', lang_info.Description)
print('wx.LanguageInfo.Language:', lang_info.Language)
}}}

The code above leverages ctypes to access the Windows specific API calls
to grab the language. Windows has a very complex language/locale setup. I
believe this is due to decades of adding and patching.

In order to replicate the issue.
Start -> Control Panel -> Region and Language
Keyboards and Languages tab. Display langiage section. Install and enable
English (United States).
Formats tab. Format drop down. Select English (United States)
Administrative tab. (Now here is something very misleading) Change System
Locale button. Set to English (United States). This may require a reboot.
Click the apply button. Run the script above the output will be


{{{
user default: 1033
system default: 1033
wx default: 60
user default canonical name: en_US
system default canonical name: en_US
wx default canonical name: en_US
}}}

Now repeat the steps above making only one change. Change the format
to Hebrew (Israel). Take note this is not changing the the displayed
language
It is changing the language format which would be display of date/time,
currency things of that nature. Which as best as i figure would be the
locale.

rerun the script and the output will be

{{{
user default: 1033
system default: 1033
wx default: 100
user default canonical name: en_US
system default canonical name: en_US
wx default canonical name: he_IL
}}}

now if you notice the returned languages from the Windows API has not
changed at all. But the language code from wxWidgets has. This is
incorrect behavior

In Windows You have the ability to set the locale, displayed language,
keyboard layout and finally the system language all separately. this adds
quite a bit of complexity in deciding what to use in order to display the
GUI components.

wxLocale.GetSystemLanguage is incorrect in 2 ways. first is it does not
return the system language it actually returns the user locale. second is
it should not return anything user based it should return the system
language as the method name implies. But with respect to returning the
default system language this is not something that should be needed. it is
for use in non unicode applications as well as being the System "install"
language, the defaulted language that windows uses when it is getting
installed. It can be change via the Administrative tab and clicking on the
Change System Locale button. and the button being labeled as such is very
misleading because not only does setting that change the system locale.
but it also changes the system language.

Now I specifically used the languages above for a reason. if you set
wxLocale
using wx.Locale(wx.Locale.GetSystemLanguage()) and you have the format
field set to Hebrew (Israel) the GUI gets completely flipped. including
the written text gets displayed right to left. English (United States) is
not a language that gets read from right to left and should not be
displayed in this manner. But the whole GUI is actually flipped
horizontally including the close and min/max buttons in the caption bar.
Also if you open a dialog setting the current frame as a parent the
displayed text in the dialog is in Hebrew and not the default user
displayed language.

I can submit a patch for repairing the single method. But it appears that
possibly other parts of wxWidgets might possibly use that method. I am
unfamiliar with the code and it would take me a long while to locate any
potential issues. As a quick and dirty band-aide I have build a cross
reference from Windows LANDID's to wx.LANGUAGE_* codes. Use the ctypes
Windows API call to GetUserDefaultUILanguage to get the LANGID feed it
into the cross reference and use that output to set the language properly.

I believe the whole of wxLocale as well as wxLanguageInfo needs a code
rewrite. I feel this should be done because when dealing with Windows the
locale, displayed language, keyboard layout are separate things and using
the locale to set the language is incorrect. and using the language to set
the locale is also incorrect. I do not know how other operating systems
function in respect to this.


The script above has the methods that can be used in determining the
keyboard/language/locale.

Thank You for taking the time to go over this problem.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:3>

wxTrac

unread,
Oct 29, 2018, 6:03:57 PM10/29/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vadz):

Just to be clear: it's called `GetSystemLanguage()` but it is supposed to
return the language that should be used for the user and has nothing to do
with the system default language, whatever this is.

Also, I think we need to take a step back and think about what exactly is
this function useful for. AFAIK it should only be used to determine the
language to load translations for and from this point of view, it should
indeed use `::GetThreadUILanguage()`, just as mentioned in the original
bug report, as it's more appropriate than `::GetUserDefaultLCID()` if the
two don't match (and in general they don't, although very often they do,
of course).

And ideally we'd use `::GetThreadPreferredUILanguages()` to allow
selecting the first language for which we have translations available.
Again, this is something mentioned in the original bug report and I still
think it would be great to implement this.

I'm not sure if there are any other conclusions to draw from the
comment:3. In particular I don't think we need to totally rewrite this
code.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:4>

wxTrac

unread,
Oct 29, 2018, 10:24:16 PM10/29/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by robind):

FTR: https://github.com/wxWidgets/Phoenix/issues/1008

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:5>

wxTrac

unread,
Oct 30, 2018, 6:15:24 AM10/30/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vaclavslavik):

Note that in the past 9 years, something changed: there's now
`wxTranslations` API for loading translations in the way comment:4 and the
original report describe. The flipping could be addressed by using RTL
information from that, not the locale (and ideally deprecating anything
language- related in `wxLocale` and keeping it for locale information
only).

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:6>

wxTrac

unread,
Oct 30, 2018, 11:24:37 AM10/30/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vadz):

To be honest, I'm not sure how is `wxTranslations` supposed to be used if
you just want the application to appear in the user's language. It would
be nice to modernize `samples/internat` to show it. Also, presumably,
`wxLocale` still needs to be used if you want to show dates/times etc
according to user's preferences, so I'm not completely convinced that
language-dependent parts of `wxLocale` need to be deprecated as this would
mean that you would have to explicitly use both it and `wxTranslations` in
the most common case, instead of using just a single class (and forwarding
the translations stuff to `wxTranslations`), which doesn't really look
like a big gain for me.

Again, if anybody has any time to look into this (I really don't right
now, sorry), I'd recommend starting by replacing `::GetUserDefaultLCID()`
with `::GetThreadUILanguage()` and seeing what problems are left after
doing this.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:7>

wxTrac

unread,
Oct 30, 2018, 12:11:55 PM10/30/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vaclavslavik):

> To be honest, I'm not sure how is wxTranslations supposed to be used if
you just want the application to appear in the user's language.

Parts of `wxLocale` are implemented in it, answering that… The API is
mostly the same (except the addition of `GetBestTranslation`, which is
used internally and which uses OS priority list to determine suitable
language ''for given domain'').

> lso, presumably, wxLocale still needs to be used if you want to show
dates/times etc according to user's preferences, so I'm not completely
convinced that language-dependent parts

Locale formatting ''is not'' language-dependent. That's the whole point:
while UI language handling doesn't map to locale well, has multiple
prioritized languages and is disconnected from locale in modern OSes,
locale is one, (user-)globally configured and handles formatting etc.

> which doesn't really look like a big gain for me.

Clarity would be the gain - separating independent things (UI language,
locale) into independent classes. It would fix the long-standing confusion
of concepts in wx API that ''does'' lead to problems. The very flipping
problem above illustrates this, it's a consequence of confusing locale
with UI language even among core devs - not in the sense that we're
unclear on the concepts (but many users are), but in the sense that there
are all too handy, but wrong, tools at our disposal to do the wrong thing
automatically. Clearly separating the two concepts would help avoid that.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:8>

wxTrac

unread,
Oct 31, 2018, 6:47:20 PM10/31/18
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vadz):

Vaclav, I don't really disagree with anything in the comment:8, but I'm
not sure what exactly do you suggest should be done. AFAICS we still need
to do what I wrote in the comment:7 and even though I don't have time to
do anything anyhow right now, I still think it would be useful if you
could please explain what (if anything) do you think should be done in
more details. TIA!

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:9>

wxTrac

unread,
Feb 13, 2020, 12:47:43 PM2/13/20
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------
Changes (by kgschlosser):

* cc: drschlosser@… (removed)


Comment:

I wanted to see if there has been advancement on this at all. There is
another user that mentioned having the same issue as me with the RTL when
changing the format (locale) in Windows. @robind posted a link to the
issue on wxPython Phoenix.


I do not know how the locale and languages are handled in wxWidgets and if
any of it is handled by wxPython. I know that there is an enumeration that
is available in wxPython for languages/locals. I do not know the reason
why this enumeration exists. I am going to make an assumption that there
are constants of definitions in wxWidgets for the locals/languages. When I
looked a while back I did not notice any code that queried Windows for
things like decimal positions or format specifiers. I am also not sure why
iso language_locale (en_US) identifiers are not the default mechanism used
in setting the language and locale.

I did want to throw out there that Windows does have "virtual" LCID's and
these virtual LCID's have been in Windows since at least Windows 7 and are
probably used in Vista and maybe XP. Because these virtual LCID's were not
commonly used issues never really arose from them. Windows 10 changed
that. Almost all of the new languages/locales that were added to Windows
10 use these virtual LCID's. I cam across this when setting the locale in
Python. Python pitches a fit when one of these language/locals are set.
Language/locals that have a virtual LCID all share the same ID. 0x1000 I
believe, so when using the Windows API it is really important to minimize
using LCID's. The iso name is what should be used where ever available.

I wrote a helper module to address this issue in Python and also
wxPython/wxWidgets. It is written in Python (ctypes) which can be ported
to c code fairly easily. I mention this helper because it shows one
approach to managing Windows languages and locals. It supports all
languages/locals available from Windows XP to Windows 10 including all of
the available language packs. Not all of these are supported by
wxPython/wxWidgets but it does map the ones that are supported. On a clean
Windows 7 x64 SP1 installation there are 123 locales and 196 languages and
of those wxPython/wxWidgets has support for 127 possible locale/language
combinations.

https://github.com/kdschlosser/pyWinLocale

The module also has all of the Windows API calls for getting the locale
format specifiers for a given locale using the iso name. it also supports
the 3 different iso name specifications for the country code.

I do want to tip my hat to the devs of wxWidgets for writing wxWidgets. It
is one hell of a task to write a cross platform project like this. It is a
huge amount of hard work that has taken place. I thank you guys/gals for
the time and effort put in to make wxWidgets available to everyone.

I am not a c developer, I know enough to get into trouble. I do know
Windows API, if there is any way I would be able to help let me know.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:10>

wxTrac

unread,
Feb 13, 2020, 1:20:11 PM2/13/20
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------
Changes (by kgschlosser):

* cc: drschlosser@… (added)


Comment:

I wanted to mention that I am in agreement with Vaclav as far as how
locals and languages should be handled.

This is my understanding of locals and languages work. please correct me
if my thought process is incorrect on this. There is a heap of information
on this exact topic and quite a bit of it is conflicting. But this is what
I have come up with and how it should be done.


There has always been a large amount of fog when it comes to languages and
locals in software. This is due to the thought that they are joined in
some manner. the iso codes seem to strengthen this thought. They are not
joined. They need to be able to be changed completely independent of one
another. Windows has added to this thought process as well, and that has
not helped what's so ever.

a locale simply defines the format specifiers, things like decimal
positions, time formatting. currency formatting.

the language is exactly that. it is the displayed character set.

The only way the locale and language is linked together is by means of the
code pages (character map) this is so that the proper characters can be
gotten for the selected language when formatting the time, or currency so
it can be displayed to the user correctly.

So because they should be handled independently of one another they should
be coded as such. there should be a class for language and there should be
a completely separate class for locale. the back end code would tie the 2
together for the purposes of making a call to the OS in order to get
proper format specifiers for a given locale.

OS's have provided hard coded identifiers for common locale/language
combinations. These identifiers have also added confusion. They seem to be
thought of as what the OS supports. This is not true. any locale can be
paired with any language. so if an application has support for 32
languages and 32 locals then there are 992 locale/language combinations
the OS supports.

There should be a single function for convenience when setting the
locale/language. This function would be passed the iso representation of a
locale/language (en_US) and the function would construct the locale and
language class instances and then set wxWidgets to use those instances at
the default language and locale.

The user should be able to construct the instances them selves if wanted.
Those classes should have methods available so a user is able to query the
OS for information about if a language is RTL or not. or where the
currency identifier gets placed for a given locale. and what the currency
identifier is for a given language.

It would be nice to be able to set a widgets locale and language to be
different from the default one. The application I work on has a
translation dialog that is available to the user. It allows them to
translate the application to any language they want. It would be great if
the application was able to display 2 locals/language combinations at the
same time.

I believe this is what Vaclav was thinking. I could be incorrect.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:11>

wxTrac

unread,
Feb 13, 2020, 5:01:44 PM2/13/20
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vadz):

Replying to [comment:10 kgschlosser]:
> I wanted to see if there has been advancement on this at all.

No, sorry, I just don't have any bandwidth for this and, unfortunately, I
don't think this is going to change any time soon. I can only repeat that
I still think that the smallest fix that would, IMHO, be helpful is fixing
`GetSystemLanguage()` as described in comment:4 and any PRs implementing
this would be definitely welcome.

I'm still not sure what API changes exactly was Vaclav suggesting. AFAICS
`wxTranslations` is fine as it is, but we don't have any good way to
decide which language should be used for it and this probably needs to be
added.

As for `wxLocale`, it seems to also be fine as far for locale (not
language) functionality. The fact that it can also be used to load
translations may not be ideal from API design purity point of view, but
we're not going to remove it for the observable future because of
compatibility constraints anyhow, so we still need to make this work as
well as possible -- i.e. by using the user preferred language(s) when
`wxLocale` is initialized using `wxLANGUAGE_DEFAULT`.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:12>

wxTrac

unread,
Mar 29, 2020, 3:54:37 AM3/29/20
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------
Changes (by kgschlosser):

* cc: drschlosser@… (removed)


Comment:

Replying to [comment:12 vadz]:
> Replying to [comment:10 kgschlosser]:
> > I wanted to see if there has been advancement on this at all.
>
> No, sorry, I just don't have any bandwidth for this and, unfortunately,
I don't think this is going to change any time soon. I can only repeat
that I still think that the smallest fix that would, IMHO, be helpful is
fixing `GetSystemLanguage()` as described in comment:4 and any PRs
implementing this would be definitely welcome.
>
> I'm still not sure what API changes exactly was Vaclav suggesting.
AFAICS `wxTranslations` is fine as it is, but we don't have any good way
to decide which language should be used for it and this probably needs to
be added.
>
> As for `wxLocale`, it seems to also be fine as far for locale (not
language) functionality. The fact that it can also be used to load
translations may not be ideal from API design purity point of view, but
we're not going to remove it for the observable future because of
compatibility constraints anyhow, so we still need to make this work as
well as possible -- i.e. by using the user preferred language(s) when
`wxLocale` is initialized using `wxLANGUAGE_DEFAULT`.


OK so when I run the following code.

locale = wx.Locale()
locale.Init(wx.LANGUAGE_PASHTO)

I get the error locale Pashuto is not supported by the OS.


Yet when I query Windows directly It tells me that a locale of AF and a
language of ps is indeed supported by my OS. Further more why is it trying
to set the locale to a language and not a country?


All of the information you see below is gotten from the OS.

Afghanistan - AF
english_name: Pashto
english_locale_name: Afghanistan
name: Pashto
locale_name: Afghanistan
label: Pashto (Afghanistan)
native_name: پښتو
native_locale_name: افغانستان
native_label: پښتو (افغانستان)
ansi codepage: 0
codepage: 1
Windows LCID: 0x0463
iso code: ps-AF


I have not been able to find a way to set the locale and language
independent of one another. I am able to set the language and locale in
windows to ps_US without an issue. how come I cannot get wxWidgets to
accept it? Both the language and the locale are supported by wxWidgets But
not together. which does not make any sense. the locale is used only for
formatting and nothing more. It queries the language code page to get
symbols that represent things like decimal points and dollar signs and
that is the extent of what a locals involvement with a language should be.
a language is NOT married to a locale but in wxWidgets it appears as tho
they are.

The world is a small place compared to what it used to be. There are all
kinds of people that speak all kinds of languages in all sorts of
different countries. The way wxWidgets is currently set up it limits
languages to specific countries. So users that speak Swahili that live in
Germany and have Windows set to that language and locale are not going to
be able to run an application that uses wxWidgets unless they set their
Windows locale to a standard locale that has a language of Swahili. That
is a completely bonkers concept to me.


Using wxLocale and wxLanguage should be as simple as.

wx.SetLocale(wx.Locale('DE'))
wx.SetLanguage(wx.Language('sw'))

Now I know that wxSetLocale does exist. Problem is that it requires a hell
of alot of code in order to assemble the locale string in order to use it.
and using wxLocale to do it does not work because of the LCID issue.

wxSetLocale should take a single parameter wxLocale. it should be able to
build the locale string by calling a function that should exist
wxGetLanguage
getting the ANSI code page from the language and also the language english
name and getting the locale english name and build the string that is
needed.

when wx.SetLanguage is called it will set the language and then call
wxSetLocal(wxGetLocale()) to set the language locale and code page
properly.


Do not rely on Windows LCID's as a way to identify a language/locale. Here
is a list of language/locales that all have the exact same LCID.

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-
lcid/926e694f-1797-4418-a922-343d1c5e91a6

and then you have the virtual or dynamic LCID's
0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, 0x4000,
0x4400, 0x4800 and 0x4C00

On top of of that it ends up not working properly.


So using the LCID as the identifier when querying any of the Windows
locale functions is going to either fail, or it is going to return
incorrect information. there are alternate functions that take the iso
code instead. and those are the functions that should be used.

here is an example to get the ansi code page for a locale.
This is what wxWidgets uses
GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, WXSIZEOF(buffer))


and here is how you do it without using an LCID.
GetLocaleInfoEx(LPCWSTR('en_us'), LOCALE_IDEFAULTANSICODEPAGE, buffer,
WXSIZEOF(buffer))

the above will always work for getting a language code page so long as the
language is installed into the system. the way it is done in wxWidgets
will not because not all LCID's are unique.


So if I wanted to use the korean language with a local of United States
the set_locale argument would be Korean_United States.949. no LCID needed
to do this.

Now, this problem is coming up more and more because Windows 10 uses a
whole bunch of duplicate LCID's and also dynamic LCID's. And also because
of how small the World is getting on top of that and we are seeing more
and more people using language/locales that are not pre defined.

I am not sure how else to go about explaining as to why the
language/locale in wxWidgets does not work correctly on Windows. I have
given about as much information in as much detail as I can possibly
provide.


here are a few issues that were closed as invalid and in fact were not
invalid.

#15257 - closed as invalid, and it is not invalid. 7 years ago
#15219 - closed as invalid, and it is not invalid. 7 years ago

I am sure there are other issues that have been reported that would stem
from this problem. this should be the core of things like incorrectly
formatted currency, dates, time, numbers... etc... or simply having
crashes at startup or strange errors like the popup i got with a language
name (and only the language name) being not supported by the OS as a
locale..

please do some investigation and repair. I am not strong enough writing
c/cpp code to make the changes that are need. Otherwise I would do it.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:13>

wxTrac

unread,
Mar 29, 2020, 2:17:54 PM3/29/20
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vadz):

Just to be perfectly clear: I simply don't have time to work on this. Yes,
this is important, but so are 10000 other things and some of them are even
more important than this one and even if they're not, I personally need
them more and so I need to finish them first. I'd be very supportive of
any improvements to wx API in this area, but I just can't, and won't,
promise to do anything myself in the observable future.

For now my recommendation would be to use `wxLocale` for setting the
locale only and using `wxTranslations` for loading the translations.

This is not going to work for `LANG_PASHTO` just because it's not present
in `misc/languages/langtabl.txt` but this is trivial to update if anybody
interested in adding it (and any other missing values) is motivated in
doing it. But it should definitely work for `LANG_GERMAN` and set locale
to `de` for it. And then you can use `wxTranslations` to load Swedish
language messages.

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:14>

wxTrac

unread,
Mar 2, 2021, 12:29:32 PM3/2/21
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by vadz):

Rereading this ticket, it's amazing how the discussion immediately went
completely away from the original point which was absolutely correct and
very simple to fix: `GetSystemLanguage()` was just indeed implemented
incorrectly, i.e. it was a trivial bug that should have been fixed years
(decades?) ago :-( The fix for it is now in
e8aab0ea3f309c0efb8d36812ea835ee10534eac which is part of
[https://github.com/wxWidgets/wxWidgets/pull/2260 PR 2260] that will be
merged soon, so this will be finally fixed in 3.1.5 and should fix the
most egregious manifestations of the bug, e.g. the fact that RTL direction
was used even for English language if Hebrew date format was used.

One other bad and often occurring in practice problem was that we
overwrote the system date/time formats when setting the default locale,
which didn't work as soon as non-standard format was used. And this is
trivial to fix too, of course: we just don't need to do ''anything'' in
this case and let the system/CRT take care of it, as is done for MSW in
1375de030189f6edb0dc0f85b194cc04ed5d551d of the same PR.

There are certainly more things to improve, i.e. we still should add
support for `GetUserPreferredUILanguages()`, but this doesn't seem to have
any equivalent under Unix (except for macOS) and so is much lower
priority. With the changes above, at least the most basic things, i.e.

1. Using `wxLocale(wxLANGUAGE_DEFAULT)` to use the user locale (i.e. date
etc formats) ''and'' language (i.e. load the appropriate message catalog).
1. Using `wxTranslations` to use a language chosen from the list
interactively.

should work correctly, so I think this ticket can finally be closed.

Thanks for Niels for originally reporting it and sorry for taking so long
to make the trivial fix, we were led completely astray here from the very
beginning (well, at least I was, maybe all the others understood what had
to be done correctly and just chose not to say it clearly).

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:15>

wxTrac

unread,
Mar 5, 2021, 1:03:21 PM3/5/21
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------
Reporter: nielsm | Owner:
Type: defect | Status: confirmed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------

Comment (by Vadim Zeitlin <vadim@…>):

In [changeset:"9600c29ff2ca13ef66b76eabadaac5ec8654b792/git-wxWidgets"
9600c29ff/git-wxWidgets]:
{{{
#!CommitTicketReference repository="git-wxWidgets"
revision="9600c29ff2ca13ef66b76eabadaac5ec8654b792"
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.
}}}

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:16>

wxTrac

unread,
Mar 5, 2021, 1:03:21 PM3/5/21
to wx-...@googlegroups.com
#11594: Fix wxLocale::GetSystemLanguage() and enhance it for Vista and later
---------------------+-------------------------------------
Reporter: nielsm | Owner: Vadim Zeitlin <vadim@…>
Type: defect | Status: closed
Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.10
Resolution: fixed | Keywords: wxLocale i18n MUI
Blocked By: | Blocking:
Patch: 0 |
---------------------+-------------------------------------
Changes (by Vadim Zeitlin <vadim@…>):

* owner: => Vadim Zeitlin <vadim@…>
* status: confirmed => closed
* resolution: => fixed


Comment:

In [changeset:"7bcac7bfde636a7895ce09dfb1369b159ec15dcb/git-wxWidgets"
7bcac7bfd/git-wxWidgets]:
{{{
#!CommitTicketReference repository="git-wxWidgets"
revision="7bcac7bfde636a7895ce09dfb1369b159ec15dcb"
Merge branch 'unix-default-locale'

Improve handling of default locale and other locale-related fixes.

See https://github.com/wxWidgets/wxWidgets/pull/2260

Closes #11594.
}}}

--
Ticket URL: <https://trac.wxwidgets.org/ticket/11594#comment:17>
Reply all
Reply to author
Forward
0 new messages