diff --git a/.flake8 b/.flake8 index 058ce00c4c8..fadfa7f9c9c 100644 --- a/.flake8 +++ b/.flake8 @@ -33,8 +33,6 @@ per-file-ignores = gui/wxpython/mapdisp/test_mapdisp.py: E501 gui/wxpython/mapswipe/g.gui.mapswipe.py: E501 gui/wxpython/timeline/g.gui.timeline.py: E501 - # Generated file - gui/wxpython/menustrings.py: E501 # C wrappers call libgis.G_gisinit before importing other modules. # TODO: Is this really needed? python/grass/jupyter/__init__.py: E501 diff --git a/.gitignore b/.gitignore index ac47be4c591..a879be58b5b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ macos/cache/* *.dox.org # Ignore specific files generated during make -gui/wxpython/menustrings.py gui/wxpython/xml/menudata.xml gui/wxpython/xml/module_tree_menudata.xml include/Make/Doxyfile_arch_html diff --git a/doc/development/README.md b/doc/development/README.md index 08da6f1fc99..9a5888d38b9 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -22,3 +22,7 @@ maintaining GRASS. ## C API - [GRASS Programmer's manual](https://grass.osgeo.org/programming8/) + +## wxGUI + +- [wxGUI menus and their translation](wxgui_menus.md) diff --git a/doc/development/wxgui_menus.md b/doc/development/wxgui_menus.md new file mode 100644 index 00000000000..68e7e8690f8 --- /dev/null +++ b/doc/development/wxgui_menus.md @@ -0,0 +1,145 @@ +# wxGUI menus and their translation + +This note describes how the menus of the wxGUI are defined, built and +translated. It covers the main menu, the tool tree (Tools tab), and the menus +of the Graphical Modeler, the Cartographic Composer and the Python editor. +Paths of wxGUI files are relative to `gui/wxpython/`, other paths to the +repository root. + +## Source files + +| File | Content | +| --- | --- | +| `xml/main_menu.xml` | Root of the main menu: the top-level toolboxes. | +| `xml/module_tree.xml` | Root of the tool tree, with the `` and `` placeholders. | +| `xml/toolboxes.xml` | Toolboxes (menus) with their labels and items: `module-item` (a tool), `wxgui-item`, `subtoolbox`, `separator`. | +| `xml/wxgui_items.xml` | GUI items: label, handler or command, description, keywords. | +| `xml/menudata_modeler.xml`, `xml/menudata_psmap.xml`, `xml/menudata_pyedit.xml` | Complete menus in the final `menudata` format, read as they are. | +| `xml/*.dtd` | Structure of each file type. | + +## Build and runtime + +At build time, with the C locale (English): + +1. `tools/build_modules_xml.py` writes `module_items.xml` with the + description and keywords of every tool, taken from its interface + description. For a tool with a label, the description is the label and + the description joined with a space. +2. `core/toolboxes.py` combines `main_menu.xml` (or `module_tree.xml` with + the `module_tree` argument), `toolboxes.xml`, `wxgui_items.xml` and + `module_items.xml` into `menudata.xml` (or `module_tree_menudata.xml`). + It expands subtoolboxes, fills each item with the data of the item of the + same name (elements already in the item take precedence), adds handlers, + and converts the tags to the `menudata` format (`toolbox` to `menu`, + `description` to `help`, `module` to `command`, and so on). + +All three files are generated and not committed. Autotools writes +`module_items.xml` directly to the `xml/` directory of the distribution and +the other two to `xml/` in the source tree (ignored by Git), from where the +distribution gets copies. CMake writes all of them to the output tree. + +At runtime, `core/menutree.py` (`MenuTreeModelBuilder`) reads a `menudata` +file into a tree model, passing each menu label, item label and item help +through `_()`. Classes in `lmgr/menudata.py`, `gmodeler/menudata.py`, +`psmap/menudata.py` and `gui_core/pyedit.py` choose the file. When the user +config directory has `toolboxes/toolboxes.xml`, `toolboxes/main_menu.xml` or +`toolboxes/module_tree.xml`, `core/toolboxes.py` regenerates the menu data in +that directory when it is missing or older than these files. Each time the +tool tree is loaded, its `` placeholder is replaced by an Addons +menu listing the installed addons. + +```mermaid +flowchart LR + TOOLS["tools
--interface-description"] --> BMX["tools/build_modules_xml.py"] + BMX --> MI["module_items.xml"] + MM["main_menu.xml
module_tree.xml"] --> TBX["core/toolboxes.py"] + TB["toolboxes.xml
wxgui_items.xml"] --> TBX + MI --> TBX + USER["user toolboxes/*.xml"] -. runtime .-> TBX + TBX --> MD["menudata.xml
module_tree_menudata.xml"] + MD --> MT["core/menutree.py"] + MDX["menudata_modeler.xml
menudata_psmap.xml
menudata_pyedit.xml"] --> MT + MT --> GUI["menus and tool tree"] +``` + +To print a menu as a tree or as a list of tools, run in a GRASS session from +the installed `gui/wxpython` directory: + +```bash +PYTHONPATH=. python core/menutree.py tree manager # or module_tree, modeler, psmap +PYTHONPATH=. python core/menutree.py commands manager +``` + +## Translation + +`make pot` in `locale/` writes the templates in `locale/templates/`. For the +`grasswxpy` domain, it extracts the `_()` strings from the Python files of the +wxGUI, then joins (`-j`) the strings of the committed menu XML files listed in +`WXPY_XMLFILES`. xgettext finds the rules for these files through +`GETTEXTDATADIRS=locale/`: `locale/its/grass-wxgui.loc` maps the root +elements `toolboxes`, `wxgui-items` and `menudata` to +`locale/its/grass-wxgui.its`, which marks `label`, `help` and `description` +as translatable and adds translator comments built from the XML itself. + +This part reads no generated file, so it needs no build. The help of a tool +item is the tool description, which is translated from `grassmods` for a tool +without a label, because `_()` in +`python/grass/__init__.py` looks a message up in `grasslibs`, then +`grassmods`, then `grasswxpy`. + +```mermaid +flowchart LR + PY["gui/wxpython/**/*.py"] --> XG1["xgettext"] + XML["xml/toolboxes.xml
xml/wxgui_items.xml
xml/menudata_*.xml"] --> XG2["xgettext +
locale/its/grass-wxgui.*"] + XG1 --> WXPOT["grasswxpy.pot"] + XG2 -- "-j" --> WXPOT + C["C tools,
locale/scriptstrings"] --> XG3["xgettext"] --> MODPOT["grassmods.pot"] + LIB["lib/"] --> XG4["xgettext"] --> LIBPOT["grasslibs.pot"] + WXPOT & MODPOT & LIBPOT -- "make update-po" --> PO["locale/po/*.po
(Weblate)"] + PO -- msgfmt --> MO["GISBASE/locale/LANG/
LC_MESSAGES/*.mo"] + MO --> RT["_(): grasslibs, grassmods,
grasswxpy"] +``` + +## How to add or change a menu entry + +- Tool: add `` + to a toolbox in `xml/toolboxes.xml`. The help text comes from the tool. +- GUI item: define a `wxgui-item` in `xml/wxgui_items.xml` with a handler + method of the main window frame (`lmgr/frame.py` and `main_window/frame.py`) + or a command, and reference it by name from `xml/toolboxes.xml`. +- Menu: add a `toolbox` to `xml/toolboxes.xml` and a `subtoolbox` reference + to its parent toolbox, to `xml/main_menu.xml` or to `xml/module_tree.xml`. +- Modeler, Cartographic Composer or Python editor: edit its + `xml/menudata_*.xml`. +- New XML file with translatable strings: add it to `WXPY_XMLFILES` in + `locale/Makefile` and, for a new root element, a rule to + `locale/its/grass-wxgui.loc`. + +Rebuild to regenerate the menu data. Mark an accelerator key by `&` (written +`&` in XML) before its letter. + +## How translators see it + +Each menu string appears once in `grasswxpy.pot` with references to the +committed XML files and lines and a comment in a `key=value` form, for +example: + +```text +#. type=menu-item-help (description of a menu entry); label="Georectify" +#: ../gui/wxpython/xml/wxgui_items.xml:8 +msgid "Manage Ground Control Points for Georectification" +``` + +The `&` of an accelerator key stays in the message as it is. + +## Known limitations + +- The help of a tool with a label (label and description joined) is not in + any template, so it is shown untranslated. +- Keywords are neither extracted nor passed through `_()`. +- Labels from user toolboxes and descriptions of addons are not in any + template. +- Messages have no context: identical strings share one translation, and the + first domain containing a message wins. +- The descriptions of Python tools reach `grassmods.pot` through + `locale/scriptstrings/*_to_translate.c`, which only a build generates. diff --git a/gui/wxpython/CMakeLists.txt b/gui/wxpython/CMakeLists.txt index 2261deb385b..cec3f3f8ed7 100644 --- a/gui/wxpython/CMakeLists.txt +++ b/gui/wxpython/CMakeLists.txt @@ -147,6 +147,7 @@ if(NOT WITH_FHS) add_custom_target( build_module_tree_menudata + ALL COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/core/toolboxes.py "module_tree" > @@ -163,26 +164,6 @@ if(NOT WITH_FHS) ) set_target_properties(build_module_tree_menudata PROPERTIES FOLDER GUI) - - add_custom_target( - build_menustrings - ALL - COMMAND - ${grass_env_command} ${PYTHON_EXECUTABLE} - ${CMAKE_CURRENT_SOURCE_DIR}/core/menutree.py "manager" >> - ${CMAKE_CURRENT_SOURCE_DIR}/menustrings.py - COMMAND - ${grass_env_command} ${PYTHON_EXECUTABLE} - ${CMAKE_CURRENT_SOURCE_DIR}/core/menutree.py "module_tree" >> - ${CMAKE_CURRENT_SOURCE_DIR}/menustrings.py - COMMAND - ${grass_env_command} ${PYTHON_EXECUTABLE} - ${CMAKE_CURRENT_SOURCE_DIR}/core/menutree.py "psmap" >> - ${CMAKE_CURRENT_SOURCE_DIR}/menustrings.py - DEPENDS build_module_tree_menudata gui_images - ) - - set_target_properties(build_menustrings PROPERTIES FOLDER GUI) endif() # NOT WITH_FHS install(DIRECTORY "${OUTDIR}/${WXPYTHON_DIR}/xml" DESTINATION "${WXPYTHON_DIR}") diff --git a/gui/wxpython/Makefile b/gui/wxpython/Makefile index 343599fe01a..393a0141d26 100644 --- a/gui/wxpython/Makefile +++ b/gui/wxpython/Makefile @@ -1,7 +1,7 @@ MODULE_TOPDIR = ../.. SUBDIRS = docs animation datacatalog mapswipe gmodeler rlisetup psmap dbmgr vdigit rdigit iclass gcp timeline tplot photo2image image2target -EXTRA_CLEAN_FILES = menustrings.py build_ext.pyc xml/menudata.xml xml/module_tree_menudata.xml */*.pyc +EXTRA_CLEAN_FILES = build_ext.pyc xml/menudata.xml xml/module_tree_menudata.xml */*.pyc include $(MODULE_TOPDIR)/include/Make/Dir.make include $(MODULE_TOPDIR)/include/Make/Python.make @@ -33,7 +33,8 @@ ifndef CROSS_COMPILING -$(MAKE) $(DSTDIR)/xml/module_items.xml -$(MAKE) xml/menudata.xml -$(MAKE) xml/module_tree_menudata.xml - -$(MAKE) menustrings.py + -$(MAKE) $(DSTDIR)/xml/menudata.xml + -$(MAKE) $(DSTDIR)/xml/module_tree_menudata.xml endif $(MAKE) parsubdirs @@ -49,13 +50,6 @@ xml/module_tree_menudata.xml: core/toolboxes.py $(call run_grass,$(PYTHON) $< "module_tree" > $@) $(call run_grass,$(PYTHON) $< "validate" $@) -menustrings.py: core/menutree.py $(DSTDIR)/xml/menudata.xml $(DSTDIR)/xml/module_tree_menudata.xml $(DSTDIR)/xml/menudata_modeler.xml $(DSTDIR)/xml/menudata_psmap.xml - @echo "# This is a generated file.\n# pylint: skip-file\n" > $@ - $(call run_grass,$(PYTHON) $< "manager" >> $@) - $(call run_grass,$(PYTHON) $< "module_tree" >> $@) - $(call run_grass,$(PYTHON) $< "modeler" >> $@) - $(call run_grass,$(PYTHON) $< "psmap" >> $@) - $(DSTDIR)/xml/module_items.xml: tools/build_modules_xml.py @echo "Generating interface description for all modules..." $(call run_grass,$(PYTHON) $< > $@) diff --git a/gui/wxpython/README.md b/gui/wxpython/README.md index 2fc4d78d5ee..af4b74df28b 100644 --- a/gui/wxpython/README.md +++ b/gui/wxpython/README.md @@ -55,15 +55,14 @@ clear the display and start from scratch. Notes: - Help part of menu entries is coming from the module descriptions -- The menu is generated by `./tools/build_modules_xml.py` - -Update of module description strings in `./xml/menudata.xml`: - -- in a GRASS session, run `./tools/update_menudata.py` - -From this (updated) `./xml/menudata.xml`, the gettext strings are generated -via Makefile and stored into the file `menustrings.py`. +- The menu data (`./xml/menudata.xml` and `./xml/module_tree_menudata.xml`) + is generated by `./core/toolboxes.py` +- How the menus are built and translated is described in + [wxGUI menus and their translation](../../doc/development/wxgui_menus.md) While generating the po files in `../../locale/po/` by `../../locale/Makefile`, all `.py` files are parsed and the strings are stored in -`../../locale/po/grasswxpy_XX.po`. +`../../locale/po/grasswxpy_XX.po`. The labels, help texts and descriptions in +the menu definitions (`./xml/toolboxes.xml`, `./xml/wxgui_items.xml` and +`./xml/menudata_*.xml`) are extracted with the ITS rules in +`../../locale/its/`. diff --git a/gui/wxpython/core/menutree.py b/gui/wxpython/core/menutree.py index 1975c99badb..5508870d6e8 100644 --- a/gui/wxpython/core/menutree.py +++ b/gui/wxpython/core/menutree.py @@ -12,8 +12,7 @@ @endcode where action: - - strings (default, used for translations) - - tree (simple tree structure) + - tree (default, simple tree structure) - commands (command names and their place in tree) - dump (tree structure with stored data) @@ -38,8 +37,6 @@ import copy import xml.etree.ElementTree as ET -from typing import TYPE_CHECKING - import wx from core.treemodel import TreeModel, ModuleNode @@ -52,9 +49,6 @@ if not os.getenv("GISBASE"): sys.exit("GRASS is not running. Exiting...") -if TYPE_CHECKING: - from typing_extensions import Writer - # TODO: change the system to remove strange derived classes @@ -158,17 +152,6 @@ def PrintTree(self, fh): for child in self.model.root.children: printTree(node=child, fh=fh) - def PrintStrings(self, fh: Writer[str]): - """Print menu strings to file (used for localization) - - :param fh: file descriptor - """ - className = self.__class__.__name__ - fh.write("menustrings_%s = [\n" % className) - for child in self.model.root.children: - printStrings(child, fh) - fh.write(" '']\n") - def PrintCommands(self, fh): printCommands(self.model.root, fh, itemSep=" | ", menuSep=" > ") @@ -192,20 +175,6 @@ def printTree(node, fh, indent=0): printTree(node=child, fh=fh, indent=indent + 2) -def printStrings(node, fh: Writer[str]): - # node.label - with module in brackets - # node.data['label'] - without module in brackets - if node.label and not node.data: - fh.write(" _(%r),\n" % str(node.label)) - if node.data: - if node.data.get("label"): - fh.write(" _(%r),\n" % str(node.data["label"])) - if node.data.get("description"): - fh.write(" _(%r),\n" % str(node.data["description"])) - for child in node.children: - printStrings(node=child, fh=fh) - - def printCommands(node, fh, itemSep, menuSep): def collectParents(node, parents): parent = node.parent @@ -227,11 +196,11 @@ def collectParents(node, parents): if __name__ == "__main__": - action = "strings" + action = "tree" menu = "manager" for arg in sys.argv: - if arg in {"strings", "tree", "commands", "dump"}: + if arg in {"tree", "commands", "dump"}: action = arg elif arg in {"manager", "module_tree", "modeler", "psmap"}: menu = arg @@ -264,9 +233,7 @@ def collectParents(node, parents): gscore.fatal("Unknown value for parameter menu: %s" % menu) - if action == "strings": - menudata.PrintStrings(sys.stdout) - elif action == "tree": + if action == "tree": menudata.PrintTree(sys.stdout) elif action == "commands": menudata.PrintCommands(sys.stdout) diff --git a/gui/wxpython/docs/wxgui_sphinx/src/wxgui_libraries.rst b/gui/wxpython/docs/wxgui_sphinx/src/wxgui_libraries.rst index ec91edafd6f..e7bac32efe9 100644 --- a/gui/wxpython/docs/wxgui_sphinx/src/wxgui_libraries.rst +++ b/gui/wxpython/docs/wxgui_sphinx/src/wxgui_libraries.rst @@ -14,7 +14,6 @@ Libraries location_wizard mapdisp mapwin - menustrings modules nviz vnet diff --git a/gui/wxpython/docs/wxgui_sphinx/src/wxgui_toolboxes.rst b/gui/wxpython/docs/wxgui_sphinx/src/wxgui_toolboxes.rst index f7b54d9a54d..a00f7801598 100644 --- a/gui/wxpython/docs/wxgui_sphinx/src/wxgui_toolboxes.rst +++ b/gui/wxpython/docs/wxgui_sphinx/src/wxgui_toolboxes.rst @@ -32,25 +32,31 @@ Files related to toolboxes GRASS source code contains these XML files: * ``gui/wxpython/xml/main_menu.xml`` +* ``gui/wxpython/xml/module_tree.xml`` * ``gui/wxpython/xml/toolboxes.xml`` * ``gui/wxpython/xml/wxgui_items.xml`` -GRASS distribution contains these XML files: +GRASS distribution contains these XML files in ``gui/wxpython/xml`` +(relative to the GRASS installation directory): -* ``etc/gui/wxpython/xml/main_menu.xml`` -* ``etc/gui/wxpython/xml/toolboxes.xml`` -* ``etc/gui/wxpython/xml/wxgui_items.xml`` -* ``etc/gui/wxpython/xml/module_items.xml`` (generated during compilation) -* ``etc/gui/wxpython/xml/menudata.xml`` (generated during compilation) +* ``main_menu.xml`` +* ``module_tree.xml`` +* ``toolboxes.xml`` +* ``wxgui_items.xml`` +* ``module_items.xml`` (generated during compilation) +* ``menudata.xml`` (generated during compilation) +* ``module_tree_menudata.xml`` (generated during compilation) GRASS directory (``.grass8``) in user home directory (i.e., ``$HOME`` on Unix) contains these XML files: * ``toolboxes/main_menu.xml`` (created by user) +* ``toolboxes/module_tree.xml`` (created by user) * ``toolboxes/toolboxes.xml`` (created by user) * ``toolboxes/menudata.xml`` (generated on wxGUI startup) +* ``toolboxes/module_tree_menudata.xml`` (generated on wxGUI startup) .. graphviz:: @@ -69,8 +75,6 @@ GRASS directory (``.grass8``) in user home directory wxgui_items [label="wxgui_items.xml in distribution", shape="note", URL="#wxgui-items-file"]; module_items [label="module_items.xml in distribution", shape="note", URL="#module-items-file"]; - menustrings [label="menustrings.py\n(used for translations)", shape="note"]; - module_items -> menudata; wxgui_items -> menudata; main_menu -> menudata; @@ -83,10 +87,7 @@ GRASS directory (``.grass8``) in user home directory umain_menu -> umenudata; utoolboxes -> umenudata; - menudata -> menustrings; - // guimenu [label="Main menu in wxGUI", shape="box3d"]; - // menustrings -> guimenu; // menudata -> guimenu; // umenudata -> guimenu; } @@ -97,11 +98,15 @@ Other files GRASS source code contains these XML files: -* ``gui/wxpython/xml/menudata_gmodeler.xml`` +* ``gui/wxpython/xml/menudata_modeler.xml`` * ``gui/wxpython/xml/menudata_psmap.xml`` +* ``gui/wxpython/xml/menudata_pyedit.xml`` -In GRASS distribution these XML files are in the ``etc/gui/wxpython/xml`` -directory. +These files are already in the ``menudata`` format. In GRASS distribution +they are in the same ``gui/wxpython/xml`` directory. + +How the strings of all these files are extracted for translation is described +in ``doc/development/wxgui_menus.md`` in the source code. Generation of files and menu @@ -371,7 +376,7 @@ You should validate your XML before running wxGUI, e.g. using ``xmllint`` xmllint --noout --dtdvalid toolboxes.dtd toolboxes.xml You can find ``toolboxes.dtd`` and ``main_menu.dtd`` in your GRASS directory, -in ``etc/gui/wxpython/xml`` subdirectory. Depending on the validator, +in ``gui/wxpython/xml`` subdirectory. Depending on the validator, you might need to add DTD file to the drectory with the XML file. If you will provide an invalid, not well formed or empty file loading of diff --git a/gui/wxpython/gui_core/goutput.py b/gui/wxpython/gui_core/goutput.py index f491b576414..e2e8893be9c 100644 --- a/gui/wxpython/gui_core/goutput.py +++ b/gui/wxpython/gui_core/goutput.py @@ -166,7 +166,9 @@ def _layout(self): helpText = StaticText( self.panelPrompt, id=wx.ID_ANY, - label="Press Tab to display command help, Ctrl+Space to autocomplete", + label=_( + "Press Tab to display command help, Ctrl+Space to autocomplete" + ), ) helpText.SetForegroundColour( wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) diff --git a/gui/wxpython/xml/menudata.README b/gui/wxpython/xml/menudata.README index 9ddcad09ab4..24ae66c43a0 100644 --- a/gui/wxpython/xml/menudata.README +++ b/gui/wxpython/xml/menudata.README @@ -1,6 +1,10 @@ MENU - the entries in menudata.xml and module_tree_menudata.xml are autogenerated - via tools/build_modules_xml.py (see ../Makefile) + by core/toolboxes.py from main_menu.xml (or module_tree.xml), toolboxes.xml, + wxgui_items.xml and module_items.xml, which is generated by + tools/build_modules_xml.py (see ../Makefile and ../CMakeLists.txt) +- How the menus are built and translated is described in + ../../../doc/development/wxgui_menus.md - Find more info at https://grass.osgeo.org/grass-devel/manuals/wxGUI.toolboxes.html (../docs/wxgui_sphinx/src/) diff --git a/locale/Makefile b/locale/Makefile index d60b091b680..3e466f4360f 100644 --- a/locale/Makefile +++ b/locale/Makefile @@ -34,6 +34,10 @@ DOMAINS = $(LIBDOMAIN) $(MODDOMAIN) $(WXPYDOMAIN) LIB_POTFILES = find ../lib \( -name "*.c" -o -name "*.py" \) | LC_ALL=C sort | xargs grep -l "_(\"\|n_(\"" MOD_POTFILES = find ../ \( -name "*.c" -o -name "*.cpp" \) | grep -v '../lib' | LC_ALL=C sort | xargs grep -l "_(\"\|n_(\"" WXPY_POTFILES = find ../gui/wxpython -name '*.py' | LC_ALL=C sort | xargs grep -l "_(\"\|n_(\"" +#wxGUI menu definitions, extracted with the ITS rules in ./its +WXPY_XMLFILES = ../gui/wxpython/xml/toolboxes.xml ../gui/wxpython/xml/wxgui_items.xml \ + ../gui/wxpython/xml/menudata_modeler.xml ../gui/wxpython/xml/menudata_psmap.xml \ + ../gui/wxpython/xml/menudata_pyedit.xml #For Python script module messages MOD_PYFILES = find ../scripts -name '*.py' | LC_ALL=C sort | xargs grep -l "_(\"\|n_(\"" @@ -48,10 +52,6 @@ endef #The xgettext utility is used to automate the creation of #portable message files (.po) pot: - if [ ! -f ../gui/wxpython/menustrings.py ] ; then \ - echo "Build GRASS before running 'make pot'" >&2 ; \ - exit 1 ; \ - fi @rm -f ./templates/*.pot @echo "Generating $(LIBDOMAIN)..." xgettext $(XGETTEXT_ARGS) --from-code=utf-8 --keyword=_ --keyword=n_:1,2 -cGTC -o ./templates/$(LIBDOMAIN).pot `$(LIB_POTFILES)` @@ -60,6 +60,7 @@ pot: xgettext $(XGETTEXT_ARGS) --from-code=utf-8 -j --keyword=_ --keyword=n_:1,2 -cGTC -o ./templates/$(MODDOMAIN).pot `$(MOD_PYFILES)` @echo "Generating $(WXPYDOMAIN)..." xgettext $(XGETTEXT_ARGS) --from-code=utf-8 --keyword=_ --keyword=n_:1,2 -cGTC -o ./templates/$(WXPYDOMAIN).pot `$(WXPY_POTFILES)` + GETTEXTDATADIRS="$(CURDIR)" xgettext $(XGETTEXT_ARGS) --from-code=utf-8 -j -o ./templates/$(WXPYDOMAIN).pot $(WXPY_XMLFILES) #merge already existing translations with new messages in POT template file, deduplicate it and create new po files: update-po: diff --git a/locale/its/grass-wxgui.its b/locale/its/grass-wxgui.its new file mode 100644 index 00000000000..8b30b1350ca --- /dev/null +++ b/locale/its/grass-wxgui.its @@ -0,0 +1,38 @@ + + + + + + + + type=menu-title (name of a menu or submenu) + + + + + + + + diff --git a/locale/its/grass-wxgui.loc b/locale/its/grass-wxgui.loc new file mode 100644 index 00000000000..5fca1eee4c9 --- /dev/null +++ b/locale/its/grass-wxgui.loc @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/pyproject.toml b/pyproject.toml index c9b8a7bb24a..55752680c30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -581,7 +581,6 @@ ignore = ["CVS", ".git", ".ruff_cache", ".pytest_cache"] ignore-paths = [ "bin[.].*", "dist[.].*", - "gui/wxpython/menustrings.py", "python/grass/temporal/ply", # External code "python/libgrass_interface_generator", ]