On macOS 10.13.4, the locale name returned by gl_locale_name_default() is wrong when two or more preferred languages are specified in the system preferences. Namely, it returns, e.g. for me in Germany, "en_DE" instead of the expected "de_DE" (where the language is the first preferred language).
This is caused by an unexpected behaviour of CFLocaleCopyCurrent(). It may be the same bug as the one mentioned here: - for macOS: <https://stackoverflow.com/questions/45189185/regarding-cflocalecopycurrent-api-incorrect-return-value> - for iOS: <https://openradar.appspot.com/34581827> <https://bugzilla.xamarin.com/show_bug.cgi?id=59596#c3> <https://bugreports.qt.io/browse/QTBUG-63324> The fix is to use the older API instead, which still returns the expected locale name. 2019-05-19 Bruno Haible <br...@clisp.org> localename: Fix default on macOS. * m4/intlmacosx.m4 (gt_INTL_MACOSX): Don't test for CFLocaleCopyCurrent. * lib/localename.c: Remove includes for HAVE_CFLOCALECOPYCURRENT. (gl_locale_name_environ, gl_locale_name_default): Remove code for HAVE_CFLOCALECOPYCURRENT. * lib/localename.h (gl_locale_name_default): Update. diff --git a/m4/intlmacosx.m4 b/m4/intlmacosx.m4 index 30e6f50..3495174 100644 --- a/m4/intlmacosx.m4 +++ b/m4/intlmacosx.m4 @@ -1,4 +1,4 @@ -# intlmacosx.m4 serial 6 (gettext-0.20) +# intlmacosx.m4 serial 7 (gettext-0.20.2) dnl Copyright (C) 2004-2014, 2016, 2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -33,21 +33,15 @@ AC_DEFUN([gt_INTL_MACOSX], AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], [1], [Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) fi - dnl Check for API introduced in Mac OS X 10.5. - AC_CACHE_CHECK([for CFLocaleCopyCurrent], [gt_cv_func_CFLocaleCopyCurrent], - [gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[#include <CoreFoundation/CFLocale.h>]], - [[CFLocaleCopyCurrent();]])], - [gt_cv_func_CFLocaleCopyCurrent=yes], - [gt_cv_func_CFLocaleCopyCurrent=no]) - LIBS="$gt_save_LIBS"]) - if test $gt_cv_func_CFLocaleCopyCurrent = yes; then - AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], [1], - [Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) - fi + dnl Don't check for the API introduced in Mac OS X 10.5, CFLocaleCopyCurrent, + dnl because in macOS 10.13.4 it has the following behaviour: + dnl When two or more languages are specified in the + dnl "System Preferences > Language & Region > Preferred Languages" panel, + dnl it returns en_CC where CC is the territory (even when English is not among + dnl the preferred languages!). What we want instead is what + dnl CFLocaleCopyCurrent returned in earlier macOS releases and what + dnl CFPreferencesCopyAppValue still returns, namely ll_CC where ll is the + dnl first among the preferred languages and CC is the territory. AC_CACHE_CHECK([for CFLocaleCopyPreferredLanguages], [gt_cv_func_CFLocaleCopyPreferredLanguages], [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" @@ -64,7 +58,6 @@ AC_DEFUN([gt_INTL_MACOSX], fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes \ - || test $gt_cv_func_CFLocaleCopyCurrent = yes \ || test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi diff --git a/lib/localename.c b/lib/localename.c index 1b1bb19..b6b94c2 100644 --- a/lib/localename.c +++ b/lib/localename.c @@ -66,13 +66,9 @@ extern char * getlocalename_l(int, locale_t); # endif #endif -#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE +#if HAVE_CFPREFERENCESCOPYAPPVALUE # include <CoreFoundation/CFString.h> -# if HAVE_CFLOCALECOPYCURRENT -# include <CoreFoundation/CFLocale.h> -# elif HAVE_CFPREFERENCESCOPYAPPVALUE -# include <CoreFoundation/CFPreferences.h> -# endif +# include <CoreFoundation/CFPreferences.h> #endif #if defined _WIN32 && !defined __CYGWIN__ @@ -1156,7 +1152,7 @@ extern char * getlocalename_l(int, locale_t); #endif -#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE +#if HAVE_CFPREFERENCESCOPYAPPVALUE /* Mac OS X 10.4 or newer */ /* Canonicalize a Mac OS X locale name to a Unix locale name. @@ -3326,7 +3322,7 @@ gl_locale_name_environ (int category, const char *categoryname) retval = getenv ("LANG"); if (retval != NULL && retval[0] != '\0') { -#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE +#if HAVE_CFPREFERENCESCOPYAPPVALUE /* Mac OS X 10.2 or newer. Ignore invalid LANG value set by the Terminal application. */ if (strcmp (retval, "UTF-8") != 0) @@ -3373,7 +3369,7 @@ gl_locale_name_default (void) "C.UTF-8" locale, which operates in the same way as the "C" locale. */ -#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined WINDOWS_NATIVE || defined __CYGWIN__) +#if !(HAVE_CFPREFERENCESCOPYAPPVALUE || defined WINDOWS_NATIVE || defined __CYGWIN__) /* The system does not have a way of setting the locale, other than the POSIX specified environment variables. We use C as default locale. */ @@ -3386,8 +3382,17 @@ gl_locale_name_default (void) context, because message catalogs are not specific to a single codeset. */ -# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE +# if HAVE_CFPREFERENCESCOPYAPPVALUE /* Mac OS X 10.4 or newer */ + /* Don't use the API introduced in Mac OS X 10.5, CFLocaleCopyCurrent, + because in macOS 10.13.4 it has the following behaviour: + When two or more languages are specified in the + "System Preferences > Language & Region > Preferred Languages" panel, + it returns en_CC where CC is the territory (even when English is not among + the preferred languages!). What we want instead is what + CFLocaleCopyCurrent returned in earlier macOS releases and what + CFPreferencesCopyAppValue still returns, namely ll_CC where ll is the + first among the preferred languages and CC is the territory. */ { /* Cache the locale name, since CoreFoundation calls are expensive. */ static const char *cached_localename; @@ -3395,17 +3400,12 @@ gl_locale_name_default (void) if (cached_localename == NULL) { char namebuf[256]; -# if HAVE_CFLOCALECOPYCURRENT /* Mac OS X 10.5 or newer */ - CFLocaleRef locale = CFLocaleCopyCurrent (); - CFStringRef name = CFLocaleGetIdentifier (locale); -# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* Mac OS X 10.4 or newer */ CFTypeRef value = CFPreferencesCopyAppValue (CFSTR ("AppleLocale"), kCFPreferencesCurrentApplication); if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ()) { CFStringRef name = (CFStringRef)value; -# endif if (CFStringGetCString (name, namebuf, sizeof (namebuf), kCFStringEncodingASCII)) @@ -3413,12 +3413,7 @@ gl_locale_name_default (void) gl_locale_name_canonicalize (namebuf); cached_localename = strdup (namebuf); } - -# if HAVE_CFLOCALECOPYCURRENT /* Mac OS X 10.5 or newer */ - CFRelease (locale); -# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* Mac OS X 10.4 or newer */ } -# endif if (cached_localename == NULL) cached_localename = "C"; } diff --git a/lib/localename.h b/lib/localename.h index 071248a..c0839b8 100644 --- a/lib/localename.h +++ b/lib/localename.h @@ -86,8 +86,7 @@ extern const char * gl_locale_name_environ (int category, const char *categoryna The result must not be freed; it is statically allocated. */ extern const char * gl_locale_name_default (void) -#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE \ - || defined _WIN32 || defined __CYGWIN__) +#if !(HAVE_CFPREFERENCESCOPYAPPVALUE || defined _WIN32 || defined __CYGWIN__) _GL_ATTRIBUTE_CONST #endif ;