all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: "Kefu Chai" <k.chai@proxmox.com>
To: "Maximiliano Sandoval" <m.sandoval@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [PATCH proxmox-i18n v2] add pgettext() and npgettext() support for context-aware translations
Date: Sat, 28 Feb 2026 12:00:12 +0800	[thread overview]
Message-ID: <DGQAMFGI228C.2B28HGE88ODBC@proxmox.com> (raw)
In-Reply-To: <s8ov7fvmkzs.fsf@proxmox.com>

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 <k.chai@proxmox.com> 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="<support@proxmox.com>" \
>>        --copyright-holder="Copyright (C) Proxmox Server Solutions GmbH <support@proxmox.com> & 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

>
>>        --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 @@
>      <script type='text/javascript'>
>          function gettext(message) { return message; }
>          function ngettext(singular, plural, count) { return count === 1 ? singular : plural; }
> +        function pgettext(context, message) { return message; }
> +        function pngettext(context, singular, plural, count) { return count === 1 ? singular : plural; }
>      </script>
>      [% END %]
>      [%- IF debug %]
>
> There are similar files at pmg-gui and proxmox-backup-server that would
> also need updating.





  reply	other threads:[~2026-02-28  3:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-05 10:16 [PATCH proxmox-i18n v1] " Kefu Chai
2026-02-05 13:15 ` Maximiliano Sandoval
2026-02-06  5:44   ` Kefu Chai
2026-02-06  5:47 ` [PATCH proxmox-i18n v2] " Kefu Chai
2026-02-17 15:45   ` Maximiliano Sandoval
2026-02-28  4:00     ` Kefu Chai [this message]
2026-03-02  8:15       ` Maximiliano Sandoval

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DGQAMFGI228C.2B28HGE88ODBC@proxmox.com \
    --to=k.chai@proxmox.com \
    --cc=m.sandoval@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal