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

Ken Thomases ken at codeweavers.com
Wed Dec 9 10:44:50 CST 2009

On Dec 8, 2009, at 6:39 AM, <Joerg-Cyril.Hoehle at t-systems.com> <Joerg-Cyril.Hoehle at t-systems.com 
 > wrote:

> Ken Thomases wrote:
>> This results in the order I previously described:
>> LC_* from the original environment
>> Mac OS X settings
> In other words, LANG is completely ignored, since there presumably  
> won't
> be a Mac without settings.

Correct.  LANG is unreliable because Terminal.app can set it without  
the user's knowledge to a value that doesn't reflect the user's  

> I thought that was current behaviour.

Nope.  Currently LANG, if set, supersedes the Mac OS X settings,  
except for LC_MESSAGES which is treated oddly.

> The only point of dissension is about LANG.  What you propose is
> closer to POSIX than what's current, so it's still progress, even  
> though
> it both violates POSIX and deviates from Wine's behaviour on Linux.

It deviates from LINUX because LINUX doesn't have any mechanism (as  
far as I know) other than LC_ALL, LC_*, and LANG to express the user's  
preferences.  Mac OS X does.  I have argued (probably past the point  
of anybody caring) that it makes sense to consider the Mac OS X  
settings as though they were stored in the LC_* variables (with the  
user able to override them by manually setting LC_* or LC_ALL).  If  
you grant this assumption, then the behavior does follow what Wine  
does on Linux.  That is, if a Linux user has LC_* variables set to  
express their preferences, then those take precedence over LANG.

> Hmm, thinking about your pseudo-code (not quoted here), I'm not sure
> that
> implements the "LC_ALL takes priority over LC_xyz" correctly, does it?

My pseudocode only sets environment variables (if they aren't already  
set).  The precedence is implemented by the C library in how it  
handles the various environment variables during setlocale(LC_ALL,  
"").  If LC_ALL is set in the environment, then it takes precedence  
over the LC_* and LANG variables, in which case the stuff we do to  
translate the Mac OS X settings to the LC_* variables is ignored  
(appropriately).  Then, Wine takes its cues from the C library.

> Also, it omits the mapping that Bruno Haible hinted at:
>    "Note that these [MacOS X]
>     settings are similar but not entirely equal to Unix (glibc)
>     conventions (e.g. "zh-Hans" vs. "zh_CN"), therefore some mapping  
> of
>     names has to be done."

"zh-Hans" doesn't specify a country, so it would actually map to just  
"zh".  (Which, by the way, the Mac C library rejects because it  
doesn't have a proper locale definition in /usr/share/locale.  So,  
even if we performed the mapping, it wouldn't buy us anything in this  

In my testing, if you set your Mac OS X formats region to one of  
China, Taiwan, or Hong Kong, then  
CFLocaleGetIdentifier( CFLocaleCopyCurrent() ) produces a value that  
the C library would understand: zh_CN, zh_TW, or zh_HK.  If you  
customize your formats, it may add stuff like @currency=USD to the end  
of that, which the C library chokes on, so we have to strip it off.   
(The current Wine code already does this.)

Admittedly, you can probably get different results in a few ways.  For  
example, I queried the available locale identifiers with  
CFLocaleCopyAvailableLocaleIdentifiers(), created a CFLocaleRef from  
each locale ID, and then probed those.  That list contains some  
Chinese locales without a country, and CFLocaleGetIdentifier() on one  
of those CFLocaleRefs can produce results like "zh-Hans".  I'm  
attaching the output of my locale dumping program.

It may be safest to not use CFLocaleGetIdentifier(), but rather format  
our own locale string by doing, effectively:

	CFLocaleRef locale = CFLocaleCopyCurrent();
	CFStringRef country = CFLocaleGetValue(locale, kCFLocaleCountryCode);
	CFStringRef localeString;
	if (country)
		localeString = CFStringCreateWithFormat(NULL, NULL, @"%s_%s.UTF-8",
			CFLocaleGetValue(locale, kCFLocaleLanguageCode),
		localeString = CFStringCreateWithFormat(NULL, NULL, @"%s.UTF-8",
			CFLocaleGetValue(locale, kCFLocaleLanguageCode));

This avoids the need for the stripping of modifiers that the C library  
doesn't handle.  It also takes care of specifying ".UTF-8" in a more  
straightforward manner than the current Wine code.  Unfortunately, it  
throws away a lot of available information, but that's a consequence  
of using the C library as a middleman between Mac OS X and the Win32  
world.  In the long run, it would be better for Wine to directly use  
the Mac APIs rather than relying on the C library.

A patch to implement this approach (the one still relying on the C  
library) will be forthcoming.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: mac_locales_dump.txt.bz2
Type: application/x-bzip2
Size: 6571 bytes
Desc: not available
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20091209/4d351b68/attachment-0001.bin>
-------------- next part --------------

More information about the wine-devel mailing list