Skip to content

i18n: Improve some C source strings flagged on Weblate - #8012

Merged
echoix merged 9 commits into
OSGeo:mainfrom
echoix:i18n-complete-source-strings
Oct 10, 2026
Merged

echoix merged 9 commits into
OSGeo:mainfrom
echoix:i18n-complete-source-strings

Conversation

@echoix

@echoix echoix commented Oct 4, 2026

Copy link
Copy Markdown
Member

Over the last year or two, when translating on Weblate, I flagged some source strings. This cleans up some C strings based on these comments.

Description

Fix C source strings flagged by comments on Weblate: messages built from separately translated fragments or with a substituted word, which translators cannot adapt, plus a few typos and an inconsistent term.

  • r.in.pdal: the point count messages used _(GPOINT_COUNT_FORMAT " points ..."). xgettext extracted a fragment, and the msgid at runtime (%llu points ...) matched no catalog entry, so they were never translated. They now use PRIu64, so the msgid is the same whatever the type of the count, and the final message is split into sentences with one placeholder each.
  • r.reclass, r.horizon, v.rectify, db.dbf: no more strings translated in pieces or with a substituted word.
  • v.class: translate the column headers instead of the %15s%15s%15s format string, with translator comments.
  • lib/gis/view.c: remove leading spaces in the window overlap warnings.
  • v.in.ogr, v.profile: fix typos.
  • SQLite driver: "SQLite" (the database engine) spelled consistently.

Positional placeholders (%1$s) are not used. With plain snprintf/vsnprintf they are not interpreted on MSVC (the output is $s $s), so messages that would need reordering are split into sentences with one placeholder each. They do work on MinGW.

Motivation and context

Translators cannot reorder or adapt text that is split across several _() calls or filled with a substituted word, and some strings were never translated at all (r.in.pdal).

How has this been tested?

Built by CI on Linux, macOS, MinGW and MSVC. Positional placeholder support was checked with a small C program on MSVC and MinGW64 (MSYS2), with and without libintl.

For the PRIu64 messages: xgettext with the options of locale/Makefile extracts %<PRIu64> points found in region.; after msgfmt and a French catalog, a program using unsigned long long and unsigned long counts printed the translated message with the number substituted in both cases.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing
    functionality to not work as before)

Checklist

  • PR title provides summary of the changes and starts with one of the
    pre-defined prefixes
  • My code follows the code style
    of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.

AI assistance (Claude) was used to find the affected strings from the Weblate comments and to draft these changes.
(All of the comments on weblate, or most if there would have been one not, were written by me originally, flagged when translating in french over the last year or two)

echoix added 9 commits October 4, 2026 11:53
Join the 'Illegal reclass rule' and 'invalid reclass rule' messages instead of translating their pieces separately.
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().
The direction was a separately translated word substituted into the sentence, which cannot agree in gender or case in all languages.
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.
The message was joined from separately translated fragments. Use two complete messages with one placeholder each.
The format string '%15s%15s%15s' was translated, which splits a table header over three untranslatable arguments. Translate each column header instead.
Leading whitespace in a msgid is easy to lose or misplace in translations.
Fix 'where' for 'were' and the capitalized 'Your'.
@github-actions github-actions Bot added vector Related to vector data processing raster Related to raster data processing C Related code is in C C++ Related code is in C++ database Related to database management libraries module labels Oct 4, 2026
@echoix
echoix requested a review from petrasovaa October 5, 2026 16:23
@echoix

echoix commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

I re-reviewed everything here. Then, I made Opus 5.5 re-review these changes. Only one file was not string-only changes. It still agrees. Due to low risk, and clear benefits, I'll be merging after waiting a week for reviews.

Details

Need the PR head branch name.

Fetched from upstream. Now find the merge base and diff.

Let me verify the r.in.pdal claims myself before reporting.

Key thing to verify: whether the (uint64_t) casts are actually needed (the review agent called them redundant), and whether any tests parse the old final message.

Casts are required (without them -Wformat warns on LP64). Now confirming xgettext handles PRIu64 inside _():

I fetched PR 8012 from upstream (refs/pull/8012/head, 5 commits, head 0a48f5a) into a local branch pr-8012 and reviewed it against its merge base. The r.in.pdal change is correct and fixes a real translation bug. I found no correctness bugs anywhere in the PR. The reviewer agent raised one point that was wrong, which I checked and drop below.

raster/r.in.pdal/main.cpp

Why the change is needed. The old code put GPOINT_COUNT_FORMAT inside _(). xgettext can't expand macros, so it extracted cut-off msgids. I ran xgettext on both versions to confirm:

  Extracted msgid
Before " points found in input file(s)" (number gone)
Before "Raster map <%s> created. " (rest of the sentence gone)
After "% points found in input file(s)", flagged c-format
After "% points found in region.", "Number of input files: %d", "Raster map <%s> created."

At runtime the full string, with %llu in it, never matched those msgids, so these messages were never translated. xgettext and msgfmt handle PRIu64 specially (the %<PRIu64> placeholder), so the new form is the right one.

The (uint64_t) casts are needed. The agent called them redundant, but they aren't. gpoint_count is unsigned long long, while on 64-bit Linux PRIu64 is "lu". I compiled a test without the cast and g++ -Wformat warns: '%lu' expects 'long unsigned int', but argument has type 'long long unsigned int'. With the cast it compiles cleanly, and it can only widen the value, never truncate it.

Removing buff/BUFFSIZE is fine. Both were used only by the two snprintf calls that were removed, and the PR also drops the risk of a silently truncated message.

Points worth raising (none blocking):

  1. The final output changes. The G_done_msg line used to read "Raster map <X> created. N points [from M files] found in region." Now the count and the file count come earlier as separate G_message lines, and the done line only says the map was created. Anyone scraping that last line for the count will notice. No tests in tests/ or testsuite/ match on this text.
  2. Two count formats in one function. Lines 988–1013 still use GPOINT_COUNT_FORMAT. That's acceptable because those messages aren't wrapped in _(). A follow-up could make gpoint_count a uint64_t in lidar.h and use PRIu64 everywhere, which would remove the casts. That's out of scope for a messages PR.

Other files

  • r.reclass: this is better than before. Dropping strcat into buf[1024] removes a possible overflow, and the tty message is no longer two separately translated halves. Optional: quote the rule, e.g. Invalid reclass rule: <%s>.
  • v.class: translating the headers separately is correct for gettext. The catch is that translations longer than 15 bytes run into the next column, and %15s pads multibyte UTF-8 by bytes, so headers can misalign with the number columns. This is minor.
  • dbfexe.c: splitting into two db_d_append_error calls changes the shape of the error text callers get. It's fine, just worth knowing.
  • v.rectify: one cause now produces three warnings and then a fatal error. A single G_fatal_error naming the map, project and mapset would be tidier. This is optional.
  • r.horizon, view.c, db.sqlite, v.in.ogr, v.profile: these are string-only changes and are correct.

I left the PR checked out as local branch pr-8012. Nothing was committed or pushed, and nothing was posted on the PR.

@echoix
echoix merged commit 9c7baf5 into OSGeo:main Oct 10, 2026
26 checks passed
@github-actions github-actions Bot added this to the 8.6.0 milestone Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C Related code is in C C++ Related code is in C++ database Related to database management libraries module raster Related to raster data processing vector Related to vector data processing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant