[glib] g_date_time_format: Support nominative/genitive months



commit be4f96b6502c01d2a51d60b7a669c8ef82e22a4d
Author: Rafal Luzynski <digitalfreak lingonborough com>
Date:   Fri Mar 24 11:19:13 2017 +0100

    g_date_time_format: Support nominative/genitive months
    
    Supports %OB (alternative, standalone, nominative) month name along
    with the old %B (primary, in a complete date format context, genitive)
    month name.  Similarly %Ob and %Oh for abbreviated month names.
    Depending on the underlying operating system uses nl_langinfo()
    or provides our custom implementation.
    
    (Tweaked by Philip Withnall <withnall endlessm com> to add test case
    comment and bug reference.)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=749206

 configure.ac           |  44 ++++++++++
 glib/gdatetime.c       | 234 +++++++++++++++++++++++++++++++++++++++++++++++--
 glib/tests/gdatetime.c | 148 +++++++++++++++++++++++++++++++
 meson.build            |  48 ++++++++++
 4 files changed, 467 insertions(+), 7 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d460c9b18..5dcdb79a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1274,6 +1274,50 @@ AC_CACHE_CHECK([for nl_langinfo (_NL_CTYPE_OUTDIGITn_MB)], glib_cv_langinfo_outd
 if test x$glib_cv_langinfo_outdigit = xyes; then
   AC_DEFINE(HAVE_LANGINFO_OUTDIGIT,1,[Have nl_langinfo (_NL_CTYPE_OUTDIGITn_MB)])
 fi
+
+dnl Check for nl_langinfo and ALTMON_n
+AC_CACHE_CHECK([for nl_langinfo (ALTMON_n)], glib_cv_langinfo_altmon,[
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <langinfo.h>],
+                [char *str;
+                 str = nl_langinfo (ALTMON_1);
+                 str = nl_langinfo (ALTMON_2);
+                 str = nl_langinfo (ALTMON_3);
+                 str = nl_langinfo (ALTMON_4);
+                 str = nl_langinfo (ALTMON_5);
+                 str = nl_langinfo (ALTMON_6);
+                 str = nl_langinfo (ALTMON_7);
+                 str = nl_langinfo (ALTMON_8);
+                 str = nl_langinfo (ALTMON_9);
+                 str = nl_langinfo (ALTMON_10);
+                 str = nl_langinfo (ALTMON_11);
+                 str = nl_langinfo (ALTMON_12);])],
+                [glib_cv_langinfo_altmon=yes],
+                [glib_cv_langinfo_altmon=no])])
+if test x$glib_cv_langinfo_altmon = xyes; then
+  AC_DEFINE(HAVE_LANGINFO_ALTMON,1,[Have nl_langinfo (ALTMON_n)])
+fi
+
+dnl Check for nl_langinfo and _NL_ABALTMON_n
+AC_CACHE_CHECK([for nl_langinfo (_NL_ABALTMON_n)], glib_cv_langinfo_abaltmon,[
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <langinfo.h>],
+                [char *str;
+                 str = nl_langinfo (_NL_ABALTMON_1);
+                 str = nl_langinfo (_NL_ABALTMON_2);
+                 str = nl_langinfo (_NL_ABALTMON_3);
+                 str = nl_langinfo (_NL_ABALTMON_4);
+                 str = nl_langinfo (_NL_ABALTMON_5);
+                 str = nl_langinfo (_NL_ABALTMON_6);
+                 str = nl_langinfo (_NL_ABALTMON_7);
+                 str = nl_langinfo (_NL_ABALTMON_8);
+                 str = nl_langinfo (_NL_ABALTMON_9);
+                 str = nl_langinfo (_NL_ABALTMON_10);
+                 str = nl_langinfo (_NL_ABALTMON_11);
+                 str = nl_langinfo (_NL_ABALTMON_12);])],
+                [glib_cv_langinfo_abaltmon=yes],
+                [glib_cv_langinfo_abaltmon=no])])
+if test x$glib_cv_langinfo_abaltmon = xyes; then
+  AC_DEFINE(HAVE_LANGINFO_ABALTMON,1,[Have nl_langinfo (_NL_ABALTMON_n)])
+fi
 AC_LANG_RESTORE
 
 dnl ****************************************
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 4bb13d1da..85359ac00 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -46,6 +46,11 @@
 
 #include "config.h"
 
+/* langinfo.h in glibc 2.27 defines ALTMON_* only if _GNU_SOURCE is defined.  */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -212,15 +217,37 @@ static const gint month_item[2][12] =
 
 #define WEEKDAY_ABBR(d)       (get_weekday_name_abbr (g_date_time_get_day_of_week (d)))
 #define WEEKDAY_FULL(d)       (get_weekday_name (g_date_time_get_day_of_week (d)))
-#define MONTH_ABBR(d)         (get_month_name_abbr (g_date_time_get_month (d)))
-#define MONTH_FULL(d)         (get_month_name (g_date_time_get_month (d)))
+/* We don't yet know if nl_langinfo (MON_n) returns standalone or complete-date
+ * format forms but if nl_langinfo (ALTMON_n) is not supported then we will
+ * have to use MONTH_FULL as standalone.  The same if nl_langinfo () does not
+ * exist at all.  MONTH_ABBR is similar: if nl_langinfo (_NL_ABALTMON_n) is not
+ * supported then we will use MONTH_ABBR as standalone.
+ */
+#define MONTH_ABBR(d)         (get_month_name_abbr_standalone (g_date_time_get_month (d)))
+#define MONTH_FULL(d)         (get_month_name_standalone (g_date_time_get_month (d)))
 
 static const gchar *
-get_month_name (gint month)
+get_month_name_standalone (gint month)
 {
   switch (month)
     {
     case 1:
+      /* Translators: Some languages (Baltic, Slavic, Greek, and some more)
+       * need different grammatical forms of month names depending on whether
+       * they are standalone or in a complete date context, with the day
+       * number.  Some other languages may prefer starting with uppercase when
+       * they are standalone and with lowercase when they are in a complete
+       * date context.  Here are full month names in a form appropriate when
+       * they are used standalone.  If your system is Linux with the glibc
+       * version 2.27 (released Feb 1, 2018) or newer or if it is from the BSD
+       * family (which includes OS X) then you can refer to the date command
+       * line utility and see what the command `date +%OB' produces.  Also in
+       * the latest Linux the command `locale alt_mon' in your native locale
+       * produces a complete list of month names almost ready to copy and
+       * paste here.  Note that in most of the languages (western European,
+       * non-European) there is no difference between the standalone and
+       * complete date form.
+       */
       return C_("full month name", "January");
     case 2:
       return C_("full month name", "February");
@@ -253,11 +280,28 @@ get_month_name (gint month)
 }
 
 static const gchar *
-get_month_name_abbr (gint month)
+get_month_name_abbr_standalone (gint month)
 {
   switch (month)
     {
     case 1:
+      /* Translators: Some languages need different grammatical forms of
+       * month names depending on whether they are standalone or in a complete
+       * date context, with the day number.  Some may prefer starting with
+       * uppercase when they are standalone and with lowercase when they are
+       * in a full date context.  However, as these names are abbreviated
+       * the grammatical difference is visible probably only in Belarusian
+       * and Russian.  In other languages there is no difference between
+       * the standalone and complete date form when they are abbreviated.
+       * If your system is Linux with the glibc version 2.27 (released
+       * Feb 1, 2018) or newer then you can refer to the date command line
+       * utility and see what the command `date +%Ob' produces.  Also in
+       * the latest Linux the command `locale ab_alt_mon' in your native
+       * locale produces a complete list of month names almost ready to copy
+       * and paste here.  Note that this feature is not yet supported by any
+       * other platform.  Here are abbreviated month names in a form
+       * appropriate when they are used standalone.
+       */
       return C_("abbreviated month name", "Jan");
     case 2:
       return C_("abbreviated month name", "Feb");
@@ -345,6 +389,171 @@ get_weekday_name_abbr (gint day)
 
 #endif  /* HAVE_LANGINFO_TIME */
 
+#ifdef HAVE_LANGINFO_ALTMON
+
+/* If nl_langinfo () supports ALTMON_n then MON_n returns full date format
+ * forms and ALTMON_n returns standalone forms.
+ */
+
+#define MONTH_FULL_WITH_DAY(d) MONTH_FULL(d)
+
+static const gint alt_month_item[12] =
+{
+  ALTMON_1, ALTMON_2, ALTMON_3, ALTMON_4, ALTMON_5, ALTMON_6,
+  ALTMON_7, ALTMON_8, ALTMON_9, ALTMON_10, ALTMON_11, ALTMON_12
+};
+
+#define MONTH_FULL_STANDALONE(d) nl_langinfo (alt_month_item[g_date_time_get_month (d) - 1])
+
+#else
+
+/* If nl_langinfo () does not support ALTMON_n then either MON_n returns
+ * standalone forms or nl_langinfo (MON_n) does not work so we have defined
+ * it as standalone form.
+ */
+
+#define MONTH_FULL_STANDALONE(d) MONTH_FULL(d)
+#define MONTH_FULL_WITH_DAY(d) (get_month_name_with_day (g_date_time_get_month (d)))
+
+static const gchar *
+get_month_name_with_day (gint month)
+{
+  switch (month)
+    {
+    case 1:
+      /* Translators: Some languages need different grammatical forms of
+       * month names depending on whether they are standalone or in a full
+       * date context, with the day number.  Some may prefer starting with
+       * uppercase when they are standalone and with lowercase when they are
+       * in a full date context.  Here are full month names in a form
+       * appropriate when they are used in a full date context, with the
+       * day number.  If your system is Linux with the glibc version 2.27
+       * (released Feb 1, 2018) or newer or if it is from the BSD family
+       * (which includes OS X) then you can refer to the date command line
+       * utility and see what the command `date +%B' produces.  Also in
+       * the latest Linux the command `locale mon' in your native locale
+       * produces a complete list of month names almost ready to copy and
+       * paste here.  In older Linux systems due to a bug the result is
+       * incorrect in some languages.  Note that in most of the languages
+       * (western European, non-European) there is no difference between the
+       * standalone and complete date form.
+       */
+      return C_("full month name with day", "January");
+    case 2:
+      return C_("full month name with day", "February");
+    case 3:
+      return C_("full month name with day", "March");
+    case 4:
+      return C_("full month name with day", "April");
+    case 5:
+      return C_("full month name with day", "May");
+    case 6:
+      return C_("full month name with day", "June");
+    case 7:
+      return C_("full month name with day", "July");
+    case 8:
+      return C_("full month name with day", "August");
+    case 9:
+      return C_("full month name with day", "September");
+    case 10:
+      return C_("full month name with day", "October");
+    case 11:
+      return C_("full month name with day", "November");
+    case 12:
+      return C_("full month name with day", "December");
+
+    default:
+      g_warning ("Invalid month number %d", month);
+    }
+
+  return NULL;
+}
+
+#endif  /* HAVE_LANGINFO_ALTMON */
+
+#ifdef HAVE_LANGINFO_ABALTMON
+
+/* If nl_langinfo () supports _NL_ABALTMON_n then ABMON_n returns full
+ * date format forms and _NL_ABALTMON_n returns standalone forms.
+ */
+
+#define MONTH_ABBR_WITH_DAY(d) MONTH_ABBR(d)
+
+static const gint ab_alt_month_item[12] =
+{
+  _NL_ABALTMON_1, _NL_ABALTMON_2, _NL_ABALTMON_3, _NL_ABALTMON_4,
+  _NL_ABALTMON_5, _NL_ABALTMON_6, _NL_ABALTMON_7, _NL_ABALTMON_8,
+  _NL_ABALTMON_9, _NL_ABALTMON_10, _NL_ABALTMON_11, _NL_ABALTMON_12
+};
+
+#define MONTH_ABBR_STANDALONE(d) nl_langinfo (ab_alt_month_item[g_date_time_get_month (d) - 1])
+
+#else
+
+/* If nl_langinfo () does not support _NL_ABALTMON_n then either ABMON_n
+ * returns standalone forms or nl_langinfo (ABMON_n) does not work so we
+ * have defined it as standalone form. Now it's time to swap.
+ */
+
+#define MONTH_ABBR_STANDALONE(d) MONTH_ABBR(d)
+#define MONTH_ABBR_WITH_DAY(d) (get_month_name_abbr_with_day (g_date_time_get_month (d)))
+
+static const gchar *
+get_month_name_abbr_with_day (gint month)
+{
+  switch (month)
+    {
+    case 1:
+      /* Translators: Some languages need different grammatical forms of
+       * month names depending on whether they are standalone or in a full
+       * date context, with the day number.  Some may prefer starting with
+       * uppercase when they are standalone and with lowercase when they are
+       * in a full date context.  Here are abbreviated month names in a form
+       * appropriate when they are used in a full date context, with the
+       * day number.  However, as these names are abbreviated the grammatical
+       * difference is visible probably only in Belarusian and Russian.
+       * In other languages there is no difference between the standalone
+       * and complete date form when they are abbreviated.  If your system
+       * is Linux with the glibc version 2.27 (released Feb 1, 2018) or newer
+       * then you can refer to the date command line utility and see what the
+       * command `date +%b' produces.  Also in the latest Linux the command
+       * `locale abmon' in your native locale produces a complete list of
+       * month names almost ready to copy and paste here.  In other systems
+       * due to a bug the result is incorrect in some languages.
+       */
+      return C_("abbreviated month name with day", "Jan");
+    case 2:
+      return C_("abbreviated month name with day", "Feb");
+    case 3:
+      return C_("abbreviated month name with day", "Mar");
+    case 4:
+      return C_("abbreviated month name with day", "Apr");
+    case 5:
+      return C_("abbreviated month name with day", "May");
+    case 6:
+      return C_("abbreviated month name with day", "Jun");
+    case 7:
+      return C_("abbreviated month name with day", "Jul");
+    case 8:
+      return C_("abbreviated month name with day", "Aug");
+    case 9:
+      return C_("abbreviated month name with day", "Sep");
+    case 10:
+      return C_("abbreviated month name with day", "Oct");
+    case 11:
+      return C_("abbreviated month name with day", "Nov");
+    case 12:
+      return C_("abbreviated month name with day", "Dec");
+
+    default:
+      g_warning ("Invalid month number %d", month);
+    }
+
+  return NULL;
+}
+
+#endif  /* HAVE_LANGINFO_ABALTMON */
+
 /* Format AM/PM indicator if the locale does not have a localized version. */
 static const gchar *
 get_fallback_ampm (gint hour)
@@ -2736,7 +2945,8 @@ g_date_time_format_locale (GDateTime   *datetime,
            }
          break;
        case 'b':
-         name = MONTH_ABBR (datetime);
+         name = alt_digits ? MONTH_ABBR_STANDALONE (datetime)
+                           : MONTH_ABBR_WITH_DAY (datetime);
           if (g_strcmp0 (name, "") == 0)
             return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
@@ -2755,7 +2965,8 @@ g_date_time_format_locale (GDateTime   *datetime,
            }
          break;
        case 'B':
-         name = MONTH_FULL (datetime);
+         name = alt_digits ? MONTH_FULL_STANDALONE (datetime)
+                           : MONTH_FULL_WITH_DAY (datetime);
           if (g_strcmp0 (name, "") == 0)
             return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
@@ -2809,7 +3020,8 @@ g_date_time_format_locale (GDateTime   *datetime,
                         g_date_time_get_week_numbering_year (datetime));
          break;
        case 'h':
-         name = MONTH_ABBR (datetime);
+         name = alt_digits ? MONTH_ABBR_STANDALONE (datetime)
+                           : MONTH_ABBR_WITH_DAY (datetime);
           if (g_strcmp0 (name, "") == 0)
             return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
@@ -3080,6 +3292,14 @@ g_date_time_format_locale (GDateTime   *datetime,
  * - 0: Pad a numeric result with zeros. This overrides the default padding
  *   for the specifier.
  *
+ * Additionally, when O is used with B, b, or h, it produces the alternative
+ * form of a month name. The alternative form should be used when the month
+ * name is used without a day number (e.g., standalone). It is required in
+ * some languages (Baltic, Slavic, Greek, and more) due to their grammatical
+ * rules. For other languages there is no difference. \%OB is a GNU and BSD
+ * strftime() extension expected to be added to the future POSIX specification,
+ * \%Ob and \%Oh are GNU strftime() extensions. Since: 2.56
+ *
  * Returns: a newly allocated string formatted to the requested format
  *     or %NULL in the case that there was an error (such as a format specifier
  *     not being supported in the current locale). The string
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index f22f64654..4f736be34 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -1552,6 +1552,153 @@ test_modifiers (void)
   g_free (oldlocale);
 }
 
+/* Test that the `O` modifier for g_date_time_format() works with %B, %b and %h;
+ * i.e. whether genitive month names are supported. */
+static void
+test_month_names (void)
+{
+  gchar *oldlocale;
+
+  g_test_bug ("749206");
+
+  oldlocale = g_strdup (setlocale (LC_ALL, NULL));
+
+  /* Make sure that nothing has been changed in western European languages.  */
+  setlocale (LC_ALL, "en_GB.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  1,  1,  "%B", "January");
+      TEST_PRINTF_DATE (2018,  2,  1, "%OB", "February");
+      TEST_PRINTF_DATE (2018,  3,  1,  "%b", "Mar");
+      TEST_PRINTF_DATE (2018,  4,  1, "%Ob", "Apr");
+      TEST_PRINTF_DATE (2018,  5,  1,  "%h", "May");
+      TEST_PRINTF_DATE (2018,  6,  1, "%Oh", "Jun");
+    }
+  else
+    g_test_incomplete ("locale en_GB not available, skipping English month names test");
+
+  setlocale (LC_ALL, "de_DE.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  7,  1,  "%B", "Juli");
+      TEST_PRINTF_DATE (2018,  8,  1, "%OB", "August");
+      TEST_PRINTF_DATE (2018,  9,  1,  "%b", "Sep");
+      TEST_PRINTF_DATE (2018, 10,  1, "%Ob", "Okt");
+      TEST_PRINTF_DATE (2018, 11,  1,  "%h", "Nov");
+      TEST_PRINTF_DATE (2018, 12,  1, "%Oh", "Dez");
+    }
+  else
+    g_test_incomplete ("locale de_DE not available, skipping German month names test");
+
+  setlocale (LC_ALL, "es_ES.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "es_ES") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  1,  1,  "%B", "enero");
+      TEST_PRINTF_DATE (2018,  2,  1, "%OB", "febrero");
+      TEST_PRINTF_DATE (2018,  3,  1,  "%b", "mar");
+      TEST_PRINTF_DATE (2018,  4,  1, "%Ob", "abr");
+      TEST_PRINTF_DATE (2018,  5,  1,  "%h", "may");
+      TEST_PRINTF_DATE (2018,  6,  1, "%Oh", "jun");
+    }
+  else
+    g_test_incomplete ("locale es_ES not available, skipping Spanish month names test");
+
+  setlocale (LC_ALL, "fr_FR.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "fr_FR") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  7,  1,  "%B", "juillet");
+      TEST_PRINTF_DATE (2018,  8,  1, "%OB", "août");
+      TEST_PRINTF_DATE (2018,  9,  1,  "%b", "sept.");
+      TEST_PRINTF_DATE (2018, 10,  1, "%Ob", "oct.");
+      TEST_PRINTF_DATE (2018, 11,  1,  "%h", "nov.");
+      TEST_PRINTF_DATE (2018, 12,  1, "%Oh", "déc.");
+    }
+  else
+    g_test_incomplete ("locale fr_FR not available, skipping French month names test");
+
+  /* Make sure that there are visible changes in some European languages.  */
+  setlocale (LC_ALL, "el_GR.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "el_GR") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  1,  1,  "%B", "Ιανουαρίου");
+      TEST_PRINTF_DATE (2018,  2,  1,  "%B", "Φεβρουαρίου");
+      TEST_PRINTF_DATE (2018,  3,  1,  "%B", "Μαρτίου");
+      TEST_PRINTF_DATE (2018,  4,  1, "%OB", "Απρίλιος");
+      TEST_PRINTF_DATE (2018,  5,  1, "%OB", "Μάιος");
+      TEST_PRINTF_DATE (2018,  6,  1, "%OB", "Ιούνιος");
+      TEST_PRINTF_DATE (2018,  7,  1,  "%b", "Ιούλ");
+      TEST_PRINTF_DATE (2018,  8,  1, "%Ob", "Αύγ");
+    }
+  else
+    g_test_incomplete ("locale el_GR not available, skipping Greek month names test");
+
+  setlocale (LC_ALL, "hr_HR.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "hr_HR") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  5,  1,  "%B", "svibnja");
+      TEST_PRINTF_DATE (2018,  6,  1,  "%B", "lipnja");
+      TEST_PRINTF_DATE (2018,  7,  1,  "%B", "srpnja");
+      TEST_PRINTF_DATE (2018,  8,  1, "%OB", "Kolovoz");
+      TEST_PRINTF_DATE (2018,  9,  1, "%OB", "Rujan");
+      TEST_PRINTF_DATE (2018, 10,  1, "%OB", "Listopad");
+      TEST_PRINTF_DATE (2018, 11,  1,  "%b", "Stu");
+      TEST_PRINTF_DATE (2018, 12,  1, "%Ob", "Pro");
+    }
+  else
+    g_test_incomplete ("locale hr_HR not available, skipping Croatian month names test");
+
+  setlocale (LC_ALL, "lt_LT.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "lt_LT") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  1,  1,  "%B", "sausio");
+      TEST_PRINTF_DATE (2018,  2,  1,  "%B", "vasario");
+      TEST_PRINTF_DATE (2018,  3,  1,  "%B", "kovo");
+      TEST_PRINTF_DATE (2018,  4,  1, "%OB", "balandis");
+      TEST_PRINTF_DATE (2018,  5,  1, "%OB", "gegužė");
+      TEST_PRINTF_DATE (2018,  6,  1, "%OB", "birželis");
+      TEST_PRINTF_DATE (2018,  7,  1,  "%b", "Lie");
+      TEST_PRINTF_DATE (2018,  8,  1, "%Ob", "Rgp");
+    }
+  else
+    g_test_incomplete ("locale lt_LT not available, skipping Lithuanian month names test");
+
+  setlocale (LC_ALL, "pl_PL.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "pl_PL") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  5,  1,  "%B", "maja");
+      TEST_PRINTF_DATE (2018,  6,  1,  "%B", "czerwca");
+      TEST_PRINTF_DATE (2018,  7,  1,  "%B", "lipca");
+      TEST_PRINTF_DATE (2018,  8,  1, "%OB", "sierpień");
+      TEST_PRINTF_DATE (2018,  9,  1, "%OB", "wrzesień");
+      TEST_PRINTF_DATE (2018, 10,  1, "%OB", "październik");
+      TEST_PRINTF_DATE (2018, 11,  1,  "%b", "lis");
+      TEST_PRINTF_DATE (2018, 12,  1, "%Ob", "gru");
+    }
+  else
+    g_test_incomplete ("locale pl_PL not available, skipping Polish month names test");
+
+  setlocale (LC_ALL, "ru_RU.utf-8");
+  if (strstr (setlocale (LC_ALL, NULL), "ru_RU") != NULL)
+    {
+      TEST_PRINTF_DATE (2018,  1,  1,  "%B", "января");
+      TEST_PRINTF_DATE (2018,  2,  1,  "%B", "февраля");
+      TEST_PRINTF_DATE (2018,  3,  1,  "%B", "марта");
+      TEST_PRINTF_DATE (2018,  4,  1, "%OB", "Апрель");
+      TEST_PRINTF_DATE (2018,  5,  1, "%OB", "Май");
+      TEST_PRINTF_DATE (2018,  6,  1, "%OB", "Июнь");
+      TEST_PRINTF_DATE (2018,  7,  1,  "%b", "июл");
+      TEST_PRINTF_DATE (2018,  8,  1, "%Ob", "авг");
+      /* This difference is very important in Russian:  */
+      TEST_PRINTF_DATE (2018,  5,  1,  "%b", "мая");
+      TEST_PRINTF_DATE (2018,  5,  1, "%Ob", "май");
+    }
+  else
+    g_test_incomplete ("locale ru_RU not available, skipping Russian month names test");
+
+  setlocale (LC_ALL, oldlocale);
+  g_free (oldlocale);
+}
+
 static void
 test_GDateTime_dst (void)
 {
@@ -2167,6 +2314,7 @@ main (gint   argc,
   g_test_add_func ("/GDateTime/strftime", test_strftime);
   g_test_add_func ("/GDateTime/strftime/error_handling", test_GDateTime_strftime_error_handling);
   g_test_add_func ("/GDateTime/modifiers", test_modifiers);
+  g_test_add_func ("/GDateTime/month_names", test_month_names);
   g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);
   g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix);
   g_test_add_func ("/GDateTime/to_timeval", test_GDateTime_to_timeval);
diff --git a/meson.build b/meson.build
index 79cf96fec..bb0419ed5 100644
--- a/meson.build
+++ b/meson.build
@@ -769,6 +769,54 @@ if cc.links('''#include <langinfo.h>
   glib_conf.set('HAVE_LANGINFO_OUTDIGIT', 1)
 endif
 
+# Check for nl_langinfo and alternative month names
+if cc.links('''#ifndef _GNU_SOURCE
+              # define _GNU_SOURCE
+              #endif
+              #include <langinfo.h>
+               int main (int argc, char ** argv) {
+                 char *str;
+                 str = nl_langinfo (ALTMON_1);
+                 str = nl_langinfo (ALTMON_2);
+                 str = nl_langinfo (ALTMON_3);
+                 str = nl_langinfo (ALTMON_4);
+                 str = nl_langinfo (ALTMON_5);
+                 str = nl_langinfo (ALTMON_6);
+                 str = nl_langinfo (ALTMON_7);
+                 str = nl_langinfo (ALTMON_8);
+                 str = nl_langinfo (ALTMON_9);
+                 str = nl_langinfo (ALTMON_10);
+                 str = nl_langinfo (ALTMON_11);
+                 str = nl_langinfo (ALTMON_12);
+                 return 0;
+               }''', name : 'nl_langinfo (ALTMON_n)')
+  glib_conf.set('HAVE_LANGINFO_ALTMON', 1)
+endif
+
+# Check for nl_langinfo and abbreviated alternative month names
+if cc.links('''#ifndef _GNU_SOURCE
+              # define _GNU_SOURCE
+              #endif
+              #include <langinfo.h>
+               int main (int argc, char ** argv) {
+                 char *str;
+                 str = nl_langinfo (_NL_ALTMON_1);
+                 str = nl_langinfo (_NL_ALTMON_2);
+                 str = nl_langinfo (_NL_ALTMON_3);
+                 str = nl_langinfo (_NL_ALTMON_4);
+                 str = nl_langinfo (_NL_ALTMON_5);
+                 str = nl_langinfo (_NL_ALTMON_6);
+                 str = nl_langinfo (_NL_ALTMON_7);
+                 str = nl_langinfo (_NL_ALTMON_8);
+                 str = nl_langinfo (_NL_ALTMON_9);
+                 str = nl_langinfo (_NL_ALTMON_10);
+                 str = nl_langinfo (_NL_ALTMON_11);
+                 str = nl_langinfo (_NL_ALTMON_12);
+                 return 0;
+               }''', name : 'nl_langinfo (_NL_ALTMON_n)')
+  glib_conf.set('HAVE_LANGINFO_ABALTMON', 1)
+endif
+
 # Check if C compiler supports the 'signed' keyword
 if not cc.compiles('''signed char x;''', name : 'signed')
   glib_conf.set('signed', '/* NOOP */')


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]