diff --git a/script/hassfest/translations.py b/script/hassfest/translations.py index 55d2fa21934..5e55b9a1ca8 100644 --- a/script/hassfest/translations.py +++ b/script/hassfest/translations.py @@ -132,7 +132,9 @@ def translation_key_validator(value: str) -> str: return value -def validate_translation_value(value: Any, allow_placeholders=True) -> str: +def validate_translation_value( + value: Any, allow_placeholders: bool = True, allow_urls: bool = False +) -> str: """Validate that the value is a valid translation. - prevents string with HTML @@ -148,7 +150,7 @@ def validate_translation_value(value: Any, allow_placeholders=True) -> str: raise vol.Invalid("the string should not contain combined translations") if string_value != string_value.strip(): raise vol.Invalid("the string should not contain leading or trailing spaces") - if RE_URL.search(string_value): + if not allow_urls and RE_URL.search(string_value): raise vol.Invalid( "the string should not contain URLs, " "please use description placeholders instead" @@ -161,11 +163,13 @@ def translation_value_validator(value: Any) -> str: return validate_translation_value(value) -def custom_translation_value_validator(allow_placeholders=True): +def custom_translation_value_validator( + allow_placeholders: bool = True, allow_urls: bool = False +): """Validate translation value with custom options.""" def _validator(value: Any) -> str: - return validate_translation_value(value, allow_placeholders) + return validate_translation_value(value, allow_placeholders, allow_urls) return _validator @@ -363,7 +367,10 @@ def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema: vol.Optional("preview_features"): cv.schema_with_slug_keys( { vol.Required("name"): translation_value_validator, - vol.Required("description"): translation_value_validator, + vol.Required("description"): custom_translation_value_validator( + allow_placeholders=False, + allow_urls=True, + ), vol.Optional("enable_confirmation"): translation_value_validator, vol.Optional("disable_confirmation"): translation_value_validator, }, diff --git a/tests/hassfest/test_translations.py b/tests/hassfest/test_translations.py index 87a38a1352d..fdd903ab806 100644 --- a/tests/hassfest/test_translations.py +++ b/tests/hassfest/test_translations.py @@ -134,7 +134,7 @@ SAMPLE_STRINGS = { "preview_features": { "new_feature": { "name": "New feature", - "description": "This is a new experimental feature", + "description": "This is a new experimental feature, see https://example.com", "enable_confirmation": "Are you sure you want to enable this feature?", "disable_confirmation": "Are you sure you want to disable this feature?", }, @@ -429,3 +429,23 @@ def test_no_placeholders_used_for_urls(translation_string: str) -> None: with pytest.raises(vol.Invalid): schema(translation_string) + + +@pytest.mark.parametrize( + "translation_string", + [ + "An example is: https://example.com.", + "www.example.com", + "http://example.com:8080", + "WWW.EXAMPLE.COM", + "HTTPS://www.example.com", + ], +) +def test_allow_urls_in_translation_value(translation_string: str) -> None: + """Test that URLs are allowed when allow_urls=True.""" + schema = vol.Schema( + translations.custom_translation_value_validator(allow_urls=True) + ) + + # Should not raise + schema(translation_string)