From 6642aeb47aee3d82978a27497dc9ca57058c66b4 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 16 Sep 2018 19:12:44 +0200 Subject: [PATCH] setlocale: Improve locale handling on macOS 10.12 or newer. * lib/setlocale.c: Include header files for CoreFoundation. Declare gl_locale_name_canonicalize. (libintl_setlocale): Try harder to set a locale for categories LC_CTYPE and LC_MESSAGES. * m4/setlocale.m4 (gl_PREREQ_SETLOCALE): Add comment. --- ChangeLog | 9 ++++++ lib/setlocale.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- m4/setlocale.m4 | 5 ++- 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5fb9682595..51608264a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2018-09-16 Bruno Haible + setlocale: Improve locale handling on macOS 10.12 or newer. + * lib/setlocale.c: Include header files for CoreFoundation. Declare + gl_locale_name_canonicalize. + (libintl_setlocale): Try harder to set a locale for categories LC_CTYPE + and LC_MESSAGES. + * m4/setlocale.m4 (gl_PREREQ_SETLOCALE): Add comment. + +2018-09-16 Bruno Haible + Update list of locale names with scripts on macOS. * lib/localename.c (gl_locale_name_canonicalize): Update tables to match Mac OS X 10.13 and recent glibc. diff --git a/lib/setlocale.c b/lib/setlocale.c index 77bdabab46..63f870f1df 100644 --- a/lib/setlocale.c +++ b/lib/setlocale.c @@ -35,6 +35,18 @@ #include "localename.h" +#if HAVE_CFLOCALECOPYPREFERREDLANGUAGES || HAVE_CFPREFERENCESCOPYAPPVALUE +# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES +# include +# elif HAVE_CFPREFERENCESCOPYAPPVALUE +# include +# endif +# include +# include +# include +extern void gl_locale_name_canonicalize (char *name); +#endif + #if 1 # undef setlocale @@ -892,14 +904,81 @@ rpl_setlocale (int category, const char *locale) ) if (setlocale_single (cat, name) == NULL) # if defined __APPLE__ && defined __MACH__ - /* On Mac OS X 10.13, some locales can be set through - System Preferences > Language & Region, that are not - supported by libc. The system's setlocale() falls - back to "C" for these locale categories. Let's do the - same, but print a warning, to limit user expectations. */ - fprintf (stderr, - "Warning: Failed to set locale category %s to %s.\n", - category_to_name (cat), name); + { + /* On Mac OS X 10.13, some locales can be set through + System Preferences > Language & Region, that are not + supported by libc. The system's setlocale() falls + back to "C" for these locale categories. We can possibly + do better. If we can't, print a warning, to limit user + expectations. */ + int warn = 1; + + if (cat == LC_CTYPE) + warn = (setlocale_single (cat, "UTF-8") == NULL); +# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES || HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */ + else if (cat == LC_MESSAGES) + { + /* Take the primary language preference. */ +# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* MacOS X 10.5 or newer */ + CFArrayRef prefArray = CFLocaleCopyPreferredLanguages (); +# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */ + CFTypeRef preferences = + CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"), + kCFPreferencesCurrentApplication); + if (preferences != NULL + && CFGetTypeID (preferences) == CFArrayGetTypeID ()) + { + CFArrayRef prefArray = (CFArrayRef)preferences; +# endif + int n = CFArrayGetCount (prefArray); + if (n > 0) + { + char buf[256]; + CFTypeRef element = CFArrayGetValueAtIndex (prefArray, 0); + if (element != NULL + && CFGetTypeID (element) == CFStringGetTypeID () + && CFStringGetCString ((CFStringRef)element, + buf, sizeof (buf), + kCFStringEncodingASCII)) + { + /* Remove the country. + E.g. "zh-Hans-DE" -> "zh-Hans". */ + char *last_minus = strrchr (buf, '-'); + if (last_minus != NULL) + *last_minus = '\0'; + + /* Convert to Unix locale name. + E.g. "zh-Hans" -> "zh_CN". */ + gl_locale_name_canonicalize (buf); + + /* Try setlocale with this value. */ + warn = (setlocale_single (cat, buf) == NULL); + } + } +# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* MacOS X 10.5 or newer */ + CFRelease (prefArray); +# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */ + } +# endif + } +# endif + /* No fallback possible for LC_NUMERIC. The application + should use the locale properties + kCFLocaleDecimalSeparator, kCFLocaleGroupingSeparator. + No fallback possible for LC_TIME. The application should + use the locale property kCFLocaleCalendarIdentifier. + No fallback possible for LC_COLLATE. The application + should use the locale properties + kCFLocaleCollationIdentifier, kCFLocaleCollatorIdentifier. + No fallback possible for LC_MONETARY. The application + should use the locale properties + kCFLocaleCurrencySymbol, kCFLocaleCurrencyCode. */ + + if (warn) + fprintf (stderr, + "Warning: Failed to set locale category %s to %s.\n", + category_to_name (cat), name); + } # else goto fail; # endif diff --git a/m4/setlocale.m4 b/m4/setlocale.m4 index 802ee01fa9..e0fb74a92d 100644 --- a/m4/setlocale.m4 +++ b/m4/setlocale.m4 @@ -1,4 +1,4 @@ -# setlocale.m4 serial 4 +# setlocale.m4 serial 5 dnl Copyright (C) 2011-2018 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -25,5 +25,8 @@ AC_DEFUN([gl_FUNC_SETLOCALE], # Prerequisites of lib/setlocale.c. AC_DEFUN([gl_PREREQ_SETLOCALE], [ + dnl No need to check for CFLocaleCopyPreferredLanguages and + dnl CFPreferencesCopyAppValue because lib/setlocale.c is not used on Mac OS X. + dnl (The Mac OS X specific code is only used in libintl.) : ]) -- 2.11.4.GIT