From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id C27781FF145 for ; Sat, 28 Feb 2026 04:59:55 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 02C471BD5B; Sat, 28 Feb 2026 05:00:54 +0100 (CET) Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Date: Sat, 28 Feb 2026 12:00:12 +0800 Message-Id: Subject: Re: [PATCH proxmox-i18n v2] add pgettext() and npgettext() support for context-aware translations From: "Kefu Chai" To: "Maximiliano Sandoval" X-Mailer: aerc 0.20.0 References: <20260205101613.1067594-2-k.chai@proxmox.com> <20260206054707.1465261-2-k.chai@proxmox.com> In-Reply-To: X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1772251197290 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.821 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_SHORT 0.001 Use of a URL Shortener for very short URL RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.706 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.401 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 1.026 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: UORNLJL3WNHOMYIYO6PNBRVN6563IGRQ X-Message-ID-Hash: UORNLJL3WNHOMYIYO6PNBRVN6563IGRQ X-MailFrom: k.chai@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: pve-devel@lists.proxmox.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On Tue Feb 17, 2026 at 11:45 PM CST, Maximiliano Sandoval wrote: Hi Maximiliano, Thanks for the detailed testing and feedback! I've addressed all the points you raised. > Kefu Chai writes: > > Thanks for the update. Comments below. > >> This commit adds message context (msgctxt) support to the JavaScript >> [..] >> Makefile | 1 + >> po2js.pl | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-------- >> 2 files changed, 61 insertions(+), 9 deletions(-) >> >> diff --git a/Makefile b/Makefile >> index 86bd723..3feaee7 100644 >> --- a/Makefile >> +++ b/Makefile >> @@ -155,6 +155,7 @@ define potupdate >> --package-version=3D"$(shell cd $(2);git rev-parse HEAD)" \ >> --msgid-bugs-address=3D"" \ >> --copyright-holder=3D"Copyright (C) Proxmox Server Solutions GmbH= & the translation contributors." \ >> + --keyword=3Dnpgettext:1c,2,3 \ > > You were right in your previous reply, however as I mentioned, gettext > by default has keys for gettext, ngettext, pgettext and npgettext. There > is no need to add this here. I investigated this further and found that while this is true for C/C++, it= 's not true for JavaScript. The --keyword flag is actually required. According to the GNU gettext manual [1], the default keywords are language-specific: For C, C++, GCC-source: gettext, dgettext:2, dcgettext:2, ngettext:1,2, dngettext:2,3, dcngettext:2,3, gettext_noop, pgettext:1c,2, dpgettext:2c,3, dcpgettext:2c,3, npgettext:1c,2,3, dnpgettext:2c,3,4, dcnpgettext:2c,3,= 4 For JavaScript, TypeScript, TSX: _, gettext, dgettext:2, dcgettext:2, ngettext:1,2, dngettext:2,3, pgettext:1c,2, dpgettext:2c,3 Notice that npgettext is present in C/C++ defaults but ABSENT from JavaScri= pt. The xgettext source code confirms this. In gettext-tools/src/x-c.c [2]: static void init_keywords () { if (default_keywords) { x_c_keyword ("gettext"); x_c_keyword ("dgettext:2"); x_c_keyword ("dcgettext:2"); x_c_keyword ("ngettext:1,2"); x_c_keyword ("dngettext:2,3"); x_c_keyword ("dcngettext:2,3"); x_c_keyword ("gettext_noop"); x_c_keyword ("pgettext:1c,2"); x_c_keyword ("dpgettext:2c,3"); x_c_keyword ("dcpgettext:2c,3"); x_c_keyword ("npgettext:1c,2,3"); /* <- present for C */ x_c_keyword ("dnpgettext:2c,3,4"); x_c_keyword ("dcnpgettext:2c,3,4"); // ... } } But in gettext-tools/src/x-javascript.c [3]: static void init_keywords () { if (default_keywords) { x_javascript_keyword ("gettext"); x_javascript_keyword ("dgettext:2"); x_javascript_keyword ("dcgettext:2"); x_javascript_keyword ("ngettext:1,2"); x_javascript_keyword ("dngettext:2,3"); x_javascript_keyword ("pgettext:1c,2"); x_javascript_keyword ("dpgettext:2c,3"); x_javascript_keyword ("_"); /* npgettext is NOT here */ /* <- absent for JavaScript */ default_keywords =3D false; } } The official release notes for gettext 0.18.3 (July 2013) [4] explain the reason of the difference: "JavaScript: xgettext now partially supports JavaScript. Since the current JavaScript specification (ECMA-262) does not define the standard set of formatting methods nor translation functions, the implementation supports only a limited set of formatting methods and translation functions commonly used in Gjs and other popular JavaScript implementations and libraries." This was a deliberate design decision to include only commonly-used functions in the JavaScript defaults. The context+plural combination (npgettext) was apparently not common enough in 2013 to be included. We can confirm with testing: # C: npgettext extracted by default $ echo 'npgettext("ctx", "s", "p", n);' > test.c $ xgettext test.c -o - | grep msgctxt msgctxt "ctx" # GOOD! # JavaScript: npgettext NOT extracted without --keyword $ echo 'npgettext("ctx", "s", "p", n);' > test.js $ xgettext --language=3DJavaScript test.js -o - | grep msgctxt (empty) # MISSING! # JavaScript WITH --keyword flag $ xgettext --language=3DJavaScript --keyword=3Dnpgettext:1c,2,3 test.js -= o - | grep msgctxt msgctxt "ctx" # GOOD! References: [1] GNU gettext manual - xgettext Invocation (Language-specific default key= words) https://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocati= on.html [2] gettext source: x-c.c (C language keyword definitions) https://github.com/autotools-mirror/gettext/blob/master/gettext-tools/s= rc/x-c.c [3] gettext source: x-javascript.c (JavaScript language keyword definitions= ) https://github.com/autotools-mirror/gettext/blob/master/gettext-tools/s= rc/x-javascript.c [4] gettext 0.18.3 Release Notes (July 2013 - JavaScript support added) https://git.savannah.gnu.org/gitweb/?p=3Dgettext.git;a=3Dblob;f=3DNEWS Or: https://github.com/autotools-mirror/gettext/blob/master/NEWS > >> --output=3D"$(1)".pot >> endef >> =20 >> diff --git a/po2js.pl b/po2js.pl >> index 316c0bd..4b7b044 100755 >> [..] >> =20 >> if ($outfile) { > > > I tested this with pve-manager. > > - Sprinkled a few uses of pgettext > - Extracted the strings with make do_update at proxmox-i18n > - Translated two strings with context > - Checked that the translated string were visible at the web UI and that > each one had the correct translation given its context > > To make the above work I had to patch proxmox-biome to accept the > ngettext and pngettext keywords: > > modified src/biome.json > @@ -128,7 +128,9 @@ > "Proxmox", > "eslint", > "ngettext", > - "gettext" > + "gettext", > + "pgettext", > + "npgettext" > ] > } > } Updated proxmox-biome/src/biome.json to add pgettext and npgettext to the globals list. Will send a separate patch to the mailing list. > > Otherwise `make deb` would fail when building the .debs. > > I also had to modify the index.html.tpl to pve-manager to have default > implementations for these fns, otherwise the UI won't work if there is > no language selected (which is the default): Done. Added default implementations to all three locations: - pve-manager/www/index.html.tpl - proxmox-backup/www/index.hbs - pmg-gui/pmg-index.html.tt Will update them separately, and bump up the submodules in the next revision of this patch once these patches land. FWIW, to replicate your testing approach, I performed the following verification: 1. Added pgettext/npgettext test translation to zh_CN.po,=20 2. Generated JavaScript with po2js.pl: ./po2js.pl -t pve -v "3.6.6" -o pve-lang-zh_CN-test.js zh_CN.po 3. Verified context-aware translations in generated JavaScript manually. Also, I built all .deb packages with: make deb > > modified www/index.html.tpl > @@ -27,6 +27,8 @@ > > [% END %] > [%- IF debug %] > > There are similar files at pmg-gui and proxmox-backup-server that would > also need updating.