Обсуждение: PRI?64 vs Visual Studio (2022)

Поиск
Список
Период
Сортировка

PRI?64 vs Visual Studio (2022)

От
Kyotaro Horiguchi
Дата:
Hello,

If you're already aware of this and have taken it into account, please
feel free to ignore this.

As described in the recent commit a0ed19e0a9e, many %ll? format
specifiers are being replaced with %<PRI?64>.

I hadn’t paid much attention to this before, but I happened to check
how this behaves on Windows, and it seems that with VS2022, PRId64
expands to "%lld". As a result, I suspect the gettext message catalog
won't match these messages correctly.

I haven't been able to build with -Dnls=enabled myself, but I did
check the strings embedded in a binary compiled with VS2022, and they
indeed use %lld.

Just wanted to share this in case it’s helpful.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center

Re: PRI?64 vs Visual Studio (2022)

От
Peter Eisentraut
Дата:
On 31.03.25 08:28, Kyotaro Horiguchi wrote:
> If you're already aware of this and have taken it into account, please
> feel free to ignore this.
> 
> As described in the recent commit a0ed19e0a9e, many %ll? format
> specifiers are being replaced with %<PRI?64>.
> 
> I hadn’t paid much attention to this before, but I happened to check
> how this behaves on Windows, and it seems that with VS2022, PRId64
> expands to "%lld". As a result, I suspect the gettext message catalog
> won't match these messages correctly.

I think this is working correctly.  Gettext has a built-in mechanism to 
translate the %<PRI...> back to the appropriate  %lld or %ld.  See also 
<https://www.gnu.org/software/gettext/manual/html_node/c_002dformat.html>.




Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Wed, Apr 2, 2025 at 2:04 AM Peter Eisentraut <peter@eisentraut.org> wrote:
> On 31.03.25 08:28, Kyotaro Horiguchi wrote:
> > I hadn’t paid much attention to this before, but I happened to check
> > how this behaves on Windows, and it seems that with VS2022, PRId64
> > expands to "%lld". As a result, I suspect the gettext message catalog
> > won't match these messages correctly.
>
> I think this is working correctly.  Gettext has a built-in mechanism to
> translate the %<PRI...> back to the appropriate  %lld or %ld.  See also
> <https://www.gnu.org/software/gettext/manual/html_node/c_002dformat.html>.

Interesting report though.  Commit 962da900 assumed that our in-tree
printf implementation still needed to understand that %I64 stuff in
case it came to us from system headers, but it looks like it
disappeared with MSVCRT:

1. I checked with CI (VS 2019).  puts(PRId64) prints out "lld".
2. MinGW's inttypes.h[1] only uses "I64" et al if you build against MSVCRT.

So I think we should delete that stuff.  Attached.

I worried that GNU gettext() might still know about %I64 somewhere,
but it just expands the macros to whatever inttypes.h defines[2].
Good.

We don't even test -Dnls on the Windows CI task, so the fact that it
passes there doesn't mean much (if our tests would even pick up
<PRI*64> expansion failure, not sure).  We should probably do
something about that and/or its absence from the build farm.  We're
effectively counting on the EDB packaging team or end users to tell us
if we break localisation on this platform.

I was also curious to know if the nearby floating point formatting
kludge added by commit f1885386 was still needed today.  CI passes
without it, and the standard is pretty clear: "The exponent always
contains at least two digits, and only as many more digits as
necessary to represent the exponent".  I didn't look too closely at
the fine print, but that text was already present in C89 so I guess
MSVCRT just failed to conform on that point.

[1] https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-headers/crt/inttypes.h
[2]
https://github.com/autotools-mirror/gettext/blob/637b208fbe13f1c306f19d4f31c21fec7e9986d2/gettext-runtime/intl/loadmsgcat.c#L473

Вложения

Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
Thomas Munro <thomas.munro@gmail.com> writes:
> We don't even test -Dnls on the Windows CI task, so the fact that it
> passes there doesn't mean much (if our tests would even pick up
> <PRI*64> expansion failure, not sure).  We should probably do
> something about that and/or its absence from the build farm.  We're
> effectively counting on the EDB packaging team or end users to tell us
> if we break localisation on this platform.

I'm pretty certain that we do not test NLS localization at all,
anywhere :-(.  (There are no test cases checking enable_nls,
which would be a necessary thing to not fail on buildfarm critters
not using NLS.)

I agree that starting to rely on PRI?64 in translatable strings
is raising the bar a good deal, so maybe it's time to do something
about that.

            regards, tom lane



Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Wed, Nov 19, 2025 at 3:28 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> I agree that starting to rely on PRI?64 in translatable strings
> is raising the bar a good deal, so maybe it's time to do something
> about that.

Perhaps meson/configure should do a po -> mo -> gettext() check with a
canned test message?  That'd also make sure your msgfmt and libintl
are compatible, something I worried about when I wrote about musl
recently.



Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
Thomas Munro <thomas.munro@gmail.com> writes:
> Perhaps meson/configure should do a po -> mo -> gettext() check with a
> canned test message?  That'd also make sure your msgfmt and libintl
> are compatible, something I worried about when I wrote about musl
> recently.

No, I don't think that's a good approach.  That is testing the library
available at configure time, not the one you are actually running
with (possibly years later and on a different machine, even without
considering cross-compilation cases).  I think we should do it
honestly with a regression test.  It doesn't need to be very
complicated --- I think checking one message in one translation is
sufficient, so long as it includes a PRI?64 usage.

            regards, tom lane



Re: PRI?64 vs Visual Studio (2022)

От
Peter Eisentraut
Дата:
On 19.11.25 04:15, Tom Lane wrote:
> Thomas Munro <thomas.munro@gmail.com> writes:
>> Perhaps meson/configure should do a po -> mo -> gettext() check with a
>> canned test message?  That'd also make sure your msgfmt and libintl
>> are compatible, something I worried about when I wrote about musl
>> recently.
> 
> No, I don't think that's a good approach.  That is testing the library
> available at configure time, not the one you are actually running
> with (possibly years later and on a different machine, even without
> considering cross-compilation cases).  I think we should do it
> honestly with a regression test.  It doesn't need to be very
> complicated --- I think checking one message in one translation is
> sufficient, so long as it includes a PRI?64 usage.

We could generate an English message catalog that translates all 
messages unchanged, and run the whole test suite with that.  This would 
exercise the whole gettext run-time machinery.

Generating the message catalog is easy, gettext provides a tool for 
that.  What's a little tricky is convincing all our testing 
infrastructure to *not* disable NLS-related locale settings.  See 
attached for a rough, incomplete demo.

Вложения

Re: PRI?64 vs Visual Studio (2022)

От
Peter Eisentraut
Дата:
On 19.11.25 03:13, Thomas Munro wrote:
> Interesting report though.  Commit 962da900 assumed that our in-tree
> printf implementation still needed to understand that %I64 stuff in
> case it came to us from system headers, but it looks like it
> disappeared with MSVCRT:
> 
> 1. I checked with CI (VS 2019).  puts(PRId64) prints out "lld".
> 2. MinGW's inttypes.h[1] only uses "I64" et al if you build against MSVCRT.
> 
> So I think we should delete that stuff.  Attached.

Looks good to me.



Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
Peter Eisentraut <peter@eisentraut.org> writes:
> On 19.11.25 04:15, Tom Lane wrote:
>> I think we should do it
>> honestly with a regression test.  It doesn't need to be very
>> complicated --- I think checking one message in one translation is
>> sufficient, so long as it includes a PRI?64 usage.

> We could generate an English message catalog that translates all 
> messages unchanged, and run the whole test suite with that.  This would 
> exercise the whole gettext run-time machinery.

... except that if it were actually doing nothing whatsoever, you
could not tell.  This seems particularly troublesome for gettext,
since its fallback behavior is exactly to return the given string.
I'd prefer a test that fails in a visible way.

            regards, tom lane



Re: PRI?64 vs Visual Studio (2022)

От
Álvaro Herrera
Дата:
On 2025-Nov-19, Tom Lane wrote:

> Peter Eisentraut <peter@eisentraut.org> writes:
> > On 19.11.25 04:15, Tom Lane wrote:
> >> I think we should do it
> >> honestly with a regression test.  It doesn't need to be very
> >> complicated --- I think checking one message in one translation is
> >> sufficient, so long as it includes a PRI?64 usage.
> 
> > We could generate an English message catalog that translates all 
> > messages unchanged, and run the whole test suite with that.  This would 
> > exercise the whole gettext run-time machinery.
> 
> ... except that if it were actually doing nothing whatsoever, you
> could not tell.

You could feed the message catalog a translated string that differs from
the original in some simple way, say, by adding a constant prefix
"[translated]" or something like that.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/



Re: PRI?64 vs Visual Studio (2022)

От
Jacob Champion
Дата:
On Wed, Nov 19, 2025 at 9:07 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:
> You could feed the message catalog a translated string that differs from
> the original in some simple way, say, by adding a constant prefix
> "[translated]" or something like that.

`xgettext -m` can do that. (But I wish I'd known about msgen earlier...)

We could additionally use preloadable_libintl.so, in combination with
GETTEXT_LOG_UNTRANSLATED, and check if the log contains entries from
our domains. I was doing that just last week. But beware that the log
file can grow very quickly. And we'd probably have to differentiate
the "no domain" text belonging to other software from accidental
no-domain strings in our own code, like what I described in [1].

--Jacob

[1] https://postgr.es/m/CAOYmi+kQQ8vpRcoSrA5EQ98Wa3G6jFj1yRHs6mh1V7ohkTC7JA@mail.gmail.com



Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Thu, Nov 20, 2025 at 4:44 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Peter Eisentraut <peter@eisentraut.org> writes:
> > On 19.11.25 04:15, Tom Lane wrote:
> >> I think we should do it
> >> honestly with a regression test.  It doesn't need to be very
> >> complicated --- I think checking one message in one translation is
> >> sufficient, so long as it includes a PRI?64 usage.
>
> > We could generate an English message catalog that translates all
> > messages unchanged, and run the whole test suite with that.  This would
> > exercise the whole gettext run-time machinery.
>
> ... except that if it were actually doing nothing whatsoever, you
> could not tell.  This seems particularly troublesome for gettext,
> since its fallback behavior is exactly to return the given string.
> I'd prefer a test that fails in a visible way.

How about a test module with a test_nls() function that just raises an
error containing "hello %" PRId64 ", ..." with all the macros we care
about, and regression test that calls it, and two alternative expected
files with "hello ...", "hola ...", matching en.po and es.po (or
choose some other second language that we think is likely to be tested
by a subset of BF animals and/or a CI task)?  Then if you didn't
enable -Dnls it'd still pass with English, and if you did it'd pass
for any language.  Since there are no other .po files, if you had some
third language it'd fall back to English, and the .po would have a "do
not translate" comment or even prefix in the message to avoid
confusing the translation team.  That assumes that modules are allowed
to supply .po files, I didn't check, if that's not true then maybe
it'd have to be in core instead.  That'd test quite a lot of moving
parts at once.

The reason I thought about a contrived message with lots of macros is
that I'd stumbled across a partial implementation[1] in Alpine's
alternative non-GNU msgfmt program, which appears to have PRIu64 but
not PRIx64 and others.  It also has some other way of encoding this
stuff in the .mo that musl's alternative built-in libintl
implementation can understand (it looks like they have arranged to be
able to mmap the .mo and use it directly as shared read-only memory,
while GNU's implementation has to allocate memory to translate them to
%lld etc in every process, clever but (I assume) broken if
msgfmt/libintl implementations are mixed), so I figured it'd be a good
idea to make sure that we test that all the macros actually work.  I
didn't try to understand the implications of Wolfgang's reply, but I
guess that to have any chance of Alpine's libintl pickle being
straightened out, we'd ideally want a test case that someone
interested in that could use to validate the whole localisation
pipeline conclusively.

[1]
https://www.postgresql.org/message-id/flat/CA%2BhUKG%2Bpp%3D%3Dd-3LVhdNOvOAzwQN0vP4gBSxtHkmxnmfQD3NY%3Dw%40mail.gmail.com#167da8f2fb3093bc0fa0a8335c054c19



Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Thu, Nov 20, 2025 at 6:07 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:
> You could feed the message catalog a translated string that differs from
> the original in some simple way, say, by adding a constant prefix
> "[translated]" or something like that.

Oh, that's probably better than my nearby en.po + es.po suggestion.
Combining the ideas, you could have just an en.po translation, but
expected files to match "hello ..." and "[translated] hello ...".
Though, hmm, I suppose that fails to fail if it didn't translate when
it should have, so maybe a TAP test or a test_nls() function that
internally checks the translation rather than using error() and
expected files...



Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
Thomas Munro <thomas.munro@gmail.com> writes:
> On Thu, Nov 20, 2025 at 6:07 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:
>> You could feed the message catalog a translated string that differs from
>> the original in some simple way, say, by adding a constant prefix
>> "[translated]" or something like that.

> Oh, that's probably better than my nearby en.po + es.po suggestion.
> Combining the ideas, you could have just an en.po translation, but
> expected files to match "hello ..." and "[translated] hello ...".
> Though, hmm, I suppose that fails to fail if it didn't translate when
> it should have,

Yeah.  I think it's critical that the test be set up so that
failure-to-translate cannot look like a success.

I agree with the idea of just using a single test message that checks
all the PRI* macros we care about.  I don't think we need to invent a
whole new translation for this.  I'd be inclined to just get the
desired translated string pushed into one or two .po files in HEAD,
then we can start testing with those specific languages, and we're
good.  Over time the translators would presumably get translations
into other .po files, and then maybe we'd want to expand the set of
tested languages, or maybe that wouldn't really buy much.  (Managing
the encoding of the expected-file might be tricky if you got too
ambitious about that.)

            regards, tom lane



Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
I wrote:
> I agree with the idea of just using a single test message that checks
> all the PRI* macros we care about.  I don't think we need to invent a
> whole new translation for this.  I'd be inclined to just get the
> desired translated string pushed into one or two .po files in HEAD,
> then we can start testing with those specific languages, and we're
> good.  Over time the translators would presumably get translations
> into other .po files, and then maybe we'd want to expand the set of
> tested languages, or maybe that wouldn't really buy much.  (Managing
> the encoding of the expected-file might be tricky if you got too
> ambitious about that.)

Just as proof-of-concept, this is approximately what I think we
should do to begin with.

The main thing that's likely wrong here is that I just manually
shoved a new entry into src/backend/po/es.po.  I suspect that
the .po-extraction machinery would fail to pick up that string
because it's in src/test/regress/regress.c.  We could hack it
to do that, or we could put the test function into some backend
file.  I don't have much sense of which would be cleaner.

Lesser loose ends: I didn't bother fleshing out the test message
to cover all of the likely PRI* cases, and my Spanish probably
sucks.  I'm also unsure if this will work as-is on Windows;
are the LC_MESSAGES settings the same there?

            regards, tom lane

From 3f89fb8f0070a35e26e35eb63fe54caea647a4ec Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 19 Nov 2025 17:16:04 -0500
Subject: [PATCH v1] Simple test of NLS translation.

This is just intended to verify minimal functionality of the
NLS message-translation system, and in particular to check that
the PRI* macros work.
---
 src/backend/po/es.po                |  5 +++++
 src/test/regress/expected/nls.out   | 17 +++++++++++++++++
 src/test/regress/expected/nls_1.out | 17 +++++++++++++++++
 src/test/regress/parallel_schedule  |  2 +-
 src/test/regress/regress.c          | 18 ++++++++++++++++++
 src/test/regress/sql/nls.sql        | 16 ++++++++++++++++
 6 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/nls.out
 create mode 100644 src/test/regress/expected/nls_1.out
 create mode 100644 src/test/regress/sql/nls.sql

diff --git a/src/backend/po/es.po b/src/backend/po/es.po
index e2593b52271..861aea61b68 100644
--- a/src/backend/po/es.po
+++ b/src/backend/po/es.po
@@ -31143,3 +31143,8 @@ msgstr "uso no estandar de escape en un literal de cadena"
 #, c-format
 msgid "Use the escape string syntax for escapes, e.g., E'\\r\\n'."
 msgstr "Use la sintaxis de escape para cadenas, por ej. E'\\r\\n'."
+
+#: regress.c:1041
+#, c-format
+msgid "translated PRId64 = %<PRId64>, PRId32 = %<PRId32>"
+msgstr "traducido PRId64 = %<PRId64>, PRId32 = %<PRId32>"
diff --git a/src/test/regress/expected/nls.out b/src/test/regress/expected/nls.out
new file mode 100644
index 00000000000..b97802aeee8
--- /dev/null
+++ b/src/test/regress/expected/nls.out
@@ -0,0 +1,17 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  traducido PRId64 = 4242, PRId32 = -1234
+ test_translation
+------------------
+
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/expected/nls_1.out b/src/test/regress/expected/nls_1.out
new file mode 100644
index 00000000000..4b707e9dad4
--- /dev/null
+++ b/src/test/regress/expected/nls_1.out
@@ -0,0 +1,17 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  NLS is not enabled
+ test_translation
+------------------
+
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index f56482fb9f1..66ce1b7d9cd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -76,7 +76,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan
tidrangescancollate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual 
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid
tidscantidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual 

 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index a2db6080876..7d939565e2e 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -1028,3 +1028,21 @@ test_relpath(PG_FUNCTION_ARGS)

     PG_RETURN_VOID();
 }
+
+/*
+ * Simple test to verify NLS support, particularly that the PRI* macros work.
+ */
+PG_FUNCTION_INFO_V1(test_translation);
+Datum
+test_translation(PG_FUNCTION_ARGS)
+{
+#ifdef ENABLE_NLS
+    ereport(NOTICE,
+            (errmsg("translated PRId64 = %" PRId64 ", PRId32 = %" PRId32,
+                    (int64) 4242, (int32) -1234)));
+#else
+    elog(NOTICE, "NLS is not enabled");
+#endif
+
+    PG_RETURN_VOID();
+}
diff --git a/src/test/regress/sql/nls.sql b/src/test/regress/sql/nls.sql
new file mode 100644
index 00000000000..53b4add86eb
--- /dev/null
+++ b/src/test/regress/sql/nls.sql
@@ -0,0 +1,16 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+
+\set regresslib :libdir '/regress' :dlsuffix
+
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+
+SET lc_messages = 'es_ES';
+
+SELECT test_translation();
+
+RESET lc_messages;
--
2.43.7


Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Thu, Nov 20, 2025 at 11:23 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> I'm also unsure if this will work as-is on Windows;
> are the LC_MESSAGES settings the same there?

Bilal [CC'd], have you ever looked into gettext support for Windows
CI?  I think we'd need at least msgfmt.exe, libintl.{dll,lib,h}
installed on the image, though I have no clue which
distribution/package/whatever would be appropriate.  I assume a script
in pg-vm-images[1] would need to install that, once we pick one.  Does
anyone happen to know where EDB's installer pipeline pulls gettext
from?

[1] https://github.com/anarazel/pg-vm-images/tree/main/scripts



Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
I wrote:
> The main thing that's likely wrong here is that I just manually
> shoved a new entry into src/backend/po/es.po.  I suspect that
> the .po-extraction machinery would fail to pick up that string
> because it's in src/test/regress/regress.c.  We could hack it
> to do that, or we could put the test function into some backend
> file.  I don't have much sense of which would be cleaner.

Oh, better idea about that: let's make regress.so have its own
translation domain.  This allows testing the TEXTDOMAIN mechanism
as well as the basics, and it keeps the patch pretty self-contained.

I was amused to see that "make update-po" was able to fill in
translations for all of the pre-existing ereport's in regress.c.
I guess they all had duplicates somewhere else?  But I take no
credit or blame for any of those translations.

The other loose ends remain.

            regards, tom lane

From 4cc78e9deea5cd69d711bdf15d20d9b8e80d363f Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 19 Nov 2025 20:16:57 -0500
Subject: [PATCH v2] Simple test of NLS translation.

This is just intended to verify minimal functionality of the
NLS message-translation system, and in particular to check that
the PRI* macros work.
---
 src/test/regress/expected/nls.out   | 18 +++++++++
 src/test/regress/expected/nls_1.out | 17 +++++++++
 src/test/regress/meson.build        |  2 +
 src/test/regress/nls.mk             |  5 +++
 src/test/regress/parallel_schedule  |  2 +-
 src/test/regress/po/LINGUAS         |  1 +
 src/test/regress/po/es.po           | 59 +++++++++++++++++++++++++++++
 src/test/regress/po/meson.build     |  3 ++
 src/test/regress/regress.c          | 32 ++++++++++++++++
 src/test/regress/sql/nls.sql        | 16 ++++++++
 10 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/nls.out
 create mode 100644 src/test/regress/expected/nls_1.out
 create mode 100644 src/test/regress/nls.mk
 create mode 100644 src/test/regress/po/LINGUAS
 create mode 100644 src/test/regress/po/es.po
 create mode 100644 src/test/regress/po/meson.build
 create mode 100644 src/test/regress/sql/nls.sql

diff --git a/src/test/regress/expected/nls.out b/src/test/regress/expected/nls.out
new file mode 100644
index 00000000000..d16c29741db
--- /dev/null
+++ b/src/test/regress/expected/nls.out
@@ -0,0 +1,18 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  traducido PRId64 = 4242
+NOTICE:  traducido PRId32 = -1234
+ test_translation
+------------------
+
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/expected/nls_1.out b/src/test/regress/expected/nls_1.out
new file mode 100644
index 00000000000..4b707e9dad4
--- /dev/null
+++ b/src/test/regress/expected/nls_1.out
@@ -0,0 +1,17 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  NLS is not enabled
+ test_translation
+------------------
+
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/meson.build b/src/test/regress/meson.build
index 1da9e9462a9..4001a81ffe5 100644
--- a/src/test/regress/meson.build
+++ b/src/test/regress/meson.build
@@ -57,3 +57,5 @@ tests += {
     'dbname': 'regression',
   },
 }
+
+subdir('po', if_found: libintl)
diff --git a/src/test/regress/nls.mk b/src/test/regress/nls.mk
new file mode 100644
index 00000000000..43227c64f09
--- /dev/null
+++ b/src/test/regress/nls.mk
@@ -0,0 +1,5 @@
+# src/test/regress/nls.mk
+CATALOG_NAME     = regress
+GETTEXT_FILES    = regress.c
+GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS)
+GETTEXT_FLAGS    = $(BACKEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index f56482fb9f1..66ce1b7d9cd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -76,7 +76,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan
tidrangescancollate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual 
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid
tidscantidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual 

 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/po/LINGUAS b/src/test/regress/po/LINGUAS
new file mode 100644
index 00000000000..8357fcaaed4
--- /dev/null
+++ b/src/test/regress/po/LINGUAS
@@ -0,0 +1 @@
+es
diff --git a/src/test/regress/po/es.po b/src/test/regress/po/es.po
new file mode 100644
index 00000000000..3049b73f9f9
--- /dev/null
+++ b/src/test/regress/po/es.po
@@ -0,0 +1,59 @@
+# Spanish message translation file for regress test library
+#
+# Copyright (C) 2025 PostgreSQL Global Development Group
+# This file is distributed under the same license as the regress (PostgreSQL) package.
+#
+# Tom Lane <tgl@sss.pgh.pa.us>, 2025.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: regress (PostgreSQL) 19\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2025-11-19 19:01-0500\n"
+"PO-Revision-Date: 2025-11-19 19:01-0500\n"
+"Last-Translator: Tom Lane <tgl@sss.pgh.pa.us>\n"
+"Language-Team: PgSQL-es-Ayuda <pgsql-es-ayuda@lists.postgresql.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: regress.c:200
+#, c-format
+msgid "invalid input syntax for type %s: \"%s\""
+msgstr "la sintaxis de entrada no es válida para tipo %s: «%s»"
+
+#: regress.c:907
+#, c-format
+msgid "invalid source encoding name \"%s\""
+msgstr "la codificación de origen «%s» no es válida"
+
+#: regress.c:912
+#, c-format
+msgid "invalid destination encoding name \"%s\""
+msgstr "la codificación de destino «%s» no es válida"
+
+#: regress.c:957
+#, c-format
+msgid "default conversion function for encoding \"%s\" to \"%s\" does not exist"
+msgstr "no existe el procedimiento por omisión de conversión desde la codificación «%s» a «%s»"
+
+#: regress.c:964
+#, c-format
+msgid "out of memory"
+msgstr "memoria agotada"
+
+#: regress.c:965
+#, c-format
+msgid "String of %d bytes is too long for encoding conversion."
+msgstr "La cadena de %d bytes es demasiado larga para la recodificación."
+
+#: regress.c:1054
+#, c-format
+msgid "translated PRId64 = %<PRId64>"
+msgstr "traducido PRId64 = %<PRId64>"
+
+#: regress.c:1056
+#, c-format
+msgid "translated PRId32 = %<PRId32>"
+msgstr "traducido PRId32 = %<PRId32>"
diff --git a/src/test/regress/po/meson.build b/src/test/regress/po/meson.build
new file mode 100644
index 00000000000..e9bd964aa7f
--- /dev/null
+++ b/src/test/regress/po/meson.build
@@ -0,0 +1,3 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+nls_targets += [i18n.gettext('regress-' + pg_version_major.to_string())]
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index a2db6080876..4a584ca88ae 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -46,6 +46,10 @@
 #include "utils/rel.h"
 #include "utils/typcache.h"

+/* define our text domain for translations */
+#undef TEXTDOMAIN
+#define TEXTDOMAIN PG_TEXTDOMAIN("regress")
+
 #define EXPECT_TRUE(expr)    \
     do { \
         if (!(expr)) \
@@ -1028,3 +1032,31 @@ test_relpath(PG_FUNCTION_ARGS)

     PG_RETURN_VOID();
 }
+
+/*
+ * Simple test to verify NLS support, particularly that the PRI* macros work.
+ */
+PG_FUNCTION_INFO_V1(test_translation);
+Datum
+test_translation(PG_FUNCTION_ARGS)
+{
+#ifdef ENABLE_NLS
+    /* This would be better done in _PG_init(), if this module had one */
+    static bool inited = false;
+
+    if (!inited)
+    {
+        pg_bindtextdomain(TEXTDOMAIN);
+        inited = true;
+    }
+
+    ereport(NOTICE,
+            errmsg("translated PRId64 = %" PRId64, (int64) 4242));
+    ereport(NOTICE,
+            errmsg("translated PRId32 = %" PRId32, (int32) -1234));
+#else
+    elog(NOTICE, "NLS is not enabled");
+#endif
+
+    PG_RETURN_VOID();
+}
diff --git a/src/test/regress/sql/nls.sql b/src/test/regress/sql/nls.sql
new file mode 100644
index 00000000000..53b4add86eb
--- /dev/null
+++ b/src/test/regress/sql/nls.sql
@@ -0,0 +1,16 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+
+\set regresslib :libdir '/regress' :dlsuffix
+
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+
+SET lc_messages = 'es_ES';
+
+SELECT test_translation();
+
+RESET lc_messages;
--
2.43.7


Re: PRI?64 vs Visual Studio (2022)

От
Nazir Bilal Yavuz
Дата:
Hi,

On Thu, 20 Nov 2025 at 01:44, Thomas Munro <thomas.munro@gmail.com> wrote:
>
> On Thu, Nov 20, 2025 at 11:23 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> > I'm also unsure if this will work as-is on Windows;
> > are the LC_MESSAGES settings the same there?
>
> Bilal [CC'd], have you ever looked into gettext support for Windows
> CI?  I think we'd need at least msgfmt.exe, libintl.{dll,lib,h}
> installed on the image, though I have no clue which
> distribution/package/whatever would be appropriate.  I assume a script
> in pg-vm-images[1] would need to install that, once we pick one.  Does
> anyone happen to know where EDB's installer pipeline pulls gettext
> from?
>
> [1] https://github.com/anarazel/pg-vm-images/tree/main/scripts

Yes, I was working on that some time ago and I was able to enable NLS
(and many other dependencies) on Windows CI image by using the
dependencies from Dave Page's winpgbuild repository [1]. I was going
to share these changes but some other things came up and this one got
delayed. I am planning to return to this again soon.

As an example, I re-generated the Windows CI image and tested it with
VS 2019 [2] and VS 2022 [3]. There are 3 tests failed on both but they
are not related to NLS. A portion of configure output:

[07:40:23.149]   External libraries
[07:40:23.149]     bonjour                : NO
[07:40:23.149]     bsd_auth               : NO
[07:40:23.149]     docs                   : YES
[07:40:23.149]     docs_pdf               : NO
[07:40:23.149]     gss                    : YES 1.22.1
[07:40:23.149]     icu                    : YES 77.1
[07:40:23.149]     ldap                   : YES
[07:40:23.149]     libcurl                : NO
[07:40:23.149]     libnuma                : NO
[07:40:23.149]     liburing               : NO
[07:40:23.149]     libxml                 : YES 2.13.9
[07:40:23.149]     libxslt                : YES 1.1.43
[07:40:23.149]     llvm                   : NO
[07:40:23.149]     lz4                    : YES 1.10.0
[07:40:23.149]     nls                    : YES
[07:40:23.149]     openssl                : YES 3.0.18
[07:40:23.149]     pam                    : NO
[07:40:23.149]     plperl                 : YES 5.42.0
[07:40:23.149]     plpython               : YES 3.10
[07:40:23.149]     pltcl                  : NO
[07:40:23.149]     readline               : NO
[07:40:23.149]     selinux                : NO
[07:40:23.149]     systemd                : NO
[07:40:23.149]     uuid                   : YES 1.6.2
[07:40:23.149]     zlib                   : YES 1.3.1
[07:40:23.149]     zstd                   : YES 1.5.7

[1] https://github.com/dpage/winpgbuild
[2] https://cirrus-ci.com/task/4655787001249792
[3] https://cirrus-ci.com/task/5786281818456064

--
Regards,
Nazir Bilal Yavuz
Microsoft



Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Wed, Nov 19, 2025 at 3:13 PM Thomas Munro <thomas.munro@gmail.com> wrote:
> I was also curious to know if the nearby floating point formatting
> kludge added by commit f1885386 was still needed today.  CI passes
> without it, and the standard is pretty clear: "The exponent always
> contains at least two digits, and only as many more digits as
> necessary to represent the exponent".  I didn't look too closely at
> the fine print, but that text was already present in C89 so I guess
> MSVCRT just failed to conform on that point.

We can also drop HAVE_BUGGY_STRTOF for MinGW.  This passes on CI.

That'd leave only Cygwin with HAVE BUGGY_STRTOF.  Perhaps they have
fixed their implementation[1]?  Here's an experimental patch to drop
all remnants, which could be used to find out.  No Windows/Cygwin
here.  Hmm, what if we just commit it anyway?  If their strtof() is
still broken and someone out there is running the tests and sees this
test fail, why shouldn't they take that up with libc at this stage?

[1] https://github.com/cygwin/cygwin/commit/fb01286fab9b370c86323f84a46285cfbebfe4ff

Вложения

Re: PRI?64 vs Visual Studio (2022)

От
Tom Lane
Дата:
Thomas Munro <thomas.munro@gmail.com> writes:
> That'd leave only Cygwin with HAVE BUGGY_STRTOF.  Perhaps they have
> fixed their implementation[1]?  Here's an experimental patch to drop
> all remnants, which could be used to find out.  No Windows/Cygwin
> here.  Hmm, what if we just commit it anyway?  If their strtof() is
> still broken and someone out there is running the tests and sees this
> test fail, why shouldn't they take that up with libc at this stage?

Hmm, we could get rid of the whole resultmap mechanism ...

            regards, tom lane



Re: PRI?64 vs Visual Studio (2022)

От
Thomas Munro
Дата:
On Sun, Nov 23, 2025 at 4:25 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Thomas Munro <thomas.munro@gmail.com> writes:
> > That'd leave only Cygwin with HAVE BUGGY_STRTOF.  Perhaps they have
> > fixed their implementation[1]?  Here's an experimental patch to drop
> > all remnants, which could be used to find out.  No Windows/Cygwin
> > here.  Hmm, what if we just commit it anyway?  If their strtof() is
> > still broken and someone out there is running the tests and sees this
> > test fail, why shouldn't they take that up with libc at this stage?
>
> Hmm, we could get rid of the whole resultmap mechanism ...

Yeah.  I thought I'd see what blowback my
if-Cygwin-strtof()-really-is-still-broken-they-should-fix-it argument
attracted before spending the time to nuke all those lines too.
Here's that patch.  We could always revert resultmap we found a new
reason to need it, but I hope we wouldn't.

Вложения

Re: PRI?64 vs Visual Studio (2022)

От
Peter Eisentraut
Дата:
On 24.11.25 00:03, Thomas Munro wrote:
> On Sun, Nov 23, 2025 at 4:25 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Thomas Munro <thomas.munro@gmail.com> writes:
>>> That'd leave only Cygwin with HAVE BUGGY_STRTOF.  Perhaps they have
>>> fixed their implementation[1]?  Here's an experimental patch to drop
>>> all remnants, which could be used to find out.  No Windows/Cygwin
>>> here.  Hmm, what if we just commit it anyway?  If their strtof() is
>>> still broken and someone out there is running the tests and sees this
>>> test fail, why shouldn't they take that up with libc at this stage?
>>
>> Hmm, we could get rid of the whole resultmap mechanism ...
> 
> Yeah.  I thought I'd see what blowback my
> if-Cygwin-strtof()-really-is-still-broken-they-should-fix-it argument
> attracted before spending the time to nuke all those lines too.
> Here's that patch.  We could always revert resultmap we found a new
> reason to need it, but I hope we wouldn't.

These patches look sensible to me.

Maybe wait a bit to see if Andrew can manually reproduce the issue one 
way or the other on Cygwin.

Otherwise, I'd say go for it.