On Sun, Mar 09, 2008 at 02:47:55PM +0100, Robert Luberda wrote:
> On the other hand while testing updated message catalogue translations I
> noticed, that man seems not to use translations from the
> man-db-gnulib.mo file, for example it shows untranslated messages
> 
> [17]/tmp> LC_ALL=pl_PL man --help | grep help
>   -?, --help                 give this help list
> 
> even though translation is available:
> 
> [19]/usr/share/locale/pl/LC_MESSAGES> msgunfmt man-db-gnulib.mo | grep
> -1  'give this help'
> 
> msgid "give this help list"
> msgstr "wyƛwietlenie tego tekstu pomocy"

This appears to be a Gnulib bug.

man-db sets its default text domain to "man-db", and keeps all Gnulib's
strings in a separate "man-db-gnulib" domain, using 'gnulib-tool
--po-domain=man-db' which results in
-DDEFAULT_TEXT_DOMAIN=\"man-db-gnulib\". (I checked this general
approach with Bruno a while back and he said it was fine.)

However, Gnulib's argp implementation has three bugs which cause this
not to work properly:

  * It hardcodes "libc" as a domain in two places. This is obviously
    wrong in Gnulib.

  * It uses argp_domain as both the domain used to translate its own
    strings (i.e. string literals in lib/argp-*.c) and the domain used
    to translate strings provided by the user, which normally have to
    use gettext_noop so that they can be used as 'struct argp_option'
    initialisers. This is dreadfully inconvenient because you have to
    copy strings about all over the place and keep your POT file up to
    date as the argp implementation changes. If argp is in libc then
    this is obviously impossible.

    Instead, argp should use DEFAULT_TEXT_DOMAIN to translate its own
    string literals (falling back to the default program domain if that
    is not set), and should reserve argp_domain for translating strings
    that appear in that argp structure.

  * In a number of places, argp uses the domain of the root argp
    structure when translating text from a child argp structure. This is
    the direct cause of Robert's bug, because the standard --help and
    --version options are implemented as a child argp structure with its
    own domain.

    My patch changes this to use argp_domain from the child instead.
    However, on reflection, I'm not certain that this is correct;
    arguably it needs to walk up the tree until it finds a domain to
    use. This depends on whether you think that argp_domain == NULL
    means "use default program domain" or "use same domain as parent
    argp structure".

Could somebody review the attached patch and see if it looks right?

2008-03-10  Colin Watson  <[EMAIL PROTECTED]>

        * lib/argp-help.c: Define ARGP_TEXT_DOMAIN to
        DEFAULT_TEXT_DOMAIN if set.
        (validate_uparams, fill_in_uparams, hol_help, _help)
        (__argp_failure): Use our default domain rather than the
        provided argp_domain to translate our own strings.
        (hol_entry_help): Translate user strings using the appropriate
        child argp_domain, rather than that from the root argp.

        * lib/argp-parse.c: Define ARGP_TEXT_DOMAIN to
        DEFAULT_TEXT_DOMAIN if set.
        (argp_default_argp, argp_version_argp): Set argp_domain to
        ARGP_TEXT_DOMAIN rather than "libc".
        (argp_version_parser, parser_finalize, parser_parse_opt): Use
        our default domain rather than the provided argp_domain to
        translate our own strings.

Thanks,

-- 
Colin Watson                                       [EMAIL PROTECTED]
diff --git a/lib/argp-help.c b/lib/argp-help.c
index 4c0ca60..5ca3378 100644
--- a/lib/argp-help.c
+++ b/lib/argp-help.c
@@ -46,6 +46,16 @@
 # include "gettext.h"
 #endif
 
+#ifdef _LIBC
+# define ARGP_TEXT_DOMAIN "libc"
+#else
+# ifdef DEFAULT_TEXT_DOMAIN
+#  define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
+# else
+#  define ARGP_TEXT_DOMAIN NULL
+# endif
+#endif
+
 #include "argp.h"
 #include "argp-fmtstream.h"
 #include "argp-namefrob.h"
@@ -143,7 +153,7 @@ validate_uparams (const struct argp_state *state, struct uparams *upptr)
       if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin)
 	{
 	  __argp_failure (state, 0, 0,
-			  dgettext (state->root_argp->argp_domain,
+			  dgettext (ARGP_TEXT_DOMAIN,
 				    "\
 ARGP_HELP_FMT: %s value is less than or equal to %s"),
 			  "rmargin", up->name);
@@ -216,13 +226,13 @@ fill_in_uparams (const struct argp_state *state)
 		  {
 		    if (unspec && !un->is_bool)
 		      __argp_failure (state, 0, 0,
-				      dgettext (state->root_argp->argp_domain,
+				      dgettext (ARGP_TEXT_DOMAIN,
 						"\
 %.*s: ARGP_HELP_FMT parameter requires a value"),
 				      (int) var_len, var);
 		    else if (val < 0)
 		      __argp_failure (state, 0, 0,
-				      dgettext (state->root_argp->argp_domain,
+				      dgettext (ARGP_TEXT_DOMAIN,
 						"\
 %.*s: ARGP_HELP_FMT parameter must be positive"),
 				      (int) var_len, var);
@@ -232,7 +242,7 @@ fill_in_uparams (const struct argp_state *state)
 		  }
 	      if (! un->name)
 		__argp_failure (state, 0, 0,
-				dgettext (state->root_argp->argp_domain, "\
+				dgettext (ARGP_TEXT_DOMAIN, "\
 %.*s: Unknown ARGP_HELP_FMT parameter"),
 				(int) var_len, var);
 
@@ -243,7 +253,7 @@ fill_in_uparams (const struct argp_state *state)
 	  else if (*var)
 	    {
 	      __argp_failure (state, 0, 0,
-			      dgettext (state->root_argp->argp_domain,
+			      dgettext (ARGP_TEXT_DOMAIN,
 					"Garbage in ARGP_HELP_FMT: %s"), var);
 	      break;
 	    }
@@ -1135,7 +1145,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
 	    __argp_fmtstream_putc (stream, '-');
 	    __argp_fmtstream_putc (stream, *so);
 	    if (!have_long_opt || uparams.dup_args)
-	      arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream);
+	      arg (real, " %s", "[%s]", entry->argp->argp_domain, stream);
 	    else if (real->arg)
 	      hhstate->suppressed_dup_arg = 1;
 	  }
@@ -1157,7 +1167,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
 	    __argp_fmtstream_puts (stream,
 				   onotrans (opt) ?
 				             opt->name :
-				   dgettext (state->root_argp->argp_domain,
+				   dgettext (entry->argp->argp_domain,
 					     opt->name));
 	  }
     }
@@ -1173,7 +1183,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
 	    comma (uparams.long_opt_col, &pest);
 	    __argp_fmtstream_printf (stream, "--%s", opt->name);
 	    if (first_long_opt || uparams.dup_args)
-	      arg (real, "=%s", "[=%s]", state->root_argp->argp_domain,
+	      arg (real, "=%s", "[=%s]", entry->argp->argp_domain,
 		   stream);
 	    else if (real->arg)
 	      hhstate->suppressed_dup_arg = 1;
@@ -1195,7 +1205,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
     }
   else
     {
-      const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain,
+      const char *tstr = real->doc ? dgettext (entry->argp->argp_domain,
 					       real->doc) : 0;
       const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
       if (fstr && *fstr)
@@ -1243,7 +1253,7 @@ hol_help (struct hol *hol, const struct argp_state *state,
 
   if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
     {
-      const char *tstr = dgettext (state->root_argp->argp_domain, "\
+      const char *tstr = dgettext (ARGP_TEXT_DOMAIN, "\
 Mandatory or optional arguments to long options are also mandatory or \
 optional for any corresponding short options.");
       const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
@@ -1636,11 +1646,11 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
 
 	  if (first_pattern)
 	    __argp_fmtstream_printf (fs, "%s %s",
-				     dgettext (argp->argp_domain, "Usage:"),
+				     dgettext (ARGP_TEXT_DOMAIN, "Usage:"),
 				     name);
 	  else
 	    __argp_fmtstream_printf (fs, "%s %s",
-				     dgettext (argp->argp_domain, "  or: "),
+				     dgettext (ARGP_TEXT_DOMAIN, "  or: "),
 				     name);
 
 	  /* We set the lmargin as well as the wmargin, because hol_usage
@@ -1651,7 +1661,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
 	    /* Just show where the options go.  */
 	    {
 	      if (hol->num_entries > 0)
-		__argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
+		__argp_fmtstream_puts (fs, dgettext (ARGP_TEXT_DOMAIN,
 						     " [OPTION...]"));
 	    }
 	  else
@@ -1679,7 +1689,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
 
   if (flags & ARGP_HELP_SEE)
     {
-      __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
+      __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN, "\
 Try `%s --help' or `%s --usage' for more information.\n"),
 			       name, name);
       anything = 1;
@@ -1706,7 +1716,7 @@ Try `%s --help' or `%s --usage' for more information.\n"),
     {
       if (anything)
 	__argp_fmtstream_putc (fs, '\n');
-      __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
+      __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN,
 					     "Report bugs to %s.\n"),
  			       argp_program_bug_address);
       anything = 1;
@@ -1925,8 +1935,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 #endif
 #if !_LIBC
 		  if (! s && ! (s = strerror (errnum)))
-		    s = dgettext (state->root_argp->argp_domain,
-				  "Unknown system error");
+		    s = dgettext (ARGP_TEXT_DOMAIN, "Unknown system error");
 #endif
 		  fputs (s, stream);
 		}
diff --git a/lib/argp-parse.c b/lib/argp-parse.c
index d86256a..bd0fa4e 100644
--- a/lib/argp-parse.c
+++ b/lib/argp-parse.c
@@ -39,6 +39,16 @@
 #endif
 #define N_(msgid) msgid
 
+#ifdef _LIBC
+# define ARGP_TEXT_DOMAIN "libc"
+#else
+# ifdef DEFAULT_TEXT_DOMAIN
+#  define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
+# else
+#  define ARGP_TEXT_DOMAIN NULL
+# endif
+#endif
+
 #include "argp.h"
 #include "argp-namefrob.h"
 
@@ -134,7 +144,8 @@ argp_default_parser (int key, char *arg, struct argp_state *state)
 }
 
 static const struct argp argp_default_argp =
-  {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"};
+  {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL,
+   ARGP_TEXT_DOMAIN};
 
 
 static const struct argp_option argp_version_options[] =
@@ -154,7 +165,7 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
       else if (argp_program_version)
 	fprintf (state->out_stream, "%s\n", argp_program_version);
       else
-	__argp_error (state, dgettext (state->root_argp->argp_domain,
+	__argp_error (state, dgettext (ARGP_TEXT_DOMAIN,
 				       "(PROGRAM ERROR) No version known!?"));
       if (! (state->flags & ARGP_NO_EXIT))
 	exit (0);
@@ -166,7 +177,8 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
 }
 
 static const struct argp argp_version_argp =
-  {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"};
+  {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL,
+   ARGP_TEXT_DOMAIN};
 
 /* Returns the offset into the getopt long options array LONG_OPTIONS of a
    long option with called NAME, or -1 if none is found.  Passing NULL as
@@ -607,8 +619,7 @@ parser_finalize (struct parser *parser,
 	  if (!(parser->state.flags & ARGP_NO_ERRS)
 	      && parser->state.err_stream)
 	    fprintf (parser->state.err_stream,
-		     dgettext (parser->argp->argp_domain,
-			       "%s: Too many arguments\n"),
+		     dgettext (ARGP_TEXT_DOMAIN, "%s: Too many arguments\n"),
 		     parser->state.name);
 	  err = EBADKEY;
 	}
@@ -754,7 +765,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
 	N_("(PROGRAM ERROR) Option should have been recognized!?");
       if (group_key == 0)
 	__argp_error (&parser->state, "-%c: %s", opt,
-		      dgettext (parser->argp->argp_domain, bad_key_err));
+		      dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
       else
 	{
 	  struct option *long_opt = parser->long_opts;
@@ -762,7 +773,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
 	    long_opt++;
 	  __argp_error (&parser->state, "--%s: %s",
 			long_opt->name ? long_opt->name : "???",
-			dgettext (parser->argp->argp_domain, bad_key_err));
+			dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
 	}
     }
 

Reply via email to