> Date: Wed, 11 Jun 2014 18:38:09 +0300 > From: Eli Zaretskii <e...@gnu.org> > > > Date: Tue, 10 Jun 2014 21:08:08 +0300 > > From: Eli Zaretskii <e...@gnu.org> > > > > 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
Ping! Could someone please respond, and either accept the patch or explain why it cannot be accepted? It's been 4 weeks since the last reminder, with no responses whatsoever. The current nl_langinfo lacks quite a few features that are easy to get on MS-Windows, so it's a pity not to have them. The latest version of the patch I propose, which was extensively tested via the Guile test suite, is below. Thanks in advance. --- lib/langinfo.in.h~0 2014-02-15 01:00:33 +0200 +++ lib/langinfo.in.h 2014-06-11 18: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 --- lib/nl_langinfo.c~0 2014-02-15 01:00:33 +0200 +++ lib/nl_langinfo.c 2014-06-15 19:21:45 +0300 @@ -121,6 +121,7 @@ rpl_nl_langinfo (nl_item item) # include <windows.h> # include <stdio.h> +# include <limits.h> # else @@ -129,22 +130,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; - /* The Windows API has a function returning the locale's codepage as - a number. */ - sprintf (buf, "CP%u", GetACP ()); - return buf; + /* 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); + + 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"; @@ -153,9 +178,23 @@ nl_langinfo (nl_item item) # endif /* nl_langinfo items of the LC_NUMERIC category */ case RADIXCHAR: - return localeconv () ->decimal_point; + { + char *c = localeconv () ->decimal_point; + + if (*c == CHAR_MAX || *c == -1) + return ""; + return c; + } case THOUSEP: - return localeconv () ->thousands_sep; + { + char *c = localeconv () ->thousands_sep; + + if (*c == CHAR_MAX || *c == -1) + return ""; + return c; + } + case GROUPING: + return localeconv () ->grouping; /* nl_langinfo items of the LC_TIME category. TODO: Really use the locale. */ case D_T_FMT: @@ -170,93 +209,163 @@ 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: + { + char *c = localeconv () ->mon_decimal_point; + + if (*c == CHAR_MAX || *c == -1) + return ""; + return c; + } + case MON_THOUSANDS_SEP: + { + char *c = localeconv () ->mon_thousands_sep; + + if (*c == CHAR_MAX || *c == -1) + return ""; + return c; + } + 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: