From cdc703a48f96505fb30ed50a4c05502cabd6b203 Mon Sep 17 00:00:00 2001 From: axolotle Date: Fri, 1 Dec 2023 18:25:22 +0100 Subject: [PATCH] form: add pydantic errors translations --- locales/en.json | 15 +++++++++++++++ src/utils/form.py | 35 +++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/locales/en.json b/locales/en.json index 1932e0dae..9e069aad7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -683,6 +683,21 @@ "port_already_closed": "Port {port} is already closed for {ip_version} connections", "port_already_opened": "Port {port} is already opened for {ip_version} connections", "postinstall_low_rootfsspace": "The root filesystem has a total space less than 10 GB, which is quite worrisome! You will likely run out of disk space very quickly! It's recommended to have at least 16GB for the root filesystem. If you want to install YunoHost despite this warning, re-run the postinstall with --force-diskspace", + "pydantic.type_error": "Invalid type.", + "pydantic.type_error.none.not_allowed": "Value is required.", + "pydantic.type_error.str": "Invalid type, string expected.", + "pydantic.value_error.color": "Not a valid color, value must be a named or hex color.", + "pydantic.value_error.const": "Unexpected value; choose between {permitted}", + "pydantic.value_error.date": "Invalid date format", + "pydantic.value_error.email": "Value is not a valid email address", + "pydantic.value_error.number.not_ge": "Value must be greater than or equal to {limit_value}.", + "pydantic.value_error.number.not_le": "Value must be less than or equal to {limit_value}.", + "pydantic.value_error.str.regex": "Invalid string; value doesn't respects the pattern '{pattern}'", + "pydantic.value_error.time": "Invalid time format", + "pydantic.value_error.url.extra": "URL invalid, extra characters found after valid URL: '{extra}'", + "pydantic.value_error.url.host": "URL host invalid", + "pydantic.value_error.url.port": "URL port invalid, port cannot exceed 65535", + "pydantic.value_error.url.scheme": "Invalid or missing URL scheme", "regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for category '{category}'...", "regenconf_failed": "Could not regenerate the configuration for category(s): {categories}", "regenconf_file_backed_up": "Configuration file '{conf}' backed up to '{backup}'", diff --git a/src/utils/form.py b/src/utils/form.py index a7e7f781e..8289f112a 100644 --- a/src/utils/form.py +++ b/src/utils/form.py @@ -302,7 +302,7 @@ Mode = Literal["python", "bash"] class Pattern(BaseModel): regexp: str - error: Translation = "error_pattern" # FIXME add generic i18n key + error: Translation = "pydantic.value_error.str.regex" # FIXME add generic i18n key class BaseOption(BaseModel): @@ -2083,19 +2083,38 @@ def prompt_or_validate_form( form[option.id] = option.normalize(value, option) context[option.id] = form[option.id] except (ValidationError, YunohostValidationError) as e: + if isinstance(e, ValidationError): + # TODO: handle multiple errors + err = e.errors()[0] + ctx = err.get("ctx", {}) + + if "permitted" in ctx: + ctx["permitted"] = ", ".join( + f"'{choice}'" for choice in ctx["permitted"] + ) + if ( + isinstance(option, (BaseStringOption, TagsOption)) + and "regex" in err["type"] + ): + err_text = option.pattern.error + else: + err_text = m18n.n(f"pydantic.{err['type']}", **ctx) + else: + err_text = str(e) + # If in interactive cli, re-ask the current question if i < MAX_RETRIES and interactive: - logger.error( - "\n".join([err["msg"] for err in e.errors()]) - if isinstance(e, ValidationError) - else str(e) - ) + logger.error(err_text) value = None continue if isinstance(e, ValidationError): - error = "\n".join([err["msg"] for err in e.errors()]) - raise YunohostValidationError(error, raw_msg=True) + if not interactive: + err_text = m18n.n( + "app_argument_invalid", name=option.id, error=err_text + ) + + raise YunohostValidationError(err_text, raw_msg=True) # Otherwise raise the ValidationError raise e