Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2227406/?format=api
{ "id": 2227406, "url": "http://patchwork.ozlabs.org/api/patches/2227406/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/patch/2955a3592a6b97298fbcd76ba9eb152739e6e363.1776957778.git.vivien@planete-kraus.eu/", "project": { "id": 41, "url": "http://patchwork.ozlabs.org/api/projects/41/?format=api", "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": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<2955a3592a6b97298fbcd76ba9eb152739e6e363.1776957778.git.vivien@planete-kraus.eu>", "list_archive_url": null, "date": "2026-04-23T16:04:06", "name": "[v22,8/9] posix: Add a script for static validation of getopt_long PO files", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "2fced3cee18a81c7a76f3e349bc0ec053072ab2e", "submitter": { "id": 90948, "url": "http://patchwork.ozlabs.org/api/people/90948/?format=api", "name": "Vivien Kraus", "email": "vivien@planete-kraus.eu" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/glibc/patch/2955a3592a6b97298fbcd76ba9eb152739e6e363.1776957778.git.vivien@planete-kraus.eu/mbox/", "series": [ { "id": 501215, "url": "http://patchwork.ozlabs.org/api/series/501215/?format=api", "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/2227406/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2227406/checks/", "tags": {}, "related": [], "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=uYMhQj78;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=38.145.34.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=uYMhQj78", "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=2a00:5881:4008:2810::309" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.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 4g1gxg13xtz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 02:08:39 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 417D94BBC0C6\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 16:08:37 +0000 (GMT)", "from planete-kraus.eu (planete-kraus.eu\n [IPv6:2a00:5881:4008:2810::309])\n by sourceware.org (Postfix) with ESMTPS id 2B9314B87B99\n for <libc-alpha@sourceware.org>; Thu, 23 Apr 2026 16:05:55 +0000 (GMT)", "from planete-kraus.eu (localhost [127.0.0.1])\n by planete-kraus.eu (OpenSMTPD) with ESMTP id 3e682d36;\n Thu, 23 Apr 2026 16:05:43 +0000 (UTC)", "by planete-kraus.eu (OpenSMTPD) with ESMTPSA id 0b40b333\n (TLSv1.3:TLS_CHACHA20_POLY1305_SHA256:256:NO);\n Thu, 23 Apr 2026 16:05:41 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 417D94BBC0C6", "OpenDKIM Filter v2.11.0 sourceware.org 2B9314B87B99" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 2B9314B87B99", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 2B9314B87B99", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776960355; cv=none;\n b=YEwMdSlOp3gtuizkkf8lkTAjtwoDOWNRS7aPOvB4X+Z/9vh83tCoZMahN+5lTNynQAifqJcQeX2wLQleTFTjZZIjOeCVKrNJ0FdnnYJi6wxY2rZbJ0RsM29Pbor/kPBcnkjLS3UNNLYIYD9Vt5QIFsP32w2yILi2skfrwgdz08Q=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776960355; c=relaxed/simple;\n bh=i+4Wuw8L9h8suYBLhyS5MO13nksynonVNFWamuDXcRE=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=kJi/s7rd0UO5EjBZS9EkY89SKtDwjuasItUGdH1fbP7H4YMEuX2Irpwg2dx7D52dJcEAXdWx8QhOGBkspzKP8FQg5oJfIkCiR68RS39HSHNHOo+aAkHCqPENuiR8VdMqNO4zel3lOLPw3oa+vVC/ZN9zcuGy0tP5Y6hupj+zf0I=", "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=MvYut27SYpjwbiSsccm5JJfsfTk=; b=uYMhQj7866NwjXvFAj\n B5yUAEwgicaUVGn6dbSDago+STNdr96Ej2wybpvUGh0mVw6F8PU2coRTpXFP+1Xe\n Q2rbDIZnZYpUGT7bYZ/9eI1CRSMWaiUB+9UlEn4rUItpzp2SNfifFknA9/HqJpaW\n Dj5v0kbhdgNtlXeAP+6f3JpN+AxbQufL8MrAhpcBR4UjqSxkheVZcGWUC9heOo7o\n IPd8qLos/8slhmOEP8SCyjHpQxN5MJvsoJakVuXW+MZcWMogTEGxImFI3MnDZ6se\n LjgX5NUurESWGJXS+8+oxdKbD/82kSncEtVx3DJocfTKTEll287GG55z58H+G2go\n G9xw==", "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 8/9] posix: Add a script for static validation of\n getopt_long PO files", "Date": "Thu, 23 Apr 2026 18:04:06 +0200", "Message-ID": "\n <2955a3592a6b97298fbcd76ba9eb152739e6e363.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": "It is better to statically check the PO files on the developer’s side,\nbecause there is a chance to detect the problem early and not\nembarrass the translation team just before a release.\n\nThis is a perl script that I made by adapting bits and pieces from\nmtrace.pl. On the test case, it should fail with the following output:\n\n-----\nTranslation toto is used for more than one option:\n - bar\n - foo\nbar is a translation of pub, but it is also a different option.\nThere were 2 failures.\n-----\n---\n NEWS | 3 +\n manual/getopt.texi | 13 ++\n manual/install.texi | 7 +-\n posix/Makefile | 28 ++-\n posix/check-getopt-translations.pl | 195 ++++++++++++++++++\n .../standalone-multiple-getopt-collisions.po | 45 ++++\n posix/tst-check-getopt-translations.sh | 61 ++++++\n 7 files changed, 348 insertions(+), 4 deletions(-)\n create mode 100644 posix/check-getopt-translations.pl\n create mode 100644 posix/standalone-multiple-getopt-collisions.po\n create mode 100644 posix/tst-check-getopt-translations.sh", "diff": "diff --git a/NEWS b/NEWS\nindex 48f7589f49..11cef60879 100644\n--- a/NEWS\n+++ b/NEWS\n@@ -25,6 +25,9 @@ Major new features:\n * Argp parsers enable translated long option names with \"command-line\n option\" as the message context.\n \n+* The new installed script check-getopt-translations parses PO files to\n+ check for collisions between long option names and translations.\n+\n Deprecated and removed features, and other changes affecting compatibility:\n \n * Although malloc and related functions currently return pointers\ndiff --git a/manual/getopt.texi b/manual/getopt.texi\nindex dbee16b62e..e39f3e3f85 100644\n--- a/manual/getopt.texi\n+++ b/manual/getopt.texi\n@@ -394,6 +394,19 @@ not match a long option (or its abbreviation).\n \n @end deftypefun\n \n+It is possible for the programmer to introduce a new option name that\n+conflicts with the translation of an existing option name. Such a\n+case would disrupt the workflow of users as the new option would\n+replace the existing option. Before adding a new option to a program,\n+the developer should check for collisions with all known translations.\n+This can be done with the installed\n+@command{check-getopt-translations} script, by calling for each PO\n+file in the project:\n+\n+@smallexample\n+check-getopt-translations \"context used for translations\" @file{file.po}\n+@end smallexample\n+\n @node Getopt Long Option Example\n @subsection Example of Parsing Long Options with @code{getopt_long}\n \ndiff --git a/manual/install.texi b/manual/install.texi\nindex 073cda0530..2d0e78f64a 100644\n--- a/manual/install.texi\n+++ b/manual/install.texi\n@@ -601,9 +601,10 @@ verified to work to build @theglibc{}.\n Perl 5\n \n Perl is not required, but if present it is used in some tests and the\n-@code{mtrace} program, to build the @glibcadj{} manual. As of release\n-time @code{perl} version 5.42.0 is the newest verified to work to\n-build @theglibc{}.\n+@code{mtrace} program, to build the @glibcadj{} manual. It is also\n+used for the @code{check-getopt-translations} installed script. As of\n+release time @code{perl} version 5.42.0 is the newest verified to work\n+to build @theglibc{}.\n \n @item\n GNU @code{sed} 3.02 or newer\ndiff --git a/posix/Makefile b/posix/Makefile\nindex e8d5d0661c..0f99241d4a 100644\n--- a/posix/Makefile\n+++ b/posix/Makefile\n@@ -379,7 +379,7 @@ xtests-time64 := \\\n \n ifeq (yes,$(build-shared))\n test-srcs := \\\n- globtest\n+ globtest \\\n # tests-src\n tests += \\\n tst-exec \\\n@@ -390,6 +390,11 @@ tests += \\\n # tests\n endif\n \n+ifneq ($(PERL),no)\n+test-srcs += \\\n+ tst-check-getopt-translations\n+endif\n+\n ifeq (yesyes,$(build-shared)$(have-thread-library))\n tests += \\\n tst-_Fork \\\n@@ -419,6 +424,9 @@ install-others-programs := \\\n $(inst_libexecdir)/getconf \\\n # install-others-programs\n \n+install-bin-script = check-getopt-translations\n+generated += check-getopt-translations\n+\n before-compile += \\\n $(objpfx)posix-conf-vars-def.h \\\n # before-compile\n@@ -431,6 +439,7 @@ generated += \\\n getconf.speclist \\\n ptestcases.h \\\n testcases.h \\\n+ tst-check-getopt-translations.out \\\n tst-getconf.out \\\n wordexp-tst.out \\\n # generated\n@@ -509,6 +518,11 @@ endif\n endif\n endif\n \n+ifneq ($(PERL),no)\n+tests-special += \\\n+ $(objpfx)tst-check-getopt-translations.out\n+endif\n+\n include ../Rules\n \n ifeq ($(run-built-tests),yes)\n@@ -826,3 +840,15 @@ $(tst_getopt_long_collision_mo): tst-getopt_long_collision.po\n \n $(objpfx)tst-getopt_long_collision.out: $(tst_getopt_long_collision_mo) $(gen-locales)\n CFLAGS-tst-getopt_long_collision.c += -DOBJPFX=\\\"$(objpfx)\\\"\n+\n+$(objpfx)check-getopt-translations: check-getopt-translations.pl\n+\trm -f $@.new\n+\tsed -e 's|@XXX@|$(address-width)|' \\\n+\t -e 's|@VERSION@|$(version)|' \\\n+\t -e 's|@PKGVERSION@|$(PKGVERSION)|' \\\n+\t -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $^ > $@.new \\\n+\t&& rm -f $@ && mv $@.new $@ && chmod +x $@\n+\n+$(objpfx)tst-check-getopt-translations.out: tst-check-getopt-translations.sh $(objpfx)check-getopt-translations standalone-multiple-getopt-collisions.po\n+\t$(SHELL) $^ $(common-objpfx)posix/tst-check-getopt-translations.out\n+\t$(evaluate-test)\ndiff --git a/posix/check-getopt-translations.pl b/posix/check-getopt-translations.pl\nnew file mode 100644\nindex 0000000000..c3c3cff1eb\n--- /dev/null\n+++ b/posix/check-getopt-translations.pl\n@@ -0,0 +1,195 @@\n+#! /usr/bin/perl\n+\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+use strict;\n+use warnings;\n+use Data::Dumper;\n+\n+my $VERSION = \"@VERSION@\";\n+\n+my $PKGVERSION = \"@PKGVERSION@\";\n+my $REPORT_BUGS_TO = '@REPORT_BUGS_TO@';\n+my $progname = $_;\n+\n+sub usage {\n+ print \"Usage: getopt-check [OPTION]... msgctxt lang.po\\n\";\n+ print \" --help print this help, then exit\\n\";\n+ print \" --version print version number, then exit\\n\";\n+ print \"\\n\";\n+ print \"For bug reporting instructions, please see:\\n\";\n+ print \"$REPORT_BUGS_TO.\\n\";\n+ exit 0;\n+}\n+\n+sub fatal {\n+ print STDERR \"$_[0]\\n\";\n+ exit 1;\n+}\n+\n+# This script takes two positional arguments: the context for\n+# translated option names, and the PO file to check. Then, the PO\n+# file is parsed, looking at three things:\n+# 1. The msgctxt: it must be equal to the first positional argument, msgctxt;\n+# 2. The msgid;\n+# 3. The space-separated list msgstr.\n+#\n+# We are looking for two different problems:\n+#\n+# 1. Every translation element, current or obsolete, must be unique\n+# across all option names.\n+# 2. For every option name, for every translation, current or\n+# deprecated, if it doesn’t match the untranslated name, then it\n+# should not match any other untranslated option names.\n+#\n+# If we detect an example of the first case, it is a problem with the\n+# translator only. They have to remove one use of the word,\n+# preferably one that is deprecated.\n+#\n+# If we detect an example of the second case, then it is a problem\n+# with the developer: they want to introduce an option name that is\n+# already used for something else by users of this native language! If\n+# nothing is done, these users will be surprised that the same word\n+# now means another option, as the untranslated options have\n+# precedence over the translations. If the translated name is already\n+# deprecated, then the language team may agree to completely remove\n+# it. Otherwise, it may be better to find a new untranslated name.\n+\n+ arglist: while (@ARGV) {\n+ if ($ARGV[0] eq \"--v\" || $ARGV[0] eq \"--ve\" || $ARGV[0] eq \"--ver\" ||\n+\t$ARGV[0] eq \"--vers\" || $ARGV[0] eq \"--versi\" ||\n+\t$ARGV[0] eq \"--versio\" || $ARGV[0] eq \"--version\") {\n+\tprint \"getopt-check $PKGVERSION$VERSION\\n\";\n+\tprint \"Copyright (C) 2026 Free Software Foundation, Inc.\\n\";\n+\tprint \"This is free software; see the source for copying conditions. There is NO\\n\";\n+\tprint \"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\\n\";\n+\tprint \"Written by Vivien Kraus <vivien\\@planete-kraus.eu>\\n\";\n+\n+\texit 0;\n+ } elsif ($ARGV[0] eq \"--h\" || $ARGV[0] eq \"--he\" || $ARGV[0] eq \"--hel\" ||\n+\t $ARGV[0] eq \"--help\") {\n+\t&usage;\n+ } elsif ($ARGV[0] =~ /^-/) {\n+\tprint \"$progname: unrecognized option `$ARGV[0]'\\n\";\n+\tprint \"Try `$progname --help' for more information.\\n\";\n+\texit 1;\n+ } else {\n+\tlast arglist;\n+ }\n+}\n+\n+if ($#ARGV != 1) {\n+ fatal \"You must provide two arguments: the msgctxt for option names, and the name of the PO file.\";\n+}\n+\n+my $relevant_msgctxt = $ARGV[0];\n+my $pofilename = $ARGV[1];\n+my %translations;\n+\n+# %translation_used will be populated to detect multiple use of a\n+# %translation directly when we parse.\n+\n+my $entry_msgid;\n+\n+# The ad-hoc PO file parser has 3 states:\n+# 1. Waiting for msgctxt;\n+# 2. Waiting for msgid;\n+# 3. Waiting for msgstr.\n+#\n+# At the start, the state is 1. Then, if we find \"msgctxt\n+# \\\"$relevant_msgctxt\\\"\" in a single line, we jump to 2. Otherwise,\n+# if this is the end of the file, stop parsing. Otherwise, whatever\n+# the line, stay in 1. This includes: the empty line, meaning we are\n+# considering a new entry; or a comment, a #: location, or another\n+# relevant line.\n+#\n+# When we are in state 2., we are waiting for the msgid (untranslated\n+# option name). If we find an empty line, we jump back to 1. If we\n+# find a line starting with \"msgid \\\"\" and ending with a double quote,\n+# we store what is in the middle in $entry_msgid and jump to 3.\n+# Otherwise, we stay in state 2.\n+#\n+# When we are in state 3., we are waiting for msgstr. If we find an\n+# empty line, drop $entry_msgid, and back to 1. If the line starts\n+# with \"msgstr \\\"\", we add a record to %translations: the key is\n+# $entry_msgid, and the value, what is between the detected prefix and\n+# the end quote. Then, back to state 1.\n+\n+my $parser_state = 1;\n+\n+open (my $pofile, \"<\", $pofilename) || fatal \"PO file name ${pofilename} cannot be read.\";\n+\n+while (my $line = <$pofile>) {\n+ chomp $line;\n+ if ($parser_state == 1 && $line =~ /^msgctxt\\s*\"${relevant_msgctxt}\"$/) {\n+ $parser_state = 2;\n+ } elsif ($parser_state == 2 && $line eq \"\") {\n+ $parser_state = 1;\n+ } elsif ($parser_state == 2 && $line =~ /^msgid\\s*\"([^\"]+)\"$/) {\n+ $parser_state = 3;\n+ $entry_msgid = $1;\n+ } elsif ($parser_state == 3 && $line eq \"\") {\n+ $parser_state = 1;\n+ } elsif ($parser_state == 3 && $line =~ /^msgstr\\s*\"([^\"]*)\"$/) {\n+ $translations{$entry_msgid} = $1;\n+ $parser_state = 1;\n+ }\n+}\n+\n+my $number_of_errors = 0;\n+\n+# Verify that every option name is unique.\n+my %untranslated_name;\n+for my $option_name (sort(keys %translations)) {\n+ my $translation = $translations{$option_name};\n+ my @existing;\n+ if (exists $untranslated_name{$translation}) {\n+\t@existing = @{$untranslated_name{$translation}};\n+ }\n+ push(@existing, $option_name);\n+ $untranslated_name{$translation} = \\@existing;\n+}\n+for my $translation (sort(keys %untranslated_name)) {\n+ my $names = $untranslated_name{$translation};\n+ if (@{$names} > 1) {\n+ print STDERR \"Translation ${translation} is used for more than one option:\\n\";\n+ for my $untranslated (@{$names}) {\n+ print STDERR \" - ${untranslated}\\n\";\n+ }\n+ ++$number_of_errors;\n+ }\n+}\n+\n+# Verify that every option translation does not match any other\n+# untranslated name.\n+for my $option_name (sort(keys %translations)) {\n+ for my $other_option_name (sort(keys %translations)) {\n+ if ($option_name ne $other_option_name) {\n+\t if ($translations{$option_name} eq $other_option_name) {\n+\t\tprint STDERR \"${translations{$option_name}} is a translation of ${option_name}, but it is also a different option.\\n\";\n+\t\t++$number_of_errors;\n+\t }\n+ }\n+ }\n+}\n+\n+if ($number_of_errors eq 0) {\n+ exit 0\n+}\n+print STDERR \"There were ${number_of_errors} failures.\\n\";\n+exit 1\ndiff --git a/posix/standalone-multiple-getopt-collisions.po b/posix/standalone-multiple-getopt-collisions.po\nnew file mode 100644\nindex 0000000000..14b876a2a3\n--- /dev/null\n+++ b/posix/standalone-multiple-getopt-collisions.po\n@@ -0,0 +1,45 @@\n+# French translations for the getopt static checker\n+# Copyright (C) 2026 THE GNU C Library'S COPYRIGHT HOLDER\n+# This file is distributed under the same license as the GNU C Library.\n+#\n+# This has two errors:\n+# 1. \"toto\" is used both as a translation of \"foo\" and \"bar\";\n+# 2. \"bar\" is used as a translation of \"pub\", but it is another option.\n+msgid \"\"\n+msgstr \"\"\n+\"Project-Id-Version: GNU C Library (see version.h)\\n\"\n+\"Report-Msgid-Bugs-To: \\n\"\n+\"POT-Creation-Date: 2025-06-06 22:37+0200\\n\"\n+\"PO-Revision-Date: 2025-06-06 22:38+0200\\n\"\n+\"Language-Team: French <traduc@traduc.org>\\n\"\n+\"Language: fr\\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+# This is not an option name, so it’s OK for it to clash with option\n+# names.\n+msgctxt \"fish\"\n+msgid \"bass\"\n+msgstr \"bar\"\n+\n+# This is the --foo option.\n+msgctxt \"command-line option\"\n+msgid \"foo\"\n+msgstr \"toto\"\n+\n+# This is the --bar option. Oops, I translated with toto here too.\n+msgctxt \"command-line option\"\n+msgid \"bar\"\n+msgstr \"toto\"\n+\n+# Let’s go to the --pub!\n+msgctxt \"command-line option\"\n+msgid \"pub\"\n+msgstr \"bar\"\n+\n+# Wait, it’s OK if baz is translated to baz though.\n+msgctxt \"command-line option\"\n+msgid \"baz\"\n+msgstr \"baz\"\ndiff --git a/posix/tst-check-getopt-translations.sh b/posix/tst-check-getopt-translations.sh\nnew file mode 100644\nindex 0000000000..038fa3eafa\n--- /dev/null\n+++ b/posix/tst-check-getopt-translations.sh\n@@ -0,0 +1,61 @@\n+#!/bin/sh\n+# Test for check-getopt-translations.\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+set -e\n+\n+check_getopt_translations_program=$1; shift\n+po_file=$1; shift\n+logfile=$1; shift\n+\n+rm -f $logfile\n+result=0\n+expected_output=\"\\\n+Translation toto is used for more than one option:\n+ - bar\n+ - foo\n+bar is a translation of pub, but it is also a different option.\n+There were 2 failures.\"\n+\n+if output=$(${check_getopt_translations_program} \"command-line option\" ${po_file} 2>&1) ; then\n+ echo \"the errors were not caught.\" >> $logfile\n+ echo \"*** check-getopt-translations FAILED\" >> $logfile\n+ result=1\n+fi\n+\n+if test \"$output\" != \"$expected_output\"; then\n+ echo \"Expected:\" >> $logfile\n+ echo \"$expected_output\" >> $logfile\n+ echo \"Actual:\" >> $logfile\n+ echo \"$output\" >> $logfile\n+ echo \"*** check-getopt-translations FAILED\" >> $logfile\n+ result=1\n+fi\n+\n+echo \"*** check-getopt-translations PASSED\" >> $logfile\n+\n+exit $result\n+\n+# Preserve executable bits for this shell script.\n+Local Variables:\n+eval:(defun frobme () (set-file-modes buffer-file-name file-mode))\n+eval:(make-local-variable 'file-mode)\n+eval:(setq file-mode (file-modes (buffer-file-name)))\n+eval:(make-local-variable 'after-save-hook)\n+eval:(add-hook 'after-save-hook 'frobme)\n+End:\n", "prefixes": [ "v22", "8/9" ] }