Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSgpO-003gWq-2H for pgsql-hackers@arkaria.postgresql.org; Mon, 08 Dec 2025 19:23:22 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vSgpM-001HnC-1N for pgsql-hackers@arkaria.postgresql.org; Mon, 08 Dec 2025 19:23:20 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSgpL-001Hn2-2o for pgsql-hackers@lists.postgresql.org; Mon, 08 Dec 2025 19:23:20 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSgpI-003o0a-2k for pgsql-hackers@lists.postgresql.org; Mon, 08 Dec 2025 19:23:19 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 5B8JNGZJ3098753 for ; Mon, 8 Dec 2025 14:23:16 -0500 From: Tom Lane To: pgsql-hackers@lists.postgresql.org Subject: Let's add a test for NLS translation of PRI* macros MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <3098697.1765221753.0@sss.pgh.pa.us> Date: Mon, 08 Dec 2025 14:23:16 -0500 Message-ID: <3098752.1765221796@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <3098697.1765221753.1@sss.pgh.pa.us> Content-Transfer-Encoding: quoted-printable This was discussed a few weeks ago in [1], but I'm starting a new thread so as not to confuse things with the latest patches in that thread. The issue is that it seems like it'd be a good idea to have specific regression testing of whether translation of the PRI* macros works properly, since that is an aspect of gettext() behavior that didn't use to work everywhere. I don't know whether the attached will pass on Windows: we might not be able to assume that "es_ES" is the right LC_MESSAGES setting to use. But it works for me on Linux. regards, tom lane [1] https://www.postgresql.org/message-id/flat/20250331.152829.19213926903= 75275165.horikyota.ntt%40gmail.com ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name*0="v3-0001-Add-a-regression-test-to-verify-that-NLS-translat.p"; name*1="atch"; charset="UTF-8" Content-ID: <3098697.1765221753.2@sss.pgh.pa.us> Content-Description: v3-0001-Add-a-regression-test-to-verify-that-NLS-translat.patch Content-Transfer-Encoding: quoted-printable =46rom d65fbf666e93fc3dd8c0e7c9817ace3c014ab99d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 8 Dec 2025 14:14:59 -0500 Subject: [PATCH v3] Add a regression test to verify that NLS translation works. We've never actually had a formal test for this facility. It seems worth adding one now, mainly because we are starting to depend on gettext() being able to handle the PRI* macros from , and it's not all that certain that that works everywhere. So the test goes to a bit of effort to check all the PRI* macros we are likely to use. --- src/test/regress/expected/nls.out | 32 ++++++ 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 | 159 ++++++++++++++++++++++++++++ src/test/regress/po/meson.build | 3 + src/test/regress/regress.c | 63 +++++++++++ src/test/regress/sql/nls.sql | 16 +++ 10 files changed, 299 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..d1afc528a8d --- /dev/null +++ b/src/test/regress/expected/nls.out @@ -0,0 +1,32 @@ +-- 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 =3D 'es_ES'; +SELECT test_translation(); +NOTICE: traducido PRId64 =3D 424242424242 +NOTICE: traducido PRId32 =3D -1234 +NOTICE: traducido PRIdMAX =3D -5678 +NOTICE: traducido PRIdPTR =3D 9999 +NOTICE: traducido PRIu64 =3D 424242424242 +NOTICE: traducido PRIu32 =3D 1234 +NOTICE: traducido PRIuMAX =3D 5678 +NOTICE: traducido PRIuPTR =3D 9999 +NOTICE: traducido PRIx64 =3D 62c6d1a9b2 +NOTICE: traducido PRIx32 =3D 4d2 +NOTICE: traducido PRIxMAX =3D 162e +NOTICE: traducido PRIxPTR =3D 270f +NOTICE: traducido PRIX64 =3D 62C6D1A9B2 +NOTICE: traducido PRIX32 =3D 4D2 +NOTICE: traducido PRIXMAX =3D 162E +NOTICE: traducido PRIXPTR =3D 270F + test_translation = +------------------ + = +(1 row) + +RESET lc_messages; diff --git a/src/test/regress/expected/nls_1.out b/src/test/regress/expect= ed/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 =3D '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 +=3D { '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 =3D regress +GETTEXT_FILES =3D regress.c +GETTEXT_TRIGGERS =3D $(BACKEND_COMMON_GETTEXT_TRIGGERS) +GETTEXT_FLAGS =3D $(BACKEND_COMMON_GETTEXT_FLAGS) diff --git a/src/test/regress/parallel_schedule b/src/test/regress/paralle= l_schedule index cc6d799bcea..0931f1dcccf 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 me= rge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 col= late.icu.utf8 incremental_sort create_role without_overlaps generated_virt= ual +test: create_table_like alter_generic alter_operator misc async dbsize me= rge misc_functions nls sysviews tsrf tid tidscan tidrangescan 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..b3021d57e22 --- /dev/null +++ b/src/test/regress/po/es.po @@ -0,0 +1,159 @@ +# 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 (Postgre= SQL) package. +# +# Tom Lane , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: regress (PostgreSQL) 19\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2025-12-08 13:57-0500\n" +"PO-Revision-Date: 2025-11-19 19:01-0500\n" +"Last-Translator: Tom Lane \n" +"Language-Team: PgSQL-es-Ayuda \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=3DUTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: regress.c:202 +#, c-format +msgid "invalid input syntax for type %s: \"%s\"" +msgstr "la sintaxis de entrada no es v=C3=A1lida para tipo %s: =C2=AB%s=C2= =BB" + +#: regress.c:839 +#, c-format +msgid "test_inline_in_from_support_func called with %d args but expected = 3" +msgstr "" + +#: regress.c:847 regress.c:863 +#, c-format +msgid "test_inline_in_from_support_func called with non-Const parameters" +msgstr "" + +#: regress.c:854 regress.c:870 +#, c-format +msgid "test_inline_in_from_support_func called with non-TEXT parameters" +msgstr "" + +#: regress.c:903 +#, c-format +msgid "test_inline_in_from_support_func parsed to more than one node" +msgstr "" + +#: regress.c:914 +#, c-format +msgid "test_inline_in_from_support_func rewrote to more than one node" +msgstr "" + +#: regress.c:921 +#, c-format +msgid "test_inline_in_from_support_func didn't parse to a Query" +msgstr "" + +#: regress.c:1028 +#, c-format +msgid "invalid source encoding name \"%s\"" +msgstr "la codificaci=C3=B3n de origen =C2=AB%s=C2=BB no es v=C3=A1lida" + +#: regress.c:1033 +#, c-format +msgid "invalid destination encoding name \"%s\"" +msgstr "la codificaci=C3=B3n de destino =C2=AB%s=C2=BB no es v=C3=A1lida" + +#: regress.c:1078 +#, c-format +msgid "default conversion function for encoding \"%s\" to \"%s\" does not= exist" +msgstr "no existe el procedimiento por omisi=C3=B3n de conversi=C3=B3n de= sde la codificaci=C3=B3n =C2=AB%s=C2=BB a =C2=AB%s=C2=BB" + +#: regress.c:1085 +#, c-format +msgid "out of memory" +msgstr "memoria agotada" + +#: regress.c:1086 +#, 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=C3=B3= n." + +#: regress.c:1175 +#, c-format +msgid "translated PRId64 =3D %" +msgstr "traducido PRId64 =3D %" + +#: regress.c:1177 +#, c-format +msgid "translated PRId32 =3D %" +msgstr "traducido PRId32 =3D %" + +#: regress.c:1179 +#, c-format +msgid "translated PRIdMAX =3D %" +msgstr "traducido PRIdMAX =3D %" + +#: regress.c:1181 +#, c-format +msgid "translated PRIdPTR =3D %" +msgstr "traducido PRIdPTR =3D %" + +#: regress.c:1184 +#, c-format +msgid "translated PRIu64 =3D %" +msgstr "traducido PRIu64 =3D %" + +#: regress.c:1186 +#, c-format +msgid "translated PRIu32 =3D %" +msgstr "traducido PRIu32 =3D %" + +#: regress.c:1188 +#, c-format +msgid "translated PRIuMAX =3D %" +msgstr "traducido PRIuMAX =3D %" + +#: regress.c:1190 +#, c-format +msgid "translated PRIuPTR =3D %" +msgstr "traducido PRIuPTR =3D %" + +#: regress.c:1193 +#, c-format +msgid "translated PRIx64 =3D %" +msgstr "traducido PRIx64 =3D %" + +#: regress.c:1195 +#, c-format +msgid "translated PRIx32 =3D %" +msgstr "traducido PRIx32 =3D %" + +#: regress.c:1197 +#, c-format +msgid "translated PRIxMAX =3D %" +msgstr "traducido PRIxMAX =3D %" + +#: regress.c:1199 +#, c-format +msgid "translated PRIxPTR =3D %" +msgstr "traducido PRIxPTR =3D %" + +#: regress.c:1202 +#, c-format +msgid "translated PRIX64 =3D %" +msgstr "traducido PRIX64 =3D %" + +#: regress.c:1204 +#, c-format +msgid "translated PRIX32 =3D %" +msgstr "traducido PRIX32 =3D %" + +#: regress.c:1206 +#, c-format +msgid "translated PRIXMAX =3D %" +msgstr "traducido PRIXMAX =3D %" + +#: regress.c:1208 +#, c-format +msgid "translated PRIXPTR =3D %" +msgstr "traducido PRIXPTR =3D %" diff --git a/src/test/regress/po/meson.build b/src/test/regress/po/meson.b= uild 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 +=3D [i18n.gettext('regress-' + pg_version_major.to_string())= ] diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index 56cc0567b1c..2d5d799f6e4 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -48,6 +48,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)) \ @@ -1149,3 +1153,62 @@ test_relpath(PG_FUNCTION_ARGS) = PG_RETURN_VOID(); } + +/* + * Simple test to verify NLS support, particularly that the PRI* macros w= ork. + */ +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 =3D false; + + if (!inited) + { + pg_bindtextdomain(TEXTDOMAIN); + inited =3D true; + } + + ereport(NOTICE, + errmsg("translated PRId64 =3D %" PRId64, (int64) 424242424242)); + ereport(NOTICE, + errmsg("translated PRId32 =3D %" PRId32, (int32) -1234)); + ereport(NOTICE, + errmsg("translated PRIdMAX =3D %" PRIdMAX, (intmax_t) -5678)); + ereport(NOTICE, + errmsg("translated PRIdPTR =3D %" PRIdPTR, (intptr_t) 9999)); + + ereport(NOTICE, + errmsg("translated PRIu64 =3D %" PRIu64, (uint64) 424242424242)); + ereport(NOTICE, + errmsg("translated PRIu32 =3D %" PRIu32, (uint32) 1234)); + ereport(NOTICE, + errmsg("translated PRIuMAX =3D %" PRIuMAX, (uintmax_t) 5678)); + ereport(NOTICE, + errmsg("translated PRIuPTR =3D %" PRIuPTR, (uintptr_t) 9999)); + + ereport(NOTICE, + errmsg("translated PRIx64 =3D %" PRIx64, (uint64) 424242424242)); + ereport(NOTICE, + errmsg("translated PRIx32 =3D %" PRIx32, (uint32) 1234)); + ereport(NOTICE, + errmsg("translated PRIxMAX =3D %" PRIxMAX, (uintmax_t) 5678)); + ereport(NOTICE, + errmsg("translated PRIxPTR =3D %" PRIxPTR, (uintptr_t) 9999)); + + ereport(NOTICE, + errmsg("translated PRIX64 =3D %" PRIX64, (uint64) 424242424242)); + ereport(NOTICE, + errmsg("translated PRIX32 =3D %" PRIX32, (uint32) 1234)); + ereport(NOTICE, + errmsg("translated PRIXMAX =3D %" PRIXMAX, (uintmax_t) 5678)); + ereport(NOTICE, + errmsg("translated PRIXPTR =3D %" PRIXPTR, (uintptr_t) 9999)); +#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 =3D 'es_ES'; + +SELECT test_translation(); + +RESET lc_messages; -- = 2.43.7 ------- =_aaaaaaaaaa0--