{"id":2227404,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2227404/?format=json","web_url":"http://patchwork.ozlabs.org/project/glibc/patch/f7ee811c6f1995dc399a48388241ceffb79a23dd.1776957778.git.vivien@planete-kraus.eu/","project":{"id":41,"url":"http://patchwork.ozlabs.org/api/1.1/projects/41/?format=json","name":"GNU C Library","link_name":"glibc","list_id":"libc-alpha.sourceware.org","list_email":"libc-alpha@sourceware.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<f7ee811c6f1995dc399a48388241ceffb79a23dd.1776957778.git.vivien@planete-kraus.eu>","date":"2026-04-23T16:04:01","name":"[v22,3/9] argp: document translated names in --help and --usage","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"8e858104ddeb0466e674ca367d8686b2c1ddc417","submitter":{"id":90948,"url":"http://patchwork.ozlabs.org/api/1.1/people/90948/?format=json","name":"Vivien Kraus","email":"vivien@planete-kraus.eu"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/glibc/patch/f7ee811c6f1995dc399a48388241ceffb79a23dd.1776957778.git.vivien@planete-kraus.eu/mbox/","series":[{"id":501215,"url":"http://patchwork.ozlabs.org/api/1.1/series/501215/?format=json","web_url":"http://patchwork.ozlabs.org/project/glibc/list/?series=501215","date":"2026-04-23T16:03:58","name":"Support translated long option names in getopt and argp","version":22,"mbox":"http://patchwork.ozlabs.org/series/501215/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2227404/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2227404/checks/","tags":{},"headers":{"Return-Path":"<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>","X-Original-To":["incoming@patchwork.ozlabs.org","libc-alpha@sourceware.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","libc-alpha@sourceware.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu\n header.a=rsa-sha1 header.s=albinoniA header.b=TNtjKlwm;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n secure) header.d=planete-kraus.eu header.i=@planete-kraus.eu\n header.a=rsa-sha1 header.s=albinoniA header.b=TNtjKlwm","sourceware.org; dmarc=pass (p=reject dis=none)\n header.from=planete-kraus.eu","sourceware.org;\n spf=pass smtp.mailfrom=planete-kraus.eu","server2.sourceware.org;\n arc=none smtp.remote-ip=89.234.140.182"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g1gwg6VRcz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 02:07:47 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 1BB794B87B92\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 16:07:46 +0000 (GMT)","from planete-kraus.eu (planete-kraus.eu [89.234.140.182])\n by sourceware.org (Postfix) with ESMTPS id A870A4BBCDC9\n for <libc-alpha@sourceware.org>; Thu, 23 Apr 2026 16:05:47 +0000 (GMT)","from planete-kraus.eu (localhost [127.0.0.1])\n by planete-kraus.eu (OpenSMTPD) with ESMTP id 7dd75780;\n Thu, 23 Apr 2026 16:05:42 +0000 (UTC)","by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 9324f3ae\n (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO);\n Thu, 23 Apr 2026 16:05:40 +0000 (UTC)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 1BB794B87B92","OpenDKIM Filter v2.11.0 sourceware.org A870A4BBCDC9"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org A870A4BBCDC9","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org A870A4BBCDC9","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776960348; cv=none;\n b=ssLN2DLCOjPEiPWyu+x7rwQWmvCchE9gu+afUgjkDDr6xV31WdCbxHKSsPHGQOyrA/rvxfWA0rt9No+umx1lX3pQQc14jUXySB6wpq2LV62SOGIPFaAz5u+VpFXCOiBmpbcZLlh+GSNP1unM5CkUGEgC+5vJJcWM62WJI1nkwSw=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776960348; c=relaxed/simple;\n bh=eSJGJJyfSjMkXzfJvEGi/ncCldRIKsF6qmVy00W9xWY=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=c2fsQZ3aO6MwllNlx69WTnPK9Vo9MkgGIOPBrgmGylLiVru9QGClr4nCa27fJ29UbUA1FsfBJwno497j05AedE+qUPTk7V6ZcbK2e0IR6hxvSKdm/IgcZAEIEXMKM2KC6dxRj6Jv8ypl9NfDmknWYGLJT6vZ4bBG+bB/xa5dB1c=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha1; c=relaxed; d=planete-kraus.eu; h=from\n :to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-type:content-transfer-encoding; s=\n albinoniA; bh=I1wpMqa4bSkKrhu9ly53588gmh0=; b=TNtjKlwm9gBQYKpFOm\n Wbo/9o3bOIOSunsZ+5YEcJeefUAkixnMHMyX28B4LMfcAtzt2xwaHZLitBWd1ap0\n YJVE5/SK8bKryoKJT7DUBX2HsI6MYRGejP2jI3DqsUvC8/7MPjthrmmY8unVAOUz\n TzSpADGrhQbHLw5iZiQXtoJblOqFFlvjuiV6o8CJWWvY3Kq59fpm0bAR5TrGlCnU\n OPw9uTPBI7UL1IEWHF+qXTI6EZ6SqALc+f+BlDKLz6BPuSDzqbRSJ/dJWoEIAdtK\n 3cBPs6KW1zdaHtbvh8qLCPzkAC0MtiBmQeOig5HGB9sIq0aIDz6BIez1RW0oOvIv\n iobg==","From":"Vivien Kraus <vivien@planete-kraus.eu>","To":"adhemerval.zanella@linaro.org,\n\tlibc-alpha@sourceware.org","Cc":"Vivien Kraus <vivien@planete-kraus.eu>","Subject":"[PATCH v22 3/9] argp: document translated names in --help and --usage","Date":"Thu, 23 Apr 2026 18:04:01 +0200","Message-ID":"\n <f7ee811c6f1995dc399a48388241ceffb79a23dd.1776957778.git.vivien@planete-kraus.eu>","X-Mailer":"git-send-email 2.52.0","In-Reply-To":"<cover.1776957777.git.vivien@planete-kraus.eu>","References":"<cover.1776957777.git.vivien@planete-kraus.eu>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","X-BeenThere":"libc-alpha@sourceware.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Libc-alpha mailing list <libc-alpha.sourceware.org>","List-Unsubscribe":"<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>","List-Archive":"<https://sourceware.org/pipermail/libc-alpha/>","List-Post":"<mailto:libc-alpha@sourceware.org>","List-Help":"<mailto:libc-alpha-request@sourceware.org?subject=help>","List-Subscribe":"<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>","Errors-To":"libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org"},"content":"They are displayed in the --usage and --help output as the main option\nname, and the untranslated name is also displayed in parenthesis, so\nthat someone reading a script (presumably with untranslated option\nnames) can then figure out which translated option name it relates\nto.\n\nThis help message processing uses dynamic memory allocation.  If\nmalloc fails, the translated option name will not be displayed.\n\nA translation context is required for translated options processing.\nHowever, its configuration would be most likely expected to be in the\nstruct argp definition, but it would change this struct type.  The\neasiest solution is to use a fixed context.\n\nSince the configuration of the translation domain is on a per-parser\nbasis, and getopt_long is called with the union of all\noptions (including options from children parsers), then all option\nnames in all parsers must be in the same domain.  However, it makes\nsense to use documentation from different domains.  Thus, the\ntranslations for option names will all be searched in the current\ntextdomain, while documentation will respect the parser’s domain.\n---\n argp/Makefile                  | 19 +++++++\n argp/argp-help.c               | 55 +++++++++++++++++++-\n argp/argp-parse.c              |  1 +\n argp/tst-argphelp-localized.c  | 92 ++++++++++++++++++++++++++++++++++\n argp/tst-argphelp-localized.po | 25 +++++++++\n argp/tst-argpusage-localized.c | 81 ++++++++++++++++++++++++++++++\n manual/argp.texi               | 22 +++++---\n 7 files changed, 286 insertions(+), 9 deletions(-)\n create mode 100644 argp/tst-argphelp-localized.c\n create mode 100644 argp/tst-argphelp-localized.po\n create mode 100644 argp/tst-argpusage-localized.c","diff":"diff --git a/argp/Makefile b/argp/Makefile\nindex 38573fbc66..ff5fa3d77e 100644\n--- a/argp/Makefile\n+++ b/argp/Makefile\n@@ -44,6 +44,8 @@ tests = \\\n   bug-argp2 \\\n   tst-argp1 \\\n   tst-argp2 \\\n+  tst-argphelp-localized \\\n+  tst-argpusage-localized \\\n   tst-ldbl-argp \\\n   # tests\n \n@@ -51,6 +53,23 @@ CFLAGS-argp-help.c += $(uses-callbacks) -fexceptions\n CFLAGS-argp-parse.c += $(uses-callbacks)\n CFLAGS-argp-fmtstream.c += -fexceptions\n \n+tst_argphelp_localized_mo = $(objpfx)domaindir/en_GB/LC_MESSAGES/tst-argphelp-localized.mo\n+\n+$(tst_argphelp_localized_mo): tst-argphelp-localized.po\n+\t$(make-target-directory)\n+\tmsgfmt -o $@T $<\n+\tmv -f $@T $@\n+\n+LOCALES := \\\n+  en_GB.UTF-8 \\\n+  # LOCALES\n+include ../gen-locales.mk\n+\n+$(objpfx)tst-argphelp-localized.out: $(tst_argphelp_localized_mo) $(gen-locales)\n+$(objpfx)tst-argpusage-localized.out: $(tst_argphelp_localized_mo) $(gen-locales)\n+CFLAGS-tst-argphelp-localized.c += -DOBJPFX=\\\"$(objpfx)\\\"\n+CFLAGS-tst-argpusage-localized.c += -DOBJPFX=\\\"$(objpfx)\\\"\n+\n bug-argp1-ARGS = -- --help\n bug-argp2-ARGS = -- -d 111 --dstaddr 222 -p 333 --peer 444\n \ndiff --git a/argp/argp-help.c b/argp/argp-help.c\nindex 9dd4f6564f..0cacf19e33 100644\n--- a/argp/argp-help.c\n+++ b/argp/argp-help.c\n@@ -1205,6 +1205,35 @@ comma (unsigned col, struct pentry_state *pest)\n   indent_to (pest->stream, col);\n }\n \f\n+/* Help and usage output show the translated option name.  *allocated\n+   holds a pointer that should be freed by the caller, or a NULL\n+   pointer.  */\n+static const char *\n+translate_option_name (const char *name, char **allocated)\n+{\n+  /* Argp does not have a configuration for the context, so a default\n+     one is used.  */\n+  /* FIXME: use pgettext_expr.  */\n+  *allocated = NULL;\n+  if (__asprintf (allocated, \"command-line option\\004%s\", name) == -1)\n+    {\n+      /* *allocated is NULL */\n+      return name;\n+    }\n+  const char *translated = gettext (*allocated);\n+  if (strcmp (translated, *allocated) == 0)\n+    {\n+      /* No translation performed.  */\n+      free (*allocated);\n+      *allocated = NULL;\n+      return name;\n+    }\n+  /* FIXME: is it safe to discard *allocated early here?  Won’t the\n+     return value alias it? */\n+  /* *allocated is to be freed by the caller.  */\n+  return translated;\n+}\n+\f\n /* Print help for ENTRY to STREAM.  */\n static void\n hol_entry_help (struct hol_entry *entry, const struct argp_state *state,\n@@ -1213,6 +1242,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,\n   unsigned num;\n   const struct argp_option *real = entry->opt, *opt;\n   char *so = entry->short_options;\n+  const char *translated_option_name;\n   int have_long_opt = 0;\t/* We have any long options.  */\n   /* Saved margins.  */\n   int old_lm = __argp_fmtstream_set_lmargin (stream, 0);\n@@ -1276,9 +1306,14 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,\n \tif (opt->name && ovisible (opt))\n \t  {\n \t    comma (uparams.long_opt_col, &pest);\n-\t    __argp_fmtstream_printf (stream, \"--%s\", opt->name);\n+\t    char *name_allocated = NULL;\n+\t    translated_option_name = translate_option_name (opt->name, &name_allocated);\n+\t    __argp_fmtstream_printf (stream, \"--%s\", translated_option_name);\n \t    arg (real, \"=%s\", \"[=%s]\",\n \t\t state == NULL ? NULL : state->root_argp->argp_domain, stream);\n+\t    if (strcmp (translated_option_name, opt->name))\n+\t      __argp_fmtstream_printf (stream, \" (--%s)\", opt->name);\n+\t    free (name_allocated);\n \t  }\n     }\n \n@@ -1420,6 +1455,7 @@ usage_long_opt (const struct argp_option *opt,\n {\n   argp_fmtstream_t stream = cookie;\n   const char *arg = opt->arg;\n+  const char *translated_option_name = opt->name;\n   int flags = opt->flags | real->flags;\n \n   if (! arg)\n@@ -1427,16 +1463,31 @@ usage_long_opt (const struct argp_option *opt,\n \n   if (! (flags & OPTION_NO_USAGE))\n     {\n+      char *name_allocated = NULL;\n+      translated_option_name =\n+\ttranslate_option_name (opt->name, &name_allocated);\n+      int translation_differs =\n+\t(strcmp (translated_option_name, opt->name) != 0);\n       if (arg)\n \t{\n \t  arg = dgettext (domain, arg);\n-\t  if (flags & OPTION_ARG_OPTIONAL)\n+\t  if ((flags & OPTION_ARG_OPTIONAL) && translation_differs)\n+\t    __argp_fmtstream_printf (stream, \" [--%s[=%s] (--%s)]\",\n+\t\t\t\t     translated_option_name, arg, opt->name);\n+\t  else if (flags & OPTION_ARG_OPTIONAL)\n \t    __argp_fmtstream_printf (stream, \" [--%s[=%s]]\", opt->name, arg);\n+\t  else if (translation_differs)\n+\t    __argp_fmtstream_printf (stream, \" [--%s=%s (--%s)]\",\n+\t\t\t\t     translated_option_name, arg, opt->name);\n \t  else\n \t    __argp_fmtstream_printf (stream, \" [--%s=%s]\", opt->name, arg);\n \t}\n+      else if (translation_differs)\n+\t__argp_fmtstream_printf (stream, \" [--%s (--%s)]\",\n+\t\t\t\t translated_option_name, opt->name);\n       else\n \t__argp_fmtstream_printf (stream, \" [--%s]\", opt->name);\n+      free (name_allocated);\n     }\n \n   return 0;\ndiff --git a/argp/argp-parse.c b/argp/argp-parse.c\nindex 55a54e9765..a220b32cef 100644\n--- a/argp/argp-parse.c\n+++ b/argp/argp-parse.c\n@@ -472,6 +472,7 @@ parser_init (struct parser *parser, const struct argp *argp,\n   struct parser_sizes szs;\n   struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER;\n \n+  opt_data.optctxt = \"command-line option\";\n   szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1;\n   szs.long_len = 0;\n   szs.num_groups = 0;\ndiff --git a/argp/tst-argphelp-localized.c b/argp/tst-argphelp-localized.c\nnew file mode 100644\nindex 0000000000..8703742b8f\n--- /dev/null\n+++ b/argp/tst-argphelp-localized.c\n@@ -0,0 +1,92 @@\n+/* Test program for argp argument parser\n+   Copyright (C) 2026 Free Software Foundation, Inc.\n+   This file is part of the GNU C Library.\n+\n+   The GNU C Library is free software; you can redistribute it and/or\n+   modify it under the terms of the GNU Lesser General Public\n+   License as published by the Free Software Foundation; either\n+   version 2.1 of the License, or (at your option) any later version.\n+\n+   The GNU C Library is distributed in the hope that it will be useful,\n+   but WITHOUT ANY WARRANTY; without even the implied warranty of\n+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+   Lesser General Public License for more details.\n+\n+   You should have received a copy of the GNU Lesser General Public\n+   License along with the GNU C Library; if not, see\n+   <https://www.gnu.org/licenses/>.  */\n+\n+#include <stdlib.h>\n+#include <time.h>\n+#include <string.h>\n+#include <argp.h>\n+#include <libintl.h>\n+#include <locale.h>\n+#include <unistd.h>\n+#include <support/support.h>\n+#include <support/check.h>\n+\n+/* Note that the final invocation of argp --help will terminate the\n+   program with exit code 0.  */\n+\n+#define PN_(ctxt, str) (str)\n+#define N_(str) (str)\n+\n+const char *argp_program_version = \"argphelp-test 1.0\";\n+\n+const struct argp_option options[] =\n+{\n+  {PN_ (\"command-line option\", \"color\"), 'c', N_ (\"HUE\"), 0, \"Rainbow!\"},\n+  {PN_ (\"command-line option\", \"flavor\"), 'f',\n+   N_ (\"COOKIE\"), OPTION_ARG_OPTIONAL, \"Sweet!\"},\n+  {PN_ (\"command-line option\", \"texture\"), 't', 0, 0, \"Smooth!\"},\n+  {0}\n+};\n+\n+static bool color_set = false;\n+\n+static error_t\n+parse_opt (int key, char *arg, struct argp_state *state)\n+{\n+  (void) state;\n+  if (key == 'c' && color_set)\n+    FAIL (\"color already set.\\n\");\n+  else if (key == 'c')\n+    color_set = true;\n+  return 0;\n+}\n+\n+static const struct argp argp = { options, parse_opt };\n+\f\n+static int\n+do_test (void)\n+{\n+  char *test1_argv[3] =\n+    { (char *) \"/bin/tst-argphelp-localized\", (char *) \"--colour=yellow\", NULL };\n+  char *test2_argv[3] =\n+    { (char *) \"/bin/tst-argphelp-localized\", (char *) \"--help\", NULL };\n+\n+  unsetenv (\"LANGUAGE\");\n+  xsetlocale (LC_ALL, \"en_GB.UTF-8\");\n+  TEST_VERIFY_EXIT (bindtextdomain (\"tst-argphelp-localized\",\n+\t\t\t\t    OBJPFX \"domaindir\") != NULL);\n+  TEST_VERIFY_EXIT (textdomain (\"tst-argphelp-localized\") != NULL);\n+  /* Check that the catalog is OK: */\n+  TEST_COMPARE_STRING (gettext (\"command-line option\\004color\"), \"colour\");\n+  TEST_COMPARE_STRING (gettext (\"COOKIE\"), \"BISCUIT\");\n+  argp_parse (&argp, 2, test1_argv, 0, 0, NULL);\n+  TEST_VERIFY (color_set);\n+  color_set = false;\n+\n+  /* This is the last chance to fail.  */\n+  if (support_record_failure_is_failed ())\n+    FAIL_EXIT1 (\"There were test failures before the final invocation of --help\");\n+  /* This last test will exit the program with code 0 and ignore\n+     previous failures.  */\n+  argp_parse (&argp, 2, test2_argv, 0, 0, NULL);\n+  FAIL_EXIT1 (\"--help did not exit the program\");\n+  return 0;\n+}\n+\n+#define TEST_FUNCTION do_test\n+#include <support/test-driver.c>\ndiff --git a/argp/tst-argphelp-localized.po b/argp/tst-argphelp-localized.po\nnew file mode 100644\nindex 0000000000..718cb39ab7\n--- /dev/null\n+++ b/argp/tst-argphelp-localized.po\n@@ -0,0 +1,25 @@\n+# English translations for a GNU C Library test.\n+# This file is distributed under the same license as the GNU C Library.\n+#\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: tst-argphelp-localized\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"Language-Team: English (British) <(nothing)>\\n\"\n+\"Language: en_GB\\n\"\n+\"MIME-Version: 1.0\\n\"\n+\"Content-Type: text/plain; charset=ASCII\\n\"\n+\"Content-Transfer-Encoding: 8bit\\n\"\n+\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n+\n+#: tst-argphelp-localized.c:73\n+msgctxt \"command-line option\"\n+msgid \"color\"\n+msgstr \"colour\"\n+\n+msgctxt \"command-line option\"\n+msgid \"flavor\"\n+msgstr \"flavour\"\n+\n+msgid \"COOKIE\"\n+msgstr \"BISCUIT\"\ndiff --git a/argp/tst-argpusage-localized.c b/argp/tst-argpusage-localized.c\nnew file mode 100644\nindex 0000000000..f93c2a156e\n--- /dev/null\n+++ b/argp/tst-argpusage-localized.c\n@@ -0,0 +1,81 @@\n+/* Test program for argp argument parser\n+   Copyright (C) 2026 Free Software Foundation, Inc.\n+   This file is part of the GNU C Library.\n+\n+   The GNU C Library is free software; you can redistribute it and/or\n+   modify it under the terms of the GNU Lesser General Public\n+   License as published by the Free Software Foundation; either\n+   version 2.1 of the License, or (at your option) any later version.\n+\n+   The GNU C Library is distributed in the hope that it will be useful,\n+   but WITHOUT ANY WARRANTY; without even the implied warranty of\n+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+   Lesser General Public License for more details.\n+\n+   You should have received a copy of the GNU Lesser General Public\n+   License along with the GNU C Library; if not, see\n+   <https://www.gnu.org/licenses/>.  */\n+\n+#include <stdlib.h>\n+#include <time.h>\n+#include <string.h>\n+#include <argp.h>\n+#include <libintl.h>\n+#include <locale.h>\n+#include <unistd.h>\n+#include <support/support.h>\n+#include <support/check.h>\n+\n+/* Note that the final invoking argp --usage will terminate the\n+   program with exit code 0.  */\n+\n+#define PN_(ctxt, str) (str)\n+#define N_(str) (str)\n+\n+const char *argp_program_version = \"argpusage-test 1.0\";\n+\n+const struct argp_option options[] =\n+{\n+  {PN_ (\"command-line option\", \"color\"), 'c', 0, 0, \"Rainbow!\"},\n+  {PN_ (\"command-line option\", \"flavor\"), 'f',\n+   N_ (\"COOKIE\"), OPTION_ARG_OPTIONAL, \"Sweet!\"},\n+  {0}\n+};\n+\n+static error_t\n+parse_opt (int key, char *arg, struct argp_state *state)\n+{\n+  return 0;\n+}\n+\n+static const struct argp argp = { options, parse_opt };\n+\f\n+static int\n+do_test (void)\n+{\n+  char *test_argv[3] =\n+    { (char *) \"/bin/tst-argpusage-localized\", (char *) \"--usage\", NULL };\n+\n+  unsetenv (\"LANGUAGE\");\n+  xsetlocale (LC_ALL, \"en_GB.UTF-8\");\n+  /* We reuse the tst-argphelp-localized domain to avoid making a new\n+     PO file.  */\n+  TEST_VERIFY_EXIT (bindtextdomain (\"tst-argphelp-localized\",\n+\t\t\t\t    OBJPFX \"domaindir\") != NULL);\n+  TEST_VERIFY_EXIT (textdomain (\"tst-argphelp-localized\") != NULL);\n+  /* Check that the catalog is OK: */\n+  TEST_COMPARE_STRING (gettext (\"command-line option\\004color\"), \"colour\");\n+  TEST_COMPARE_STRING (gettext (\"COOKIE\"), \"BISCUIT\");\n+  /* This is the last chance to fail.  */\n+  if (support_record_failure_is_failed ())\n+    FAIL_EXIT1 (\n+\t\"There were test failures before the final invocation of --usage\");\n+  /* This last test will exit the program with code 0 and ignore\n+     previous failures.  */\n+  argp_parse (&argp, 2, test_argv, 0, 0, NULL);\n+  FAIL_EXIT1 (\"--usage did not exit the program\");\n+  return 0;\n+}\n+\n+#define TEST_FUNCTION do_test\n+#include <support/test-driver.c>\ndiff --git a/manual/argp.texi b/manual/argp.texi\nindex 0023441812..97456ef20e 100644\n--- a/manual/argp.texi\n+++ b/manual/argp.texi\n@@ -206,8 +206,10 @@ messages.  @xref{Argp Help Filtering}.\n \n @item const char *argp_domain\n If non-zero, the strings used in the argp library are translated using\n-the domain described by this string.  If zero, the current default domain\n-is used.\n+the domain described by this string.  If zero, the current default\n+domain is used.  The long option names are always translated with the\n+current default domain, and with the @samp{\"command-line option\"}\n+disambiguation string.\n \n @end table\n @end deftp\n@@ -233,7 +235,9 @@ beginning, the unused fields left unspecified.\n The @code{options} field in a @code{struct argp} points to a vector of\n @code{struct argp_option} structures, each of which specifies an option\n that the argp parser supports.  Multiple entries may be used for a single\n-option provided it has multiple names.  This should be terminated by an\n+option provided it has multiple names.  In any case, option names are\n+translated, so either the translated or untranslated form is\n+recognized for each option.  This should be terminated by an\n entry with zero in all fields.  Note that when using an initialized C\n array for options, writing @code{@{ 0 @}} is enough to achieve this.\n \n@@ -247,9 +251,12 @@ the following fields:\n @item const char *name\n The long name for this option, corresponding to the long option\n @samp{--@var{name}}; this field may be zero if this option @emph{only}\n-has a short name.  To specify multiple names for an option, additional\n-entries may follow this one, with the @code{OPTION_ALIAS} flag\n-set.  @xref{Argp Option Flags}.\n+has a short name.  You should mark this string for translation with\n+the fixed @samp{\"command-line option\"} context.  To specify multiple\n+names for an option, additional entries may follow this one, with the\n+@code{OPTION_ALIAS} flag set.  @xref{Argp Option Flags}.  Translations\n+are added automatically, it is not necessary to use an alias for\n+translations.\n \n @item int key\n The integer key provided by the current option to the option parser.  If\n@@ -323,7 +330,8 @@ This option isn't displayed in any help messages.\n This option is an alias for the closest previous non-alias option.  This\n means that it will be displayed in the same help entry, and will inherit\n fields other than @code{name} and @code{key} from the option being\n-aliased.\n+aliased.  It is not necessary to list the translation of an option\n+name as an alias.\n \n \n @item OPTION_DOC\n","prefixes":["v22","3/9"]}