Repository navigation
i18n: Translations for addons (separate domain) #728
Description
Addon messages and interface strings are not translatable today. This issue records what was found while working on #727 and proposes how to add addon translations later, as a separate gettext domain so that the core translators (with limited capacity) are not flooded.
Current state
Nothing is extracted. OSGeo/grass-addons has no POT/PO/MO files, no make pot-like target, and no translation workflow. The old scriptstrings Make rules ran during addon builds, but g.extension passed STRINGDIR=<addon source dir>, so the <tool>_to_translate.c files were written into the temporary build directory and deleted (scripts/g.extension/g.extension.py had # TODO: handle locales also for addons). #727 removes these rules and the dead STRINGDIR.
Runtime lookup only uses core catalogs, so an addon string is translated only if the identical string exists in core:
- Interface headers: g.parser translates with
GRASS_TRANSLATION_DOMAINorgrassmods(general/g.parser/translate.c). Nothing setsGRASS_TRANSLATION_DOMAIN, andG_init_locale()(lib/gis/locale.c) binds onlygrasslibsandgrassmodsto$GISBASE/locale, so another domain would be looked up in the system locale directory. - Python
_(): the builtin frompython/grass/__init__.pytriesgrasslibs, thengrassmods, thengrasswxpyfrom$GISBASE/locale. A few addons callgettext.install("grassmods" or "grasswxpy", ...)themselves (e.g.r.basin,v.krige); some use plaingettext.gettext. - C:
_()usesPACKAGE, which isgrassmodsfor all addons (include/Make/Module.make).
Size: the headers of the 366 script tools in grass-addons (364 Script.make with $(PGM).py, and 2 ShScript.make shell scripts, r.stream.variables and r.stream.watersheds) give 5359 strings, 4829 of them not in any core POT. This doesn't count _() messages in addon Python and C code.
Proposal
- Extraction (in grass-addons):
- Headers:
utils/grass_tool_header_pot.pyfrom i18n: Extract tool header strings without a build, with context for translators #727 reads any script (Python, shell, extension-less) and accepts file arguments. Add an option to search another tree layout (src/<category>/...), or pass the files found from the Makefiles. - Messages:
xgettextfor_()/n_()in addon.py,.c,.cpp, aslocale/Makefiledoes in core. - Write one
grassaddons.potin grass-addons; add a Weblate component for it, possibly with low priority or headers only at first.
- Headers:
- Runtime (in core):
- Bind the addon domain in
G_init_locale()to the directory where addon translations are installed. - g.parser: look up
grassaddonsaftergrassmods(or have g.extension setGRASS_TRANSLATION_DOMAINwhen running addons). - Python: add the domain to the
_translatefallback chain inpython/grass/__init__.py. - C addons:
PACKAGEcould be set tograssaddonsby the addon build, with a fallback tograssmodsfor strings shared with core.
- Bind the addon domain in
- Installation: decide where
.mofiles go ($GRASS_ADDON_BASE/locale?) and whether g.extension downloads compiled catalogs or compiles them withmsgfmt(not always available, e.g. on Windows).
Open questions
- Is a single
grassaddonsdomain right, or one per addon (simpler to ship with the addon, but many small Weblate components)? - Should strings already translated in core be excluded from
grassaddons.potto save translator time (the runtime fallback tograssmodswould still find them)? - Start with interface headers only, since they are what users see in the GUI and in
--help?
Activity