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 <inttypes.h>, 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.

(This effort has indeed found one problem already, now fixed
in commit f8715ec86.)

Discussion: https://postgr.es/m/3098752.1765221796@sss.pgh.pa.us
Discussion: https://postgr.es/m/292844.1765315339@sss.pgh.pa.us
pull/258/head
Tom Lane 4 days ago
parent b27e48213f
commit 8c498479d7
  1. 35
      src/test/regress/expected/nls.out
  2. 20
      src/test/regress/expected/nls_1.out
  3. 2
      src/test/regress/meson.build
  4. 5
      src/test/regress/nls.mk
  5. 2
      src/test/regress/parallel_schedule
  6. 1
      src/test/regress/po/LINGUAS
  7. 159
      src/test/regress/po/es.po
  8. 3
      src/test/regress/po/meson.build
  9. 77
      src/test/regress/regress.c
  10. 19
      src/test/regress/sql/nls.sql

@ -0,0 +1,35 @@
-- 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;
-- Some BSDen are sticky about wanting a codeset name in lc_messages,
-- but it seems that at least on common platforms it doesn't have
-- to match the actual database encoding.
SET lc_messages = 'es_ES.UTF-8';
SELECT test_translation();
NOTICE: traducido PRId64 = 424242424242
NOTICE: traducido PRId32 = -1234
NOTICE: traducido PRIdMAX = -5678
NOTICE: traducido PRIdPTR = 9999
NOTICE: traducido PRIu64 = 424242424242
NOTICE: traducido PRIu32 = 1234
NOTICE: traducido PRIuMAX = 5678
NOTICE: traducido PRIuPTR = 9999
NOTICE: traducido PRIx64 = 62c6d1a9b2
NOTICE: traducido PRIx32 = 4d2
NOTICE: traducido PRIxMAX = 162e
NOTICE: traducido PRIxPTR = 270f
NOTICE: traducido PRIX64 = 62C6D1A9B2
NOTICE: traducido PRIX32 = 4D2
NOTICE: traducido PRIXMAX = 162E
NOTICE: traducido PRIXPTR = 270F
test_translation
------------------
(1 row)
RESET lc_messages;

@ -0,0 +1,20 @@
-- 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;
-- Some BSDen are sticky about wanting a codeset name in lc_messages,
-- but it seems that at least on common platforms it doesn't have
-- to match the actual database encoding.
SET lc_messages = 'es_ES.UTF-8';
SELECT test_translation();
NOTICE: NLS is not enabled
test_translation
------------------
(1 row)
RESET lc_messages;

@ -57,3 +57,5 @@ tests += {
'dbname': 'regression', 'dbname': 'regression',
}, },
} }
subdir('po', if_found: libintl)

@ -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)

@ -76,7 +76,7 @@ test: brin_bloom brin_multi
# ---------- # ----------
# Another group of parallel tests # Another group of parallel tests
# ---------- # ----------
test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.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 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 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
# psql depends on create_am # psql depends on create_am

@ -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 (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-12-08 13:57-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:202
#, 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: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ón de origen «%s» no es válida"
#: regress.c:1033
#, c-format
msgid "invalid destination encoding name \"%s\""
msgstr "la codificación de destino «%s» no es válida"
#: regress.c:1078
#, 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: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ón."
#: regress.c:1175
#, c-format
msgid "translated PRId64 = %<PRId64>"
msgstr "traducido PRId64 = %<PRId64>"
#: regress.c:1177
#, c-format
msgid "translated PRId32 = %<PRId32>"
msgstr "traducido PRId32 = %<PRId32>"
#: regress.c:1179
#, c-format
msgid "translated PRIdMAX = %<PRIdMAX>"
msgstr "traducido PRIdMAX = %<PRIdMAX>"
#: regress.c:1181
#, c-format
msgid "translated PRIdPTR = %<PRIdPTR>"
msgstr "traducido PRIdPTR = %<PRIdPTR>"
#: regress.c:1184
#, c-format
msgid "translated PRIu64 = %<PRIu64>"
msgstr "traducido PRIu64 = %<PRIu64>"
#: regress.c:1186
#, c-format
msgid "translated PRIu32 = %<PRIu32>"
msgstr "traducido PRIu32 = %<PRIu32>"
#: regress.c:1188
#, c-format
msgid "translated PRIuMAX = %<PRIuMAX>"
msgstr "traducido PRIuMAX = %<PRIuMAX>"
#: regress.c:1190
#, c-format
msgid "translated PRIuPTR = %<PRIuPTR>"
msgstr "traducido PRIuPTR = %<PRIuPTR>"
#: regress.c:1193
#, c-format
msgid "translated PRIx64 = %<PRIx64>"
msgstr "traducido PRIx64 = %<PRIx64>"
#: regress.c:1195
#, c-format
msgid "translated PRIx32 = %<PRIx32>"
msgstr "traducido PRIx32 = %<PRIx32>"
#: regress.c:1197
#, c-format
msgid "translated PRIxMAX = %<PRIxMAX>"
msgstr "traducido PRIxMAX = %<PRIxMAX>"
#: regress.c:1199
#, c-format
msgid "translated PRIxPTR = %<PRIxPTR>"
msgstr "traducido PRIxPTR = %<PRIxPTR>"
#: regress.c:1202
#, c-format
msgid "translated PRIX64 = %<PRIX64>"
msgstr "traducido PRIX64 = %<PRIX64>"
#: regress.c:1204
#, c-format
msgid "translated PRIX32 = %<PRIX32>"
msgstr "traducido PRIX32 = %<PRIX32>"
#: regress.c:1206
#, c-format
msgid "translated PRIXMAX = %<PRIXMAX>"
msgstr "traducido PRIXMAX = %<PRIXMAX>"
#: regress.c:1208
#, c-format
msgid "translated PRIXPTR = %<PRIXPTR>"
msgstr "traducido PRIXPTR = %<PRIXPTR>"

@ -0,0 +1,3 @@
# Copyright (c) 2022-2025, PostgreSQL Global Development Group
nls_targets += [i18n.gettext('regress-' + pg_version_major.to_string())]

@ -48,6 +48,10 @@
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/typcache.h" #include "utils/typcache.h"
/* define our text domain for translations */
#undef TEXTDOMAIN
#define TEXTDOMAIN PG_TEXTDOMAIN("regress")
#define EXPECT_TRUE(expr) \ #define EXPECT_TRUE(expr) \
do { \ do { \
if (!(expr)) \ if (!(expr)) \
@ -1149,3 +1153,76 @@ test_relpath(PG_FUNCTION_ARGS)
PG_RETURN_VOID(); 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
static bool inited = false;
/*
* Ideally we'd do this bit in a _PG_init() hook. However, it seems best
* that the Solaris hack only get applied in the nls.sql test, so it
* doesn't risk affecting other tests that load this module.
*/
if (!inited)
{
/*
* Solaris' built-in gettext is not bright about associating locales
* with message catalogs that are named after just the language.
* Apparently the customary workaround is for users to set the
* LANGUAGE environment variable to provide a mapping. Do so here to
* ensure that the nls.sql regression test will work.
*/
#if defined(__sun__)
setenv("LANGUAGE", "es_ES.UTF-8:es", 1);
#endif
pg_bindtextdomain(TEXTDOMAIN);
inited = true;
}
ereport(NOTICE,
errmsg("translated PRId64 = %" PRId64, (int64) 424242424242));
ereport(NOTICE,
errmsg("translated PRId32 = %" PRId32, (int32) -1234));
ereport(NOTICE,
errmsg("translated PRIdMAX = %" PRIdMAX, (intmax_t) -5678));
ereport(NOTICE,
errmsg("translated PRIdPTR = %" PRIdPTR, (intptr_t) 9999));
ereport(NOTICE,
errmsg("translated PRIu64 = %" PRIu64, (uint64) 424242424242));
ereport(NOTICE,
errmsg("translated PRIu32 = %" PRIu32, (uint32) 1234));
ereport(NOTICE,
errmsg("translated PRIuMAX = %" PRIuMAX, (uintmax_t) 5678));
ereport(NOTICE,
errmsg("translated PRIuPTR = %" PRIuPTR, (uintptr_t) 9999));
ereport(NOTICE,
errmsg("translated PRIx64 = %" PRIx64, (uint64) 424242424242));
ereport(NOTICE,
errmsg("translated PRIx32 = %" PRIx32, (uint32) 1234));
ereport(NOTICE,
errmsg("translated PRIxMAX = %" PRIxMAX, (uintmax_t) 5678));
ereport(NOTICE,
errmsg("translated PRIxPTR = %" PRIxPTR, (uintptr_t) 9999));
ereport(NOTICE,
errmsg("translated PRIX64 = %" PRIX64, (uint64) 424242424242));
ereport(NOTICE,
errmsg("translated PRIX32 = %" PRIX32, (uint32) 1234));
ereport(NOTICE,
errmsg("translated PRIXMAX = %" PRIXMAX, (uintmax_t) 5678));
ereport(NOTICE,
errmsg("translated PRIXPTR = %" PRIXPTR, (uintptr_t) 9999));
#else
elog(NOTICE, "NLS is not enabled");
#endif
PG_RETURN_VOID();
}

@ -0,0 +1,19 @@
-- 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;
-- Some BSDen are sticky about wanting a codeset name in lc_messages,
-- but it seems that at least on common platforms it doesn't have
-- to match the actual database encoding.
SET lc_messages = 'es_ES.UTF-8';
SELECT test_translation();
RESET lc_messages;
Loading…
Cancel
Save