Prevent combined translations in strings.json (#91334)
This commit is contained in:
parent
42b0602190
commit
d26160a509
1 changed files with 49 additions and 31 deletions
|
@ -22,6 +22,7 @@ REMOVED = 2
|
|||
|
||||
RE_REFERENCE = r"\[\%key:(.+)\%\]"
|
||||
RE_TRANSLATION_KEY = re.compile(r"^(?!.+[_-]{2})(?![_-])[a-z0-9-_]+(?<![_-])$")
|
||||
RE_COMBINED_REFERENCE = re.compile(r"(.+\[%)|(%\].+)")
|
||||
|
||||
# Only allow translation of integration names if they contain non-brand names
|
||||
ALLOW_NAME_TRANSLATION = {
|
||||
|
@ -116,6 +117,18 @@ def translation_key_validator(value: str) -> str:
|
|||
return value
|
||||
|
||||
|
||||
def translation_value_validator(value: Any) -> str:
|
||||
"""Validate that the value is a valid translation.
|
||||
|
||||
- prevents string with HTML
|
||||
- prevents combined translations
|
||||
"""
|
||||
value = cv.string_with_no_html(value)
|
||||
if RE_COMBINED_REFERENCE.search(value):
|
||||
raise vol.Invalid("the string should not contain combined translations")
|
||||
return str(value)
|
||||
|
||||
|
||||
def gen_data_entry_schema(
|
||||
*,
|
||||
config: Config,
|
||||
|
@ -127,24 +140,24 @@ def gen_data_entry_schema(
|
|||
"""Generate a data entry schema."""
|
||||
step_title_class = vol.Required if require_step_title else vol.Optional
|
||||
schema = {
|
||||
vol.Optional("flow_title"): cv.string_with_no_html,
|
||||
vol.Optional("flow_title"): translation_value_validator,
|
||||
vol.Required("step"): {
|
||||
str: {
|
||||
step_title_class("title"): cv.string_with_no_html,
|
||||
vol.Optional("description"): cv.string_with_no_html,
|
||||
vol.Optional("data"): {str: cv.string_with_no_html},
|
||||
vol.Optional("data_description"): {str: cv.string_with_no_html},
|
||||
vol.Optional("menu_options"): {str: cv.string_with_no_html},
|
||||
vol.Optional("submit"): cv.string_with_no_html,
|
||||
step_title_class("title"): translation_value_validator,
|
||||
vol.Optional("description"): translation_value_validator,
|
||||
vol.Optional("data"): {str: translation_value_validator},
|
||||
vol.Optional("data_description"): {str: translation_value_validator},
|
||||
vol.Optional("menu_options"): {str: translation_value_validator},
|
||||
vol.Optional("submit"): translation_value_validator,
|
||||
}
|
||||
},
|
||||
vol.Optional("error"): {str: cv.string_with_no_html},
|
||||
vol.Optional("abort"): {str: cv.string_with_no_html},
|
||||
vol.Optional("progress"): {str: cv.string_with_no_html},
|
||||
vol.Optional("create_entry"): {str: cv.string_with_no_html},
|
||||
vol.Optional("error"): {str: translation_value_validator},
|
||||
vol.Optional("abort"): {str: translation_value_validator},
|
||||
vol.Optional("progress"): {str: translation_value_validator},
|
||||
vol.Optional("create_entry"): {str: translation_value_validator},
|
||||
}
|
||||
if flow_title == REQUIRED:
|
||||
schema[vol.Required("title")] = cv.string_with_no_html
|
||||
schema[vol.Required("title")] = translation_value_validator
|
||||
elif flow_title == REMOVED:
|
||||
schema[vol.Optional("title", msg=REMOVED_TITLE_MSG)] = partial(
|
||||
removed_title_validator, config, integration
|
||||
|
@ -201,7 +214,7 @@ def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema:
|
|||
"""Generate a strings schema."""
|
||||
return vol.Schema(
|
||||
{
|
||||
vol.Optional("title"): cv.string_with_no_html,
|
||||
vol.Optional("title"): translation_value_validator,
|
||||
vol.Optional("config"): gen_data_entry_schema(
|
||||
config=config,
|
||||
integration=integration,
|
||||
|
@ -220,40 +233,43 @@ def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema:
|
|||
vol.Optional("selector"): cv.schema_with_slug_keys(
|
||||
{
|
||||
"options": cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html, slug_validator=translation_key_validator
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
)
|
||||
},
|
||||
slug_validator=vol.Any("_", cv.slug),
|
||||
),
|
||||
vol.Optional("device_automation"): {
|
||||
vol.Optional("action_type"): {str: cv.string_with_no_html},
|
||||
vol.Optional("condition_type"): {str: cv.string_with_no_html},
|
||||
vol.Optional("trigger_type"): {str: cv.string_with_no_html},
|
||||
vol.Optional("trigger_subtype"): {str: cv.string_with_no_html},
|
||||
vol.Optional("action_type"): {str: translation_value_validator},
|
||||
vol.Optional("condition_type"): {str: translation_value_validator},
|
||||
vol.Optional("trigger_type"): {str: translation_value_validator},
|
||||
vol.Optional("trigger_subtype"): {str: translation_value_validator},
|
||||
},
|
||||
vol.Optional("system_health"): {
|
||||
vol.Optional("info"): cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html, slug_validator=translation_key_validator
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
),
|
||||
},
|
||||
vol.Optional("config_panel"): cv.schema_with_slug_keys(
|
||||
cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html, slug_validator=translation_key_validator
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
),
|
||||
slug_validator=vol.Any("_", cv.slug),
|
||||
),
|
||||
vol.Optional("application_credentials"): {
|
||||
vol.Optional("description"): cv.string_with_no_html,
|
||||
vol.Optional("description"): translation_value_validator,
|
||||
},
|
||||
vol.Optional("issues"): {
|
||||
str: vol.All(
|
||||
cv.has_at_least_one_key("description", "fix_flow"),
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Required("title"): cv.string_with_no_html,
|
||||
vol.Required("title"): translation_value_validator,
|
||||
vol.Exclusive(
|
||||
"description", "fixable"
|
||||
): cv.string_with_no_html,
|
||||
): translation_value_validator,
|
||||
vol.Exclusive("fix_flow", "fixable"): gen_data_entry_schema(
|
||||
config=config,
|
||||
integration=integration,
|
||||
|
@ -268,14 +284,14 @@ def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema:
|
|||
{
|
||||
vol.Optional("name"): str,
|
||||
vol.Optional("state"): cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html,
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
),
|
||||
vol.Optional("state_attributes"): cv.schema_with_slug_keys(
|
||||
{
|
||||
vol.Optional("name"): str,
|
||||
vol.Optional("state"): cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html,
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
),
|
||||
},
|
||||
|
@ -287,16 +303,16 @@ def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema:
|
|||
vol.Optional("entity"): cv.schema_with_slug_keys(
|
||||
cv.schema_with_slug_keys(
|
||||
{
|
||||
vol.Optional("name"): cv.string_with_no_html,
|
||||
vol.Optional("name"): translation_value_validator,
|
||||
vol.Optional("state"): cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html,
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
),
|
||||
vol.Optional("state_attributes"): cv.schema_with_slug_keys(
|
||||
{
|
||||
vol.Optional("name"): cv.string_with_no_html,
|
||||
vol.Optional("name"): translation_value_validator,
|
||||
vol.Optional("state"): cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html,
|
||||
translation_value_validator,
|
||||
slug_validator=translation_key_validator,
|
||||
),
|
||||
},
|
||||
|
@ -386,7 +402,9 @@ def gen_platform_strings_schema(config: Config, integration: Integration) -> vol
|
|||
)
|
||||
|
||||
|
||||
ONBOARDING_SCHEMA = vol.Schema({vol.Required("area"): {str: cv.string_with_no_html}})
|
||||
ONBOARDING_SCHEMA = vol.Schema(
|
||||
{vol.Required("area"): {str: translation_value_validator}}
|
||||
)
|
||||
|
||||
|
||||
def validate_translation_file( # noqa: C901
|
||||
|
@ -415,7 +433,7 @@ def validate_translation_file( # noqa: C901
|
|||
strings_schema = gen_strings_schema(config, integration).extend(
|
||||
{
|
||||
vol.Optional("device_class"): cv.schema_with_slug_keys(
|
||||
cv.string_with_no_html, slug_validator=vol.Any("_", cv.slug)
|
||||
translation_value_validator, slug_validator=vol.Any("_", cv.slug)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue