Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
!flake.lock
*.pyc
OBJ.*
locale/scriptstrings/*
*.o
*.tmp.html
*.tmp.md
Expand Down
8 changes: 2 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,7 @@ cleandistdirs:
-rm -rf $(ARCH_DISTDIR)
-rm -rf $(ARCH_BINDIR)

# Clean out the strings extracted from scripts for translation
cleanscriptstrings:
rm -f locale/scriptstrings/*.c 2>/dev/null

clean: cleandistdirs cleanscriptstrings cleandocs code-coverage-clean
clean: cleandistdirs cleandocs code-coverage-clean

libsclean: cleandistdirs
$(MAKE) clean-recursive SUBDIRS=$(LIBDIRS)
Expand All @@ -134,4 +130,4 @@ include $(MODULE_TOPDIR)/include/Make/Sphinx.make
DOXNAME=grass

.PHONY: default libs
.PHONY: cleandistdirs cleanscriptstrings clean libsclean distclean
.PHONY: cleandistdirs clean libsclean distclean
82 changes: 0 additions & 82 deletions cmake/locale_strings.cmake

This file was deleted.

31 changes: 11 additions & 20 deletions cmake/modules/build_script_in_subdir.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,14 @@ function(build_script_in_subdir dir_name)
WORLD_EXECUTE
)

set(TRANSLATE_C_FILE
${CMAKE_SOURCE_DIR}/locale/scriptstrings/${G_NAME}_to_translate.c
)

add_custom_command(
OUTPUT ${TRANSLATE_C_FILE}
COMMAND
${CMAKE_COMMAND} -DG_NAME=${G_NAME} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-DOUTPUT_FILE=${TRANSLATE_C_FILE} -DGISBASE_DIR="${RUNTIME_GISBASE}"
-DBINARY_DIR="${OUTDIR}/${GRASS_INSTALL_BINDIR}"
-DLIBDIR="${OUTDIR}/${GRASS_INSTALL_LIBDIR}"
-DSCRIPTDIR="${OUTDIR}/${G_DEST_DIR}"
-DETCDIR="${OUTDIR}/${GRASS_INSTALL_ETCDIR}"
-DPYDIR="${OUTDIR}/${GRASS_INSTALL_PYDIR}" -DGISRC="${GISRC}"
-DGUIDIR="${OUTDIR}/${GRASS_INSTALL_GUIDIR}" -P
${CMAKE_SOURCE_DIR}/cmake/locale_strings.cmake
DEPENDS g.parser
)
if(WIN32)
set(PGM_NAME ${G_NAME})
configure_file(
${CMAKE_SOURCE_DIR}/cmake/windows_launch.bat.in
${OUTDIR}/${G_DEST_DIR}/${G_NAME}.bat
@ONLY
)
endif()

set(OUT_HTML_FILE "")

Expand All @@ -96,11 +86,12 @@ function(build_script_in_subdir dir_name)
OUTPUT ${OUT_HTML_FILE}
SOURCEDIR ${G_SRC_DIR}
DEST_DIR ${G_DEST_DIR}
DEPENDS ${TRANSLATE_C_FILE} LIB_PYTHON
DEPENDS LIB_PYTHON g.parser
)
endif() # WITH_DOCS

add_custom_target(${G_NAME} DEPENDS ${TRANSLATE_C_FILE} ${OUT_HTML_FILE})
add_custom_target(${G_NAME} DEPENDS ${OUT_HTML_FILE})
add_dependencies(${G_NAME} g.parser)

set(modules_list
"${G_NAME};${modules_list}"
Expand Down
12 changes: 10 additions & 2 deletions general/g.parser/g.parser.html
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,16 @@ <h2>TRANSLATION</h2>
</pre></div>

<em>g.parser</em> will print the text of the translatable options to
standard output, one per line, and exit. This is for internal use within
the build system to prepare GRASS scripts for translation.
standard output, one per line, and exit.
<p>
The translatable fields are the <b>label</b>, <b>description</b>, and
<b>keyword</b> of the module, the <b>label</b>, <b>description</b>, and
<b>guisection</b> of flags and options, and the descriptions in the
<b>descriptions</b> of options. Each description of an option value is
translated separately with the message context
<code>option value description</code>, so the values themselves are never
translated. The strings are extracted for translation from the source files
by <code>utils/grass_tool_header_pot.py</code> in the GRASS source code.

<h2>EXAMPLES</h2>

Expand Down
12 changes: 10 additions & 2 deletions general/g.parser/g.parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,16 @@ g.parser -t somescriptfile
```

*g.parser* will print the text of the translatable options to standard
output, one per line, and exit. This is for internal use within the
build system to prepare GRASS scripts for translation.
output, one per line, and exit.

The translatable fields are the **label**, **description**, and
**keyword** of the module, the **label**, **description**, and
**guisection** of flags and options, and the descriptions in the
**descriptions** of options. Each description of an option value is
translated separately with the message context `option value description`,
so the values themselves are never translated. The strings are extracted
for translation from the source files by `utils/grass_tool_header_pot.py`
in the GRASS source code.

## EXAMPLES

Expand Down
4 changes: 2 additions & 2 deletions general/g.parser/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void parse_option(struct context *ctx, const char *cmd, const char *arg)
}

if (G_strcasecmp(cmd, "descriptions") == 0) {
ctx->option->descriptions = translate(xstrdup(arg));
ctx->option->descriptions = translate_descriptions(xstrdup(arg));
return;
}

Expand All @@ -222,7 +222,7 @@ void parse_option(struct context *ctx, const char *cmd, const char *arg)
}

if (G_strcasecmp(cmd, "guidependency") == 0) {
ctx->option->guidependency = translate(xstrdup(arg));
ctx->option->guidependency = xstrdup(arg);
return;
}

Expand Down
1 change: 1 addition & 0 deletions general/g.parser/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct Option *define_standard_option(const char *);

/* translate.c */
char *translate(const char *);
char *translate_descriptions(const char *);

/* rules.c */
void parse_rule(struct context *, const char *, const char *);
93 changes: 93 additions & 0 deletions general/g.parser/tests/g_parser_descriptions_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Tests of option value descriptions and GUI dependencies in g.parser

g.parser translates each value description separately (see translate.c),
so without a translation, the interface must be the same as written.
The header is the same in Python and shell scripts.
"""

import os
import shutil
import subprocess
import sys
import xml.etree.ElementTree as ET

import pytest

import grass.script as gs

HEADER = """\
# %module
# % description: Test of option value descriptions
# %end
# %option
# % key: format
# % type: string
# % options: plain,json,shell
# % descriptions: plain;Plain text output; json ; JSON output ;shell;Shell style;
# % guidependency: input,maps
# % answer: plain
# %end
"""

PYTHON_SCRIPT = f"""\
#!/usr/bin/env python3
{HEADER}
import grass.script as gs
gs.parser()
"""

SHELL_SCRIPT = f"""\
#!/bin/sh
{HEADER}
if [ "$1" != "@ARGS_PARSED@" ] ; then
exec g.parser "$0" "$@"
fi
"""


@pytest.fixture(scope="module")
def session(tmp_path_factory):
"""Set up a GRASS session for the tests."""
tmp_path = tmp_path_factory.mktemp("grass_session")
project = "test_project"
gs.create_project(tmp_path, project)
with gs.setup.init(tmp_path / project, env=os.environ.copy()) as session:
yield session


@pytest.fixture(scope="module", params=["python", "shell"])
def parameter(request, session, tmp_path_factory):
"""Return the parameter element from the interface description."""
if request.param == "python":
name, text, interpreter = "t_example.py", PYTHON_SCRIPT, sys.executable
else:
name, text, interpreter = "t_example.sh", SHELL_SCRIPT, shutil.which("sh")
if not interpreter:
pytest.skip("sh not available")
script = tmp_path_factory.mktemp("script") / name
script.write_text(text, encoding="utf-8")
result = subprocess.run(
[interpreter, script, "--interface-description"],
capture_output=True,
check=True,
env=session.env,
)
return ET.fromstring(result.stdout).find("parameter")


def test_value_descriptions(parameter):
"""Values are matched with their descriptions which are kept as written."""
values = {
value.findtext("name").strip(): value.findtext("description")
for value in parameter.iter("value")
}
assert values == {
"plain": "Plain text output",
"json": " JSON output ",
"shell": "Shell style",
}


def test_guidependency(parameter):
"""GUI dependency is a list of option keys, kept as written."""
assert parameter.findtext("guidependency").strip() == "input,maps"
Loading
Loading