kernel32: Allow the prefered language to be different from the prefered locale on Mac OS X. [take2]

Pierre d'Herbemont pdherbemont at free.fr
Mon Dec 11 18:38:42 CST 2006


Same with Ken's memory fixes and CFBundleCopyLocalizationsForPreferences
simplification.

It was probably unclear with the previous patch but we have to scan 
/usr/share/locale in order to get locale name that are accepted by 
setlocale.

Using the CFLocale API way only, will fail since we may end up with two 
letters language name like 'en' or 'es' and setlocale fails to 
understand them, thus returns "C".

So we have to fed up setlocale with long locale name like 'en_US' or 
'es_ES'.

Pierre.
---
   dlls/kernel32/locale.c |   53
+++++++++++++++++++++++++++++++++++++++++++++++-
   1 files changed, 52 insertions(+), 1 deletions(-)

-------------- next part --------------
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 8792623..3aa7146 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -31,9 +31,13 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <stdlib.h>
+#include <sys/types.h>
+#include <sys/dir.h>
 
 #ifdef __APPLE__
+# include <CoreFoundation/CFBundle.h>
 # include <CoreFoundation/CFLocale.h>
+# include <CoreFoundation/CFPreferences.h>
 # include <CoreFoundation/CFString.h>
 #endif
 
@@ -2822,7 +2826,12 @@ void LOCALE_Init(void)
 
 #ifdef __APPLE__
     /* MacOS doesn't set the locale environment variables so we have to do it ourselves */
+    CFMutableArrayRef available_locales;
+    CFArrayRef intersected_locales;
     char user_locale[50];
+    struct direct *file;
+    DIR *dir;
+
     CFLocaleRef user_locale_ref = CFLocaleCopyCurrent();
     CFStringRef user_locale_string_ref = CFLocaleGetIdentifier( user_locale_ref );
 
@@ -2832,7 +2841,49 @@ void LOCALE_Init(void)
     unix_cp = CP_UTF8;  /* default to utf-8 even if we don't get a valid locale */
     setenv( "LANG", user_locale, 0 );
     TRACE( "setting locale to '%s'\n", user_locale );
-#endif
+
+    /* We still want to set the LC_MESSAGES env to what is the prefered language in
+       System Preferences.app, because it can differ from CFLocaleCopyCurrent().
+
+       However this prefered language is stored using the general language denotation
+       that may not include the country code (en,fr,en-GB,...) which is not accepted
+       by setlocale (setlocale would expect en_US,fr_FR,en_GB,...).
+
+       So we retrieve possible locales from /usr/share/locale and intersect them
+       with the prefered languages using CFBundleCopyLocalizationsForPreferences. */
+    dir = opendir("/usr/share/locale");
+    available_locales = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+    while ((file = readdir(dir)))
+    {
+        CFStringRef fname = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault,
+                                                            file->d_name);
+        /* This filters the 'right' locales (xx_xx.UTF-8) */
+        if (strstr(file->d_name, ".UTF-8"))
+            CFArrayAppendValue(available_locales, (void*)fname);
+        CFRelease(fname);
+    }
+    closedir(dir);
+
+    intersected_locales = CFBundleCopyLocalizationsForPreferences(available_locales, NULL);
+    if(intersected_locales)
+    {
+        CFStringRef user_language = NULL;
+
+        if(CFArrayGetCount(intersected_locales))
+            user_language = CFArrayGetValueAtIndex(intersected_locales, 0);
+
+        if(user_language)
+        {
+            CFStringGetCString( user_language, user_locale, sizeof(user_locale), kCFStringEncodingUTF8 );
+            TRACE( "setting LC_MESSAGES to '%s'\n", user_locale );
+            setenv( "LC_MESSAGES", user_locale, 0 );
+        }
+        CFRelease(intersected_locales);
+    }
+    CFRelease(available_locales);
+#endif /* __APPLE__ */
+
     setlocale( LC_ALL, "" );
 
     unix_cp = setup_unix_locales();


More information about the wine-patches mailing list