From cc96a5fc5b3bdf4d093126ecce26e23a96e4fac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 17:04:31 -0400 Subject: [PATCH 1/9] r.reclass: Translate complete messages instead of fragments Join the 'Illegal reclass rule' and 'invalid reclass rule' messages instead of translating their pieces separately. --- raster/r.reclass/main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/raster/r.reclass/main.c b/raster/r.reclass/main.c index 2e5e0fd36a1..b5de72ea5a3 100644 --- a/raster/r.reclass/main.c +++ b/raster/r.reclass/main.c @@ -114,12 +114,10 @@ int main(int argc, char *argv[]) switch (parse(buf, &rules, &tail, &cats)) { case -1: if (tty) { - fprintf(stderr, _("Illegal reclass rule -")); - fprintf(stderr, _(" ignored\n")); + fprintf(stderr, _("Illegal reclass rule - ignored\n")); } else { - strcat(buf, _(" - invalid reclass rule")); - G_fatal_error("%s", buf); + G_fatal_error(_("%s - invalid reclass rule"), buf); } break; From fe1f4ce64241caa0b8bcc14ca86d0719d10914dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 17:04:29 -0400 Subject: [PATCH 2/9] r.in.pdal: Fix point count messages not being translated The msgids were built with a preprocessor macro inside _(), so xgettext extracted a fragment and the runtime msgid never matched a catalog entry. Write the format with PRIu64, as done for other 64-bit values in translated strings, so the msgid is the same whatever the type of the count. Report the final counts in separate messages, each with a single placeholder, instead of one message built with snprintf(). --- raster/r.in.pdal/main.cpp | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/raster/r.in.pdal/main.cpp b/raster/r.in.pdal/main.cpp index 2e88ff55f29..391020edaf1 100644 --- a/raster/r.in.pdal/main.cpp +++ b/raster/r.in.pdal/main.cpp @@ -15,6 +15,8 @@ * *****************************************************************************/ +#include +#include #include #include #include @@ -56,8 +58,6 @@ extern "C" { #include "string_list.h" } -#define BUFFSIZE GPATH_MAX - int main(int argc, char *argv[]) { int out_fd; @@ -73,8 +73,6 @@ int main(int argc, char *argv[]) struct Cell_head input_region = {}; int rows, cols; /* scan box size */ - char buff[BUFFSIZE]; - struct BinIndex bin_index_nodes; bin_index_nodes.num_nodes = 0; @@ -947,8 +945,8 @@ int main(int argc, char *argv[]) G_percent(1, 1, 1); /* flush */ G_free(raster_row); - G_message(_(GPOINT_COUNT_FORMAT " points found in input file(s)"), - grass_filter.num_processed()); + G_message(_("%" PRIu64 " points found in input file(s)"), + (uint64_t)grass_filter.num_processed()); /* close raster file & write history */ Rast_close(out_fd); @@ -979,21 +977,11 @@ int main(int argc, char *argv[]) if (set_region_flag->answer) G_put_window(®ion); - if (infiles.num_items > 1) { - snprintf(buff, BUFFSIZE, - _("Raster map <%s> created." - " " GPOINT_COUNT_FORMAT - " points from %d files found in region."), - outmap, grass_filter.num_passed(), infiles.num_items); - } - else { - snprintf(buff, BUFFSIZE, - _("Raster map <%s> created." - " " GPOINT_COUNT_FORMAT " points found in region."), - outmap, grass_filter.num_passed()); - } - - G_done_msg("%s", buff); + G_message(_("%" PRIu64 " points found in region."), + (uint64_t)grass_filter.num_passed()); + if (infiles.num_items > 1) + G_message(_("Number of input files: %d"), infiles.num_items); + G_done_msg(_("Raster map <%s> created."), outmap); // Points pruned by the reader's spatial index never reach the filter, so // the count below is not comparable to a run without the index. if (bounds_pushed_to_reader) From 351ebba5d989b7672406caf5f6f4415f9e2fa14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 17:04:32 -0400 Subject: [PATCH 3/9] r.horizon: Use complete messages for bufferzone errors The direction was a separately translated word substituted into the sentence, which cannot agree in gender or case in all languages. --- raster/r.horizon/main.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/raster/r.horizon/main.c b/raster/r.horizon/main.c index a273a59d937..57a8531e215 100644 --- a/raster/r.horizon/main.c +++ b/raster/r.horizon/main.c @@ -493,26 +493,22 @@ int main(int argc, char *argv[]) if (parm.e_buff->answer != NULL) { if (sscanf(parm.e_buff->answer, "%lf", &ebufferZone) != 1) - G_fatal_error(_("Could not read %s bufferzone size. Aborting."), - _("east")); + G_fatal_error(_("Could not read east bufferzone size. Aborting.")); } if (parm.w_buff->answer != NULL) { if (sscanf(parm.w_buff->answer, "%lf", &wbufferZone) != 1) - G_fatal_error(_("Could not read %s bufferzone size. Aborting."), - _("west")); + G_fatal_error(_("Could not read west bufferzone size. Aborting.")); } if (parm.s_buff->answer != NULL) { if (sscanf(parm.s_buff->answer, "%lf", &sbufferZone) != 1) - G_fatal_error(_("Could not read %s bufferzone size. Aborting."), - _("south")); + G_fatal_error(_("Could not read south bufferzone size. Aborting.")); } if (parm.n_buff->answer != NULL) { if (sscanf(parm.n_buff->answer, "%lf", &nbufferZone) != 1) - G_fatal_error(_("Could not read %s bufferzone size. Aborting."), - _("north")); + G_fatal_error(_("Could not read north bufferzone size. Aborting.")); } settings.fixedMaxLength = BIG; From 8db78f17d42e7c04c5c003b5ba666086729bd6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 17:04:34 -0400 Subject: [PATCH 4/9] v.rectify: Report existing output map in separate messages The error was split over two warnings and a fatal error, so the sentence was translated in pieces. Use complete sentences with a single placeholder each, so that no positional placeholders are needed. --- vector/v.rectify/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/v.rectify/main.c b/vector/v.rectify/main.c index b337e8cd85a..535d87ea82c 100644 --- a/vector/v.rectify/main.c +++ b/vector/v.rectify/main.c @@ -199,10 +199,10 @@ int main(int argc, char *argv[]) select_target_env(); if (G_find_vector2(out_opt->answer, G_mapset())) { - G_warning(_("The vector map <%s> already exists in"), + G_warning(_("The vector map <%s> already exists."), out_opt->answer); - G_warning(_("target project %s, mapset %s:"), G_location(), - G_mapset()); + G_warning(_("Target project: <%s>"), G_location()); + G_warning(_("Target mapset: <%s>"), G_mapset()); G_fatal_error(_("Rectification cancelled.")); } select_current_env(); From a6a2f80f0cc0878c23288fda6a812146a0275f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 17:04:35 -0400 Subject: [PATCH 5/9] db.dbf: Split SQL parser error into complete messages The message was joined from separately translated fragments. Use two complete messages with one placeholder each. --- db/drivers/dbf/dbfexe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/drivers/dbf/dbfexe.c b/db/drivers/dbf/dbfexe.c index 957581d83a6..263a6e37d05 100644 --- a/db/drivers/dbf/dbfexe.c +++ b/db/drivers/dbf/dbfexe.c @@ -62,8 +62,8 @@ int execute(char *sql, cursor *c) if (yyparse() != 0) { G_free(tmpsql); - db_d_append_error("%s (%s) %s\n%s\n", _("SQL parser error"), st->errmsg, - _("in statement:"), sql); + db_d_append_error(_("SQL parser error: %s\n"), st->errmsg); + db_d_append_error(_("Statement: %s\n"), sql); sqpFreeStmt(st); return DB_FAILED; } From f8a5259af104b64cff08054cc1818be9525351ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 19:14:00 -0400 Subject: [PATCH 6/9] v.class: Translate column headers instead of the format string The format string '%15s%15s%15s' was translated, which splits a table header over three untranslatable arguments. Translate each column header instead. --- vector/v.class/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vector/v.class/main.c b/vector/v.class/main.c index 69ca30de1d0..4f49f77d770 100644 --- a/vector/v.class/main.c +++ b/vector/v.class/main.c @@ -313,8 +313,13 @@ int main(int argc, char *argv[]) fprintf(stdout, _("Stdev multiplied by %.4f to define step\n"), finfo); fprintf(stdout, "\n"); - fprintf(stdout, _("%15s%15s%15s\n\n"), "From (excl.)", "To (incl.)", - "Frequency"); + fprintf(stdout, "%15s%15s%15s\n\n", + /* GTC Column header, lower class limit (exclusive) */ + _("From (excl.)"), + /* GTC Column header, upper class limit (inclusive) */ + _("To (incl.)"), + /* GTC Column header, number of values in the class */ + _("Frequency")); fprintf(stdout, "%15.5f%15.5f%15i\n", min, classbreaks[0], frequencies[0]); From 737c7ba434b8c8a12c38bc364e2d51ee939b507f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 19:14:00 -0400 Subject: [PATCH 7/9] lib/gis: Remove leading space from window overlap warnings Leading whitespace in a msgid is easy to lose or misplace in translations. --- lib/gis/view.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gis/view.c b/lib/gis/view.c index 2ae721b628b..f906c7ab2fb 100644 --- a/lib/gis/view.c +++ b/lib/gis/view.c @@ -526,12 +526,12 @@ pr_winerr(int vis, /* % of saved window overlapping current window */ { switch (vis) { case 0: - G_warning(_(" Window saved in \"%s\" is completely outside of current " + G_warning(_("Window saved in \"%s\" is completely outside of current " "GRASS window."), viewname); break; default: - G_warning(_(" Only %d%% of window saved in \"%s\" overlaps with " + G_warning(_("Only %d%% of window saved in \"%s\" overlaps with " "current GRASS window."), vis, viewname); break; From 24638158f90da05355580b5c9f4172bad935f275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 19:14:01 -0400 Subject: [PATCH 8/9] v.in.ogr, v.profile: Fix typos in messages Fix 'where' for 'were' and the capitalized 'Your'. --- vector/v.in.ogr/main.c | 2 +- vector/v.profile/main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/v.in.ogr/main.c b/vector/v.in.ogr/main.c index 9021408651d..5717ab9da4d 100644 --- a/vector/v.in.ogr/main.c +++ b/vector/v.in.ogr/main.c @@ -1924,7 +1924,7 @@ int main(int argc, char *argv[]) } if (ncentr > n_polygons) { G_important_message( - _("%d additional areas where created during import."), + _("%d additional areas were created during import."), ncentr - n_polygons); } if (snap > 0) { diff --git a/vector/v.profile/main.c b/vector/v.profile/main.c index e33eec26cce..0e4fb8a9d33 100644 --- a/vector/v.profile/main.c +++ b/vector/v.profile/main.c @@ -484,7 +484,7 @@ int main(int argc, char *argv[]) if (ncats < 1) { Vect_close(&In); Vect_close(&Pro); - G_fatal_error(_("No features match Your query")); + G_fatal_error(_("No features match your query")); } if (ncats > 1) { Vect_close(&In); @@ -649,7 +649,7 @@ int main(int argc, char *argv[]) ncats = db_select_int(driver, Fi->table, Fi->key, where_opt->answer, &cats); if (ncats < 1) - G_fatal_error(_("No features match Your query")); + G_fatal_error(_("No features match your query")); for (i = 0; i < ncats; i++) { c = Vect_cidx_find_next(&In, field_index, cats[i], otype, 0, &type, &id); From 0a48f5ae21f593adbc61abc27c0b413cc5cad0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 3 Oct 2026 19:14:01 -0400 Subject: [PATCH 9/9] db.sqlite: Write SQLite consistently in messages --- db/drivers/sqlite/db.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/drivers/sqlite/db.c b/db/drivers/sqlite/db.c index cd86e4648f6..988c71f9e64 100644 --- a/db/drivers/sqlite/db.c +++ b/db/drivers/sqlite/db.c @@ -101,7 +101,7 @@ int db__driver_open_database(dbHandle *handle) if (access(path, 0) != 0) { if (G_mkdir(path) != 0) G_fatal_error( - _("Unable to create directory '%s' for sqlite database"), + _("Unable to create directory '%s' for SQLite database"), path); } } @@ -116,7 +116,7 @@ int db__driver_open_database(dbHandle *handle) G_important_message(_("Disabling SQLite locking")); } else { - G_warning(_("The sqlite config option '%s' is not supported"), + G_warning(_("The SQLite config option '%s' is not supported"), "SQLITE_CONFIG_URI"); if (G_strlcpy(name3, name2, sizeof(name3)) >= sizeof(name3)) { db_d_append_error(_("Database name <%s> is too long"), name2); @@ -195,7 +195,7 @@ int db__driver_create_database(dbHandle *handle) G_important_message(_("Disabling SQLite locking")); } else { - G_warning(_("The sqlite config option '%s' is not supported"), + G_warning(_("The SQLite config option '%s' is not supported"), "SQLITE_CONFIG_URI"); if (G_strlcpy(name2, name, sizeof(name2)) >= sizeof(name2)) { db_d_append_error(_("Database name <%s> is too long"), name);