Repository navigation
Conversation
The guidependency field is a list of option keys used by the GUI (e.g., input,maps), so a translation would break the dependency. C tools already set it without translation. Developed with assistance from Claude (Anthropic).
The descriptions field (value;description;value;description...) was translated as a whole, so the values were part of the translatable string and translators could change them, breaking the tool. Now each description is translated separately with the message context "option value description", looked up the same way as pgettext() from GNU gettext.h. The values are kept as written. A translation containing a semicolon is not used because it would split into more items. Without a translation, the result is the same as before. Developed with assistance from Claude (Anthropic).
The strings of the # %module, # %flag, and # %option headers of Python tools were collected by running g.parser -t during the build and writing them to locale/scriptstrings/*_to_translate.c files for xgettext. The resulting entries in grassmods.pot referred to these generated files, so Weblate could not link to the source, and translators had no context. Add locale/grass_tool_header_pot.py, which reads the headers directly using only the Python standard library and writes a standard POT file: - references point to the real source file and line, - extracted comments tell translators what each string is (tool description, keyword, label of an option, GUI section, ...), - descriptions of option values are separate entries with the "option value description" context, as g.parser now translates them. make pot merges this POT into grassmods.pot with xgettext. Tools are found by their Makefiles as in the build, which now also includes the g.gui.* tools that were not extracted before. Remove the scriptstrings rules from the Make and CMake builds. The Windows launcher, which the CMake script also created, is now created when configuring as for the GUI tools. With CMake, the scriptstrings lines containing a semicolon were also split because CMake treats semicolons as list separators. Developed with assistance from Claude (Anthropic).
Generated with make pot. The entries from tool headers now refer to the source files instead of locale/scriptstrings, have comments for translators, and descriptions of option values are separate entries with the "option value description" context. The g.gui.* tools are included. Developed with assistance from Claude (Anthropic).
The tools in gui/scripts (d.rast3d, d.wms) are installed by a plain Python Makefile without the script rules, so their interface strings were not extracted. Add them to the extractor. The script build rules also accepted shell scripts (ShScript.make, used by addons) and files without an extension. Test that the extractor finds and reads them, that header commands ignore case as in g.parser, and that g.parser gives the same interface for a shell script as for a Python script. Developed with assistance from Claude (Anthropic).
STRINGDIR was passed so that building an addon with make would write the strings for translation from its interface header into the temporary source directory instead of the GRASS installation. The files were never used and the build rules using STRINGDIR are now removed. Developed with assistance from Claude (Anthropic).
This was referenced Oct 4, 2026
pytest runs with --import-mode=importlib, which imported the locale/tests directory as part of a package named locale. That package replaced the standard library locale module for the following tests in the same process, which then failed (module 'locale' has no attribute 'normalize'). Move the extractor and its tests to utils, next to the other build helpers. Developed with assistance from Claude (Anthropic).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Replaces the
locale/scriptstringsworkaround for the# %module/# %flag/# %optionheaders of script tools.utils/grass_tool_header_pot.py(Python standard library only) reads the headers directly and writes a standard POT: references to the real source lines,#.comments saying what each string is (tool description, keyword, option label, GUI section, ...).make potmerges it intograssmods.potwithxgettext -j.$(PGM).py,$(PGM).shor an extension-less$(PGM)(Script.make, ShScript.make),g.gui.*.py(GuiScript.make), plusgui/scripts/*.py(d.rast3d, d.wms), which were not extracted before. Other files can be given as arguments.descriptionsseparately, with the message contextoption value description, so the values are no longer part of translatable strings. A translation containing;is ignored. Without a translation, the output is unchanged.guidependency(a list of option keys).STRINGDIRvariable passed by g.extension. The Windows launcher previously created bycmake/locale_strings.cmakeis now created at configure time, as for GUI tools.grassmods.potregenerated in separate commits; they can be dropped if preferred.Motivation and context
The entries pointed to generated
locale/scriptstrings/*_to_translate.cfiles, so Weblate could not link to the source, a full build was needed, and translators had no context. Value lists were one string, so values could be translated by mistake (24 of the 44 existing translations of these strings did). Theg.gui.*andgui/scriptstools were not extracted. With CMake, strings containing;were also split.xgettext has no plugin mechanism for new languages, and ITS rules only apply to XML input, so a separate extractor producing a standard POT merged by gettext is the standard way to extend it.
The extractor and its tests are in
utils/, notlocale/: with--import-mode=importlib, tests underlocale/make pytest import that directory as a package namedlocale, which replaces the standard library module for the following tests.How has this been tested?
make pot(Autotools): compared to the currentgrassmods.pot, the only changes are the split value descriptions, removedguidependencyvalues, and the addedg.gui.*andgui/scriptsstrings; no C references changed..moin a French locale: a description with the context is translated, a translation with;is rejected, and an entry without the context is not used.utils/tests/(including shell, extension-less, and Perl files, and capitalized header commands) andgeneral/g.parser/tests/(Python and shell scripts); CMake build with and without docs; pre-commit.msgfmtaccepts the result.Types of changes
functionality to not work as before)
Checklist
pre-defined prefixes
of this project.
The extractor and the g.parser changes were written with assistance from Claude (Anthropic).