devilutionX icon indicating copy to clipboard operation
devilutionX copied to clipboard

Use WinRT to get user languages on Windows 10+

Open ephphatha opened this issue 3 years ago • 2 comments

Turns out windows locale support was absolute garbage until recently, yay. Windows provides multiple APIs for getting user/system language settings. Of course they all seem to work differently, and the ones I thought were recommended for fallback behaviour turn out to be the most broken.

The Windows NLS API function GetUserPreferredUiLanguages() appears to only ever return two language codes from within the same family. The codes returned are drawn from a subset of ISO639 codes and languages outside that set get transformed to the closest representation (e.g. both en-AU and en-NZ are returned as en-GB). This makes it less than useful for users with multi-language environments, as a list like en-AU, zh-CN, en-US becomes en-GB, en-US.

As far as I can tell there is no way around this (before Win10) that actually respects user preferences.

MUI API provides a similar function GetUiLanguageFallbackList() but this turns out to be even less useful for devX, it returns the same list as above with "neutral" language codes inserted after the first regional code in a family (en-NZ, zh-CN, en-US becomes en-GB, en, en-US).

WinNLS EnumUiLanguages() is better in that it returns languages outside the default family. However it doesn't return results in user preferred order and still mangles codes outside the same set as the previous two functions (en-AU, zh-CN, en-US becomes en-US, en-GB, zh-CN). This also returns all available languages, not just what the user has as their preferences.

WinRT provides a nice, simple API endpoint in UserProfile.GlobalizationPreferences.Languages that actually gives the list of user supported language codes (in IETF format), in order, without mangling or skipping any. However this requires linking against and intialising the winrt engine. This requires Windows 10 or later, and winrt::init_apartment() must be called once per thread before using any of the API. Calling it in this function isn't ideal but there's nothing else that uses it yet.

This PR is a best effort to allow developers building locally on Win10 or later to use language detection. I'm hoping the CI builds exclude this code, the MinGW build is using WINVER = 0x0400 so it already uses the pre-vista fallback.

ephphatha avatar Jan 01 '22 10:01 ephphatha

What a mess. Is the WinRT stuff also what would be used by a UWP for the Xbox Series (or what ever *** **** the latest One in the Series is called, they seam to have gone a full 360 with it at this point).

AJenbo avatar Jan 01 '22 11:01 AJenbo

I think so, looks like UWP uses WinRT or is a layer on top in some fashion.

ephphatha avatar Jan 01 '22 12:01 ephphatha