[PATCH] kernel32: Respect the LANG environment variable on Mac OS.

Ken Thomases ken at codeweavers.com
Thu Dec 3 11:27:10 CST 2009


On Dec 2, 2009, at 11:25 PM, Gert van den Berg wrote:

> What I meant is that LC_* (not LC_ALL) don't have a setting that says
> "the locale is say en_ZA" it only has we have number (LC_NUMERIC) from
> en_ZA, times (LC_TIME) from en_UK, sort things (LC_COLLATE) according
> to en_AU, determine whether something is a letter / number and how to
> change their case (LC_CTYPE) according to UTF-8, ect. LANG is only
> setting that really maps to Wine / Windows' sCountry and Locale
> settings. (if all LC_* variables are set, LANG only determine things
> not in any of the LC_* variables) LC_* does not have anything to
> determine the actual UI language either.
> 
> What I meant above, is that you should be able to get the equivalent
> effect (to the POSIX default) by setting everything to LANG's setting
> and then changing them from the LC_* variables. E.g. if LANG is fr_FR
> (not sure if that is an actual name) and LC_TIME is en_US, set
> environment up for French, change settings affected by LC_TIME to US
> English. Setting LANG to French and all individual settings to en_US,
> shoulld reslut in a system where the country is France, Locale code is
> 0x040c, UI is French, but date / time / number / currency settings,
> etc. is that of en_US.

I don't think that setting LC_ALL (or LANG) has any meaning beyond what one gets from the individual LC_* variables, but I could be mistaken.

I understand that you're suggesting it should or that you can imagine a semantic meaning to setting all of the LC_* variables to one thing and LANG to another, but I don't think it actually works that way.

In other words, I don't believe the C library has any notion of "the locale is en_ZA" in the sense you mean.  It only has the various categories.

Currently, Wine uses the LC_MESSAGES category to determine sCountry and Locale.


> Considering how OS X seem to set variables, that might work as well...
> My interpretation of your proposed logic for OS X: Set up everything
> to OS X setting, overwrite everything if LANG is set, overwrite
> further settings from LC_*, overwrite everything from LC_ALL if that
> is set. (the slow unoptimized way that might result in some settings
> being overwritten 4 times before settling on a value...)
> 
> Resulting order:
> LC_ALL
> LC_*
> LANG
> OS X settings.

That's not quite what I proposed.  I propose the following (in pseudocode):

mac_formats_locale = CFLocaleGetIdentifier( CFLocaleCopyCurrent() );
mac_language = CFArrayGetValueAtIndex( CFBundleCopyLocalizationsForPreferences( CFLocaleCopyAvailableLocaleIdentifiers(), NULL ), 0 );
for cat in ( LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_PAPER, LC_MEASUREMENT, LC_TELEPHONE )
	setenv( cat, mac_formats_locale, 0 );
setenv( "LC_MESSAGES", mac_language, 0 );

The 0 as the third argument to setenv() means don't replace any existing definition.  In this way, any LC_* environment variables set in the original environment would take precedence over the System Preferences settings.  (LC_PAPER, LC_MEASUREMENT, and LC_TELEPHONE would only be used if actually defined, which they currently aren't on Mac OS X.)

The above would all precede the call to setlocale( LC_ALL, "" ) so that it would influence how the C library locale gets initialized.  We would remove the post-setlocale override of lcid_LC_MESSAGES.

This results in the order I previously described:

LC_ALL
LC_* from the original environment
Mac OS X settings
LANG

The Mac OS X settings have to take precedence over LANG for the reasons I've previously described.  (Terminal.app sets it automatically to a value that doesn't/can't quite represent the user's actual preferences.  As it happens, Terminal.app isn't doing this for you because Mac OS X doesn't support en_ZA in the Unix locale definitions in /usr/share/locale.)


>> As near as I can tell, Wine only probes the locale information by invoking
>> setlocale(<category>, NULL).  It doesn't directly examine the environment
>> variables.  Furthermore, it only queries using the individual categories,
>> not LC_ALL.  It uses setlocale(LC_ALL, "") once to tell the C library to
>> initialize itself from the environment.
>> 
>> So, I'm not sure how setting all of the LC_* variables to a given value can
>> be different from setting LC_ALL to that value.
>> 
> 
> Interpreting it as above, settings LC_ALL is equivalent to setting all
> LC_ variables and setting LANG to LC_ALL's value.

No.  LANG is irrelevant if all LC_* variables are set.  It's only use is to supply the locale for a category if LC_ALL or the specific LC_whatever is not set.  If you set all of the LC_whatevers, then LANG is unused.

Regards,
Ken




More information about the wine-devel mailing list