From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 0B5CF1FF142 for ; Mon, 02 Mar 2026 09:14:38 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 8EDE716E1B; Mon, 2 Mar 2026 09:15:38 +0100 (CET) From: Maximiliano Sandoval To: "Kefu Chai" Subject: Re: [PATCH proxmox-i18n v2] add pgettext() and npgettext() support for context-aware translations In-Reply-To: (Kefu Chai's message of "Sat, 28 Feb 2026 12:00:12 +0800") References: <20260205101613.1067594-2-k.chai@proxmox.com> <20260206054707.1465261-2-k.chai@proxmox.com> User-Agent: mu4e 1.12.9; emacs 30.1 Date: Mon, 02 Mar 2026 09:15:28 +0100 Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1772439305946 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.971 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.012 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 1.188 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 0.93 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: SEDQMYRV7RT32DMTX5BX76RP765OJ5J7 X-Message-ID-Hash: SEDQMYRV7RT32DMTX5BX76RP765OJ5J7 X-MailFrom: m.sandoval@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: "Kefu Chai" writes: > 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="$(shell cd $(2);git rev-parse HEAD)" \ >>> --msgid-bugs-address="" \ >>> --copyright-holder="Copyright (C) Proxmox Server Solutions GmbH & the translation contributors." \ >>> + --keyword=npgettext: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 JavaScript. > > 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 = 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=JavaScript test.js -o - | grep msgctxt > (empty) # MISSING! > > # JavaScript WITH --keyword flag > $ xgettext --language=JavaScript --keyword=npgettext:1c,2,3 test.js -o - | grep msgctxt > msgctxt "ctx" # GOOD! > > References: > > [1] GNU gettext manual - xgettext Invocation (Language-specific default keywords) > https://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocation.html > > [2] gettext source: x-c.c (C language keyword definitions) > https://github.com/autotools-mirror/gettext/blob/master/gettext-tools/src/x-c.c > > [3] gettext source: x-javascript.c (JavaScript language keyword definitions) > https://github.com/autotools-mirror/gettext/blob/master/gettext-tools/src/x-javascript.c > > [4] gettext 0.18.3 Release Notes (July 2013 - JavaScript support added) > https://git.savannah.gnu.org/gitweb/?p=gettext.git;a=blob;f=NEWS > Or: https://github.com/autotools-mirror/gettext/blob/master/NEWS Thanks for digging up all this! When you send a new version, please link the GNU gettext manual in the commit message with a brief explanation of why it is needed. >> >>> --output="$(1)".pot >>> endef >>> >>> diff --git a/po2js.pl b/po2js.pl >>> index 316c0bd..4b7b044 100755 >>> [..] >>> >>> 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, > 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. -- Maximiliano