bug-gnulib
[Top][All Lists]
Advanced

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

Re: nl_langinfo and localized day/month names


From: Eli Zaretskii
Subject: Re: nl_langinfo and localized day/month names
Date: Wed, 11 Jun 2014 18:38:09 +0300

> Date: Tue, 10 Jun 2014 21:08:08 +0300
> From: Eli Zaretskii <address@hidden>
> 
> Currently, gnulib's nl_langinfo provides on C-locale names for week
> days and months, thus any program that uses it can only speak English
> in these contexts.
> 
> How about the following patch, which uses strftime to produce
> localized names for these?

Here's a (IMO) more elegant version of the patch, where I also added
support for categories that can be gleaned from 'localeconv':

--- lib/nl_langinfo.c~0 2014-02-15 01:00:33 +0200
+++ lib/nl_langinfo.c   2014-06-11 17:50:54 +0300
@@ -129,22 +129,46 @@ rpl_nl_langinfo (nl_item item)
 # endif
 
 # include <locale.h>
+# include <time.h>
 
 char *
 nl_langinfo (nl_item item)
 {
+  static struct tm known_tm = {
+    0, 0, 0,   /* 00:00:00 */
+    5, 0, 114, /* Sunday January 5, 2014 */
+    0, 4, -1
+  };
+  struct tm tmm;
+  static char nlbuf[100];
+
   switch (item)
     {
     /* nl_langinfo items of the LC_CTYPE category */
     case CODESET:
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+      /* The Windows API has a function returning the locale's
+        codepage as a number, but the value doesn't change according
+        to what the 'setlocale' call specified.  So we use it as a
+        last resort, in case the string returned by 'setlocale'
+        doesn't specify the codepage.  */
       {
-        static char buf[2 + 10 + 1];
+       char *current_locale = setlocale (LC_ALL, NULL);
+       char *pdot;
+
+       /* If they set different locales for different categories,
+          'setlocale' will return a semi-colon separated list of
+          locale values.  To make sure we use the correct one, we
+          choose LC_CTYPE.  */
+       if (strchr (current_locale, ';'))
+         current_locale = setlocale (LC_CTYPE, NULL);
 
-        /* The Windows API has a function returning the locale's codepage as
-           a number.  */
-        sprintf (buf, "CP%u", GetACP ());
-        return buf;
+       pdot = strrchr (current_locale, '.');
+       if (pdot)
+         sprintf (nlbuf, "CP%s", pdot + 1);
+       else
+         sprintf (nlbuf, "CP%u", GetACP ());
+       return nlbuf;
       }
 # elif defined __BEOS__
       return "UTF-8";
@@ -156,6 +180,8 @@ nl_langinfo (nl_item item)
       return localeconv () ->decimal_point;
     case THOUSEP:
       return localeconv () ->thousands_sep;
+    case GROUPING:
+      return localeconv () ->grouping;
     /* nl_langinfo items of the LC_TIME category.
        TODO: Really use the locale.  */
     case D_T_FMT:
@@ -170,93 +196,151 @@ nl_langinfo (nl_item item)
     case T_FMT_AMPM:
       return "%I:%M:%S %p";
     case AM_STR:
-      return "AM";
+      memcpy (&tmm, &known_tm, sizeof (known_tm));
+      tmm.tm_hour = 10;
+      if (!strftime (nlbuf, sizeof(nlbuf), "%p", &tmm))
+       return "AM";
+      return nlbuf;
     case PM_STR:
-      return "PM";
+      memcpy (&tmm, &known_tm, sizeof (known_tm));
+      tmm.tm_hour = 22;
+      if (!strftime (nlbuf, sizeof(nlbuf), "%p", &tmm))
+       return "PM";
+      return nlbuf;
     case DAY_1:
-      return "Sunday";
     case DAY_2:
-      return "Monday";
     case DAY_3:
-      return "Tuesday";
     case DAY_4:
-      return "Wednesday";
     case DAY_5:
-      return "Thursday";
     case DAY_6:
-      return "Friday";
     case DAY_7:
-      return "Saturday";
+      {
+       static char *days[] = {
+         "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+         "Friday", "Saturday"
+       };
+       memcpy (&tmm, &known_tm, sizeof (known_tm));
+       tmm.tm_mday += item - DAY_1;
+       tmm.tm_wday += item - DAY_1;
+       if (!strftime (nlbuf, sizeof(nlbuf), "%A", &tmm))
+         return days[item - DAY_1];
+       return nlbuf;
+      }
     case ABDAY_1:
-      return "Sun";
     case ABDAY_2:
-      return "Mon";
     case ABDAY_3:
-      return "Tue";
     case ABDAY_4:
-      return "Wed";
     case ABDAY_5:
-      return "Thu";
     case ABDAY_6:
-      return "Fri";
     case ABDAY_7:
-      return "Sat";
+      {
+       static char *abdays[] = {
+         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+       };
+       memcpy (&tmm, &known_tm, sizeof (known_tm));
+       tmm.tm_mday += item - ABDAY_1;
+       tmm.tm_wday += item - ABDAY_1;
+       if (!strftime (nlbuf, sizeof(nlbuf), "%a", &tmm))
+         return abdays[item - ABDAY_1];
+       return nlbuf;
+      }
     case MON_1:
-      return "January";
     case MON_2:
-      return "February";
     case MON_3:
-      return "March";
     case MON_4:
-      return "April";
     case MON_5:
-      return "May";
     case MON_6:
-      return "June";
     case MON_7:
-      return "July";
     case MON_8:
-      return "August";
     case MON_9:
-      return "September";
     case MON_10:
-      return "October";
     case MON_11:
-      return "November";
     case MON_12:
-      return "December";
+      {
+       static char *months[] = {
+         "January", "February", "March", "April", "May", "June", "July",
+         "September", "October", "November", "December"
+       };
+       memcpy (&tmm, &known_tm, sizeof (known_tm));
+       tmm.tm_mon += item - MON_1;
+       if (!strftime (nlbuf, sizeof(nlbuf), "%B", &tmm))
+         return months[item - MON_1];
+       return nlbuf;
+      }
     case ABMON_1:
-      return "Jan";
     case ABMON_2:
-      return "Feb";
     case ABMON_3:
-      return "Mar";
     case ABMON_4:
-      return "Apr";
     case ABMON_5:
-      return "May";
     case ABMON_6:
-      return "Jun";
     case ABMON_7:
-      return "Jul";
     case ABMON_8:
-      return "Aug";
     case ABMON_9:
-      return "Sep";
     case ABMON_10:
-      return "Oct";
     case ABMON_11:
-      return "Nov";
     case ABMON_12:
-      return "Dec";
+      {
+       static char *abmonths[] = {
+         "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+         "Sep", "Oct", "Nov", "Dec"
+       };
+       memcpy (&tmm, &known_tm, sizeof (known_tm));
+       tmm.tm_mon += item - ABMON_1;
+       if (!strftime (nlbuf, sizeof(nlbuf), "%b", &tmm))
+         return abmonths[item - ABMON_1];
+       return nlbuf;
+      }
     case ERA:
       return "";
     case ALT_DIGITS:
       return "\0\0\0\0\0\0\0\0\0\0";
-    /* nl_langinfo items of the LC_MONETARY category
-       TODO: Really use the locale. */
+    /* nl_langinfo items of the LC_MONETARY category.  */
     case CRNCYSTR:
-      return "-";
+      return localeconv () ->currency_symbol;
+    case INT_CURR_SYMBOL:
+      return localeconv () ->int_curr_symbol;
+    case MON_DECIMAL_POINT:
+      return localeconv () ->mon_decimal_point;
+    case MON_THOUSANDS_SEP:
+      return localeconv () ->mon_thousands_sep;
+    case MON_GROUPING:
+      return localeconv () ->mon_grouping;
+    case POSITIVE_SIGN:
+      return localeconv () ->positive_sign;
+    case NEGATIVE_SIGN:
+      return localeconv () ->negative_sign;
+    case FRAC_DIGITS:
+      nlbuf[0] = localeconv () ->frac_digits;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case INT_FRAC_DIGITS:
+      nlbuf[0] = localeconv () ->int_frac_digits;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case P_CS_PRECEDES:
+      nlbuf[0] = localeconv () ->p_cs_precedes;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case N_CS_PRECEDES:
+      nlbuf[0] = localeconv () ->n_cs_precedes;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case P_SEP_BY_SPACE:
+      nlbuf[0] = localeconv () ->p_sep_by_space;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case N_SEP_BY_SPACE:
+      nlbuf[0] = localeconv () ->n_sep_by_space;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case P_SIGN_POSN:
+      nlbuf[0] = localeconv () ->p_sign_posn;
+      nlbuf[1] = '\0';
+      return nlbuf;
+    case N_SIGN_POSN:
+      nlbuf[0] = localeconv () ->n_sign_posn;
+      nlbuf[1] = '\0';
+      return nlbuf;
     /* nl_langinfo items of the LC_MESSAGES category
        TODO: Really use the locale. */
     case YESEXPR:


--- lib/langinfo.in.h~0 2014-02-15 01:00:33 +0200
+++ lib/langinfo.in.h   2014-06-11 17:50:57 +0300
@@ -49,7 +49,10 @@
 # define CODESET     10000
 /* nl_langinfo items of the LC_NUMERIC category */
 # define RADIXCHAR   10001
+# define DECIMAL_POINT RADIXCHAR
 # define THOUSEP     10002
+# define THOUSANDS_SEP THOUSEP
+# define GROUPING    10114
 /* nl_langinfo items of the LC_TIME category */
 # define D_T_FMT     10003
 # define D_FMT       10004
@@ -102,6 +105,21 @@
 # define ALT_DIGITS  10051
 /* nl_langinfo items of the LC_MONETARY category */
 # define CRNCYSTR    10052
+# define CURRENCY_SYMBOL   CRNCYSTR
+# define INT_CURR_SYMBOL   10100
+# define MON_DECIMAL_POINT 10101
+# define MON_THOUSANDS_SEP 10102
+# define MON_GROUPING      10103
+# define POSITIVE_SIGN     10104
+# define NEGATIVE_SIGN     10105
+# define FRAC_DIGITS       10106
+# define INT_FRAC_DIGITS   10107
+# define P_CS_PRECEDES     10108
+# define N_CS_PRECEDES     10109
+# define P_SEP_BY_SPACE    10110
+# define N_SEP_BY_SPACE    10111
+# define P_SIGN_POSN       10112
+# define N_SIGN_POSN       10113
 /* nl_langinfo items of the LC_MESSAGES category */
 # define YESEXPR     10053
 # define NOEXPR      10054



reply via email to

[Prev in Thread] Current Thread [Next in Thread]