diff --git a/strix/interface/cli_args.py b/strix/interface/cli_args.py index a4f2cca77..4fc10b418 100644 --- a/strix/interface/cli_args.py +++ b/strix/interface/cli_args.py @@ -32,6 +32,12 @@ _ARGPARSE_MESSAGE_KEYS: dict[str, str] = { "%(prog)s: error: %(message)s\n": "cli.argparse_error", "unrecognized arguments: %s": "cli.argparse_unrecognized", "the following arguments are required: %s": "cli.argparse_required", + "invalid choice: %(value)r (choose from %(choices)s)": "cli.argparse_invalid_choice", + "argument %(argument_name)s: %(message)s": "cli.argparse_argument_error", + "expected one argument": "cli.argparse_expected_one", + "expected at most one argument": "cli.argparse_expected_at_most", + "expected at least one argument": "cli.argparse_expected_at_least", + "unexpected option string: %s": "cli.argparse_unexpected_option", } @@ -89,11 +95,11 @@ def _positive_budget(value: str) -> float: try: budget = float(value) except ValueError as exc: - raise argparse.ArgumentTypeError(f"invalid float value: {value!r}") from exc + raise argparse.ArgumentTypeError(t("cli.invalid_float", value=value)) from exc import math if not math.isfinite(budget) or budget <= 0: - raise argparse.ArgumentTypeError("must be a finite number greater than 0") + raise argparse.ArgumentTypeError(t("cli.finite_number")) return budget @@ -101,9 +107,9 @@ def _positive_int(value: str) -> int: try: parsed = int(value) except ValueError as exc: - raise argparse.ArgumentTypeError(f"invalid int value: {value!r}") from exc + raise argparse.ArgumentTypeError(t("cli.invalid_int", value=value)) from exc if parsed <= 0: - raise argparse.ArgumentTypeError("must be an integer greater than 0") + raise argparse.ArgumentTypeError(t("cli.positive_integer")) return parsed @@ -114,6 +120,7 @@ def parse_arguments() -> argparse.Namespace: parser = argparse.ArgumentParser( description=t("cli.description"), formatter_class=argparse.RawDescriptionHelpFormatter, + allow_abbrev=False, epilog=f""" {t("cli.examples_header")} # {t("cli.example_web_app")} diff --git a/strix/locales/en.json b/strix/locales/en.json index dde20b01f..1452d0571 100644 --- a/strix/locales/en.json +++ b/strix/locales/en.json @@ -22,6 +22,16 @@ "cli.argparse_error": "%(prog)s: error: %(message)s\n", "cli.argparse_unrecognized": "unrecognized arguments: %s", "cli.argparse_required": "the following arguments are required: %s", + "cli.argparse_invalid_choice": "invalid choice: %(value)r (choose from %(choices)s)", + "cli.argparse_argument_error": "argument %(argument_name)s: %(message)s", + "cli.argparse_expected_one": "expected one argument", + "cli.argparse_expected_at_most": "expected at most one argument", + "cli.argparse_expected_at_least": "expected at least one argument", + "cli.argparse_unexpected_option": "unexpected option string: %s", + "cli.invalid_float": "invalid float value: {value!r}", + "cli.finite_number": "must be a finite number greater than 0", + "cli.invalid_int": "invalid int value: {value!r}", + "cli.positive_integer": "must be an integer greater than 0", "cli.example_web_app": "Web application penetration test", "cli.example_github": "GitHub repository analysis", "cli.example_local_code": "Local code analysis", diff --git a/strix/locales/es.json b/strix/locales/es.json index 1f50a42ab..7fea64ad4 100644 --- a/strix/locales/es.json +++ b/strix/locales/es.json @@ -22,6 +22,16 @@ "cli.argparse_error": "%(prog)s: error: %(message)s\n", "cli.argparse_unrecognized": "argumentos no reconocidos: %s", "cli.argparse_required": "se requieren los siguientes argumentos: %s", + "cli.argparse_invalid_choice": "opción inválida: %(value)r (elija entre %(choices)s)", + "cli.argparse_argument_error": "argumento %(argument_name)s: %(message)s", + "cli.argparse_expected_one": "se espera un argumento", + "cli.argparse_expected_at_most": "se espera como máximo un argumento", + "cli.argparse_expected_at_least": "se espera al menos un argumento", + "cli.argparse_unexpected_option": "opción inesperada: %s", + "cli.invalid_float": "valor float inválido: {value!r}", + "cli.finite_number": "debe ser un número finito mayor que 0", + "cli.invalid_int": "valor entero inválido: {value!r}", + "cli.positive_integer": "debe ser un entero mayor que 0", "cli.example_web_app": "Prueba de penetración de aplicación web", "cli.example_github": "Análisis de repositorio de GitHub", "cli.example_local_code": "Análisis de código local", diff --git a/tests/test_i18n.py b/tests/test_i18n.py index 41331d71b..d47903c2e 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -346,6 +346,32 @@ class TestArgparseBuiltins: assert cli_args._translate_argparse("unknown string") == "unknown string" assert argparse._("usage: ") == "uso: " + def test_invalid_choice_translates(self): + set_language("es") + assert "inválida" in t("cli.argparse_invalid_choice") + assert "elija entre" in t("cli.argparse_invalid_choice") + + def test_argument_error_translates(self): + set_language("es") + assert t("cli.argparse_argument_error") == "argumento %(argument_name)s: %(message)s" + + def test_expected_arguments_translate(self): + set_language("es") + assert t("cli.argparse_expected_one") == "se espera un argumento" + assert "como máximo" in t("cli.argparse_expected_at_most") + assert "al menos" in t("cli.argparse_expected_at_least") + + def test_unexpected_option_translates(self): + set_language("es") + assert t("cli.argparse_unexpected_option") == "opción inesperada: %s" + + def test_validation_errors_translate(self): + set_language("es") + assert t("cli.invalid_float", value="abc") == "valor float inválido: 'abc'" + assert t("cli.invalid_int", value="abc") == "valor entero inválido: 'abc'" + assert t("cli.finite_number") == "debe ser un número finito mayor que 0" + assert t("cli.positive_integer") == "debe ser un entero mayor que 0" + class TestSettingsLanguageField: def test_settings_has_language_field(self):