diff --git a/homeassistant/helpers/translation.py b/homeassistant/helpers/translation.py index acc4f146e8bc57a71dbcb057207eff69995dabeb..1fc2c3d075bf1014e70d75b1583efe7f7ea8f022 100644 --- a/homeassistant/helpers/translation.py +++ b/homeassistant/helpers/translation.py @@ -6,6 +6,7 @@ import asyncio from collections.abc import Iterable, Mapping from contextlib import suppress import logging +import pathlib import string from typing import Any @@ -41,40 +42,18 @@ def recursive_flatten(prefix: Any, data: dict[str, Any]) -> dict[str, Any]: @callback -def component_translation_path( - component: str, language: str, integration: Integration -) -> str | None: +def component_translation_path(language: str, integration: Integration) -> pathlib.Path: """Return the translation json file location for a component. For component: - components/hue/translations/nl.json - For platform: - - components/hue/translations/light.nl.json - - If component is just a single file, will return None. """ - parts = component.split(".") - domain = parts[0] - is_platform = len(parts) == 2 - - # If it's a component that is just one file, we don't support translations - # Example custom_components/my_component.py - if integration.file_path.name != domain: - return None - - if is_platform: - filename = f"{parts[1]}.{language}.json" - else: - filename = f"{language}.json" - - translation_path = integration.file_path / "translations" - - return str(translation_path / filename) + return integration.file_path / "translations" / f"{language}.json" def _load_translations_files_by_language( - translation_files: dict[str, dict[str, str]], + translation_files: dict[str, dict[str, pathlib.Path]], ) -> dict[str, dict[str, Any]]: """Load and parse translation.json files.""" loaded: dict[str, dict[str, Any]] = {} @@ -98,47 +77,6 @@ def _load_translations_files_by_language( return loaded -def _merge_resources( - translation_strings: dict[str, dict[str, Any]], - components: set[str], - category: str, -) -> dict[str, dict[str, Any]]: - """Build and merge the resources response for the given components and platforms.""" - # Build response - resources: dict[str, dict[str, Any]] = {} - for component in components: - domain = component.rpartition(".")[-1] - - domain_resources = resources.setdefault(domain, {}) - - # Integrations are able to provide translations for their entities under other - # integrations if they don't have an existing device class. This is done by - # using a custom device class prefixed with their domain and two underscores. - # These files are in platform specific files in the integration folder with - # names like `strings.sensor.json`. - # We are going to merge the translations for the custom device classes into - # the translations of sensor. - - new_value = translation_strings.get(component, {}).get(category) - - if new_value is None: - continue - - if isinstance(new_value, dict): - domain_resources.update(new_value) - else: - _LOGGER.error( - ( - "An integration providing translations for %s provided invalid" - " data: %s" - ), - domain, - new_value, - ) - - return resources - - def build_resources( translation_strings: dict[str, dict[str, dict[str, Any] | str]], components: set[str], @@ -163,32 +101,20 @@ async def _async_get_component_strings( """Load translations.""" translations_by_language: dict[str, dict[str, Any]] = {} # Determine paths of missing components/platforms - files_to_load_by_language: dict[str, dict[str, str]] = {} + files_to_load_by_language: dict[str, dict[str, pathlib.Path]] = {} loaded_translations_by_language: dict[str, dict[str, Any]] = {} has_files_to_load = False for language in languages: - files_to_load: dict[str, str] = {} - files_to_load_by_language[language] = files_to_load - translations_by_language[language] = {} - - for comp in components: - domain, _, platform = comp.partition(".") + files_to_load: dict[str, pathlib.Path] = { + domain: component_translation_path(language, integration) + for domain in components if ( - not (integration := integrations.get(domain)) - or not integration.has_translations - ): - continue - - if platform and integration.is_built_in: - # Legacy state translations are no longer used for built-in integrations - # and we avoid trying to load them. This is a temporary measure to allow - # them to keep working for custom integrations until we can fully remove - # them. - continue - - if path := component_translation_path(comp, language, integration): - files_to_load[comp] = path - has_files_to_load = True + (integration := integrations.get(domain)) + and integration.has_translations + ) + } + files_to_load_by_language[language] = files_to_load + has_files_to_load |= bool(files_to_load) if has_files_to_load: loaded_translations_by_language = await hass.async_add_executor_job( @@ -197,18 +123,15 @@ async def _async_get_component_strings( for language in languages: loaded_translations = loaded_translations_by_language.setdefault(language, {}) - for comp in components: - if "." in comp: - continue - + for domain in components: # Translations that miss "title" will get integration put in. - component_translations = loaded_translations.setdefault(comp, {}) + component_translations = loaded_translations.setdefault(domain, {}) if "title" not in component_translations and ( - integration := integrations.get(comp) + integration := integrations.get(domain) ): component_translations["title"] = integration.name - translations_by_language[language].update(loaded_translations) + translations_by_language.setdefault(language, {}).update(loaded_translations) return translations_by_language @@ -355,10 +278,12 @@ class _TranslationCache: _LOGGER.error( ( "Validation of translation placeholders for localized (%s) string " - "%s failed" + "%s failed: (%s != %s)" ), language, key, + updated_placeholders, + cached_placeholders, ) mismatches.add(key) @@ -382,17 +307,7 @@ class _TranslationCache: categories.update(resource) for category in categories: - new_resources: Mapping[str, dict[str, Any] | str] - - if category in ("state", "entity_component"): - new_resources = _merge_resources( - translation_strings, components, category - ) - else: - new_resources = build_resources( - translation_strings, components, category - ) - + new_resources = build_resources(translation_strings, components, category) category_cache = cached.setdefault(category, {}) for component, resource in new_resources.items(): @@ -430,7 +345,7 @@ async def async_get_translations( elif integrations is not None: components = set(integrations) else: - components = _async_get_components(hass, category) + components = {comp for comp in hass.config.components if "." not in comp} return await _async_get_translations_cache(hass).async_fetch( language, category, components @@ -452,7 +367,7 @@ def async_get_cached_translations( if integration is not None: components = {integration} else: - components = _async_get_components(hass, category) + components = {comp for comp in hass.config.components if "." not in comp} return _async_get_translations_cache(hass).get_cached( language, category, components @@ -466,21 +381,6 @@ def _async_get_translations_cache(hass: HomeAssistant) -> _TranslationCache: return cache -_DIRECT_MAPPED_CATEGORIES = {"state", "entity_component", "services"} - - -@callback -def _async_get_components( - hass: HomeAssistant, - category: str, -) -> set[str]: - """Return a set of components for which translations should be loaded.""" - if category in _DIRECT_MAPPED_CATEGORIES: - return hass.config.components - # Only 'state' supports merging, so remove platforms from selection - return {component for component in hass.config.components if "." not in component} - - @callback def async_setup(hass: HomeAssistant) -> None: """Create translation cache and register listeners for translation loaders. @@ -590,13 +490,4 @@ def async_translate_state( if localize_key in translations: return translations[localize_key] - translations = async_get_cached_translations(hass, language, "state", domain) - if device_class is not None: - localize_key = f"component.{domain}.state.{device_class}.{state}" - if localize_key in translations: - return translations[localize_key] - localize_key = f"component.{domain}.state._.{state}" - if localize_key in translations: - return translations[localize_key] - return state diff --git a/script/hassfest/translations.py b/script/hassfest/translations.py index b893902af69d58cd21c8532f1e4c8144fc768b91..e815a66b4bb27bd4b158719c8a34f5efe7a7340a 100644 --- a/script/hassfest/translations.py +++ b/script/hassfest/translations.py @@ -3,7 +3,6 @@ from __future__ import annotations from functools import partial -from itertools import chain import json import re from typing import Any @@ -12,7 +11,6 @@ import voluptuous as vol from voluptuous.humanize import humanize_error import homeassistant.helpers.config_validation as cv -from homeassistant.util import slugify from script.translations import upload from .model import Config, Integration @@ -414,49 +412,6 @@ def gen_ha_hardware_schema(config: Config, integration: Integration): ) -def gen_platform_strings_schema(config: Config, integration: Integration) -> vol.Schema: - """Generate platform strings schema like strings.sensor.json. - - Example of valid data: - { - "state": { - "moon__phase": { - "full": "Full" - } - } - } - """ - - def device_class_validator(value: str) -> str: - """Key validator for platform states. - - Platform states are only allowed to provide states for device classes they prefix. - """ - if not value.startswith(f"{integration.domain}__"): - raise vol.Invalid( - f"Device class need to start with '{integration.domain}__'. Key {value} is invalid. See https://developers.home-assistant.io/docs/internationalization/core#stringssensorjson" - ) - - slug_friendly = value.replace("__", "_", 1) - slugged = slugify(slug_friendly) - - if slug_friendly != slugged: - raise vol.Invalid( - f"invalid device class {value}. After domain__, needs to be all lowercase, no spaces." - ) - - return value - - return vol.Schema( - { - vol.Optional("state"): cv.schema_with_slug_keys( - cv.schema_with_slug_keys(str, slug_validator=translation_key_validator), - slug_validator=device_class_validator, - ) - } - ) - - ONBOARDING_SCHEMA = vol.Schema( { vol.Required("area"): {str: translation_value_validator}, @@ -525,32 +480,6 @@ def validate_translation_file( # noqa: C901 "name or add exception to ALLOW_NAME_TRANSLATION", ) - platform_string_schema = gen_platform_strings_schema(config, integration) - platform_strings = [integration.path.glob("strings.*.json")] - - if config.specific_integrations: - platform_strings.append(integration.path.glob("translations/*.en.json")) - - for path in chain(*platform_strings): - name = str(path.relative_to(integration.path)) - - try: - strings = json.loads(path.read_text()) - except ValueError as err: - integration.add_error("translations", f"Invalid JSON in {name}: {err}") - continue - - try: - platform_string_schema(strings) - except vol.Invalid as err: - msg = f"Invalid {path.name}: {humanize_error(strings, err)}" - if config.specific_integrations: - integration.add_warning("translations", msg) - else: - integration.add_error("translations", msg) - else: - find_references(strings, path.name, references) - if config.specific_integrations: return diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index fe152ac0d56a91e0dc0afa0ff95d95338e005ac9..524b8f47dfe7163c07169107a8de38588ec56703 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -2050,12 +2050,7 @@ async def test_state_translated( ): if category == "entity": return { - "component.hue.entity.light.translation_key.state.on": "state_is_on" - } - if category == "state": - return { - "component.some_domain.state.some_device_class.off": "state_is_off", - "component.some_domain.state._.foo": "state_is_foo", + "component.hue.entity.light.translation_key.state.on": "state_is_on", } return {} @@ -2066,16 +2061,6 @@ async def test_state_translated( tpl8 = template.Template('{{ state_translated("light.hue_5678") }}', hass) assert tpl8.async_render() == "state_is_on" - tpl9 = template.Template( - '{{ state_translated("some_domain.with_device_class_1") }}', hass - ) - assert tpl9.async_render() == "state_is_off" - - tpl10 = template.Template( - '{{ state_translated("some_domain.with_device_class_2") }}', hass - ) - assert tpl10.async_render() == "state_is_foo" - tpl11 = template.Template('{{ state_translated("domain.is_unavailable") }}', hass) assert tpl11.async_render() == "unavailable" diff --git a/tests/helpers/test_translation.py b/tests/helpers/test_translation.py index 1bba23c51a1f66bf93efa9635cdc029e1e15beed..b841e1ab5acff4e992ae25c73fba71482568f9bb 100644 --- a/tests/helpers/test_translation.py +++ b/tests/helpers/test_translation.py @@ -47,35 +47,10 @@ async def test_component_translation_path( {"switch": [{"platform": "test"}, {"platform": "test_embedded"}]}, ) assert await async_setup_component(hass, "test_package", {"test_package": None}) - - ( - int_test, - int_test_embedded, - int_test_package, - ) = await asyncio.gather( - async_get_integration(hass, "test"), - async_get_integration(hass, "test_embedded"), - async_get_integration(hass, "test_package"), - ) - - assert path.normpath( - translation.component_translation_path("test.switch", "en", int_test) - ) == path.normpath( - hass.config.path("custom_components", "test", "translations", "switch.en.json") - ) + int_test_package = await async_get_integration(hass, "test_package") assert path.normpath( - translation.component_translation_path( - "test_embedded.switch", "en", int_test_embedded - ) - ) == path.normpath( - hass.config.path( - "custom_components", "test_embedded", "translations", "switch.en.json" - ) - ) - - assert path.normpath( - translation.component_translation_path("test_package", "en", int_test_package) + translation.component_translation_path("en", int_test_package) ) == path.normpath( hass.config.path("custom_components", "test_package", "translations", "en.json") ) @@ -86,28 +61,39 @@ def test__load_translations_files_by_language( ) -> None: """Test the load translation files function.""" # Test one valid and one invalid file - file1 = hass.config.path( - "custom_components", "test", "translations", "switch.en.json" - ) - file2 = hass.config.path( + en_file = hass.config.path("custom_components", "test", "translations", "en.json") + invalid_file = hass.config.path( "custom_components", "test", "translations", "invalid.json" ) - file3 = hass.config.path( - "custom_components", "test", "translations", "_broken.en.json" + broken_file = hass.config.path( + "custom_components", "test", "translations", "_broken.json" ) assert translation._load_translations_files_by_language( - {"en": {"switch.test": file1, "invalid": file2, "broken": file3}} + { + "en": {"test": en_file}, + "invalid": {"test": invalid_file}, + "broken": {"test": broken_file}, + } ) == { + "broken": {}, "en": { - "switch.test": { - "state": {"string1": "Value 1", "string2": "Value 2"}, + "test": { + "entity": { + "switch": { + "other1": {"name": "Other 1"}, + "other2": {"name": "Other 2"}, + "other3": {"name": "Other 3"}, + "other4": {"name": "Other 4"}, + "outlet": {"name": "Outlet " "{placeholder}"}, + } + }, "something": "else", - }, - "invalid": {}, - } + } + }, + "invalid": {"test": {}}, } assert "Translation file is unexpected type" in caplog.text - assert "_broken.en.json" in caplog.text + assert "_broken.json" in caplog.text @pytest.mark.parametrize( @@ -185,33 +171,61 @@ async def test_get_translations( hass: HomeAssistant, mock_config_flows, enable_custom_integrations: None ) -> None: """Test the get translations helper.""" - translations = await translation.async_get_translations(hass, "en", "state") + translations = await translation.async_get_translations(hass, "en", "entity") assert translations == {} assert await async_setup_component(hass, "switch", {"switch": {"platform": "test"}}) await hass.async_block_till_done() - translations = await translation.async_get_translations(hass, "en", "state") + translations = await translation.async_get_translations( + hass, "en", "entity", {"test"} + ) - assert translations["component.switch.state.string1"] == "Value 1" - assert translations["component.switch.state.string2"] == "Value 2" + assert translations == { + "component.test.entity.switch.other1.name": "Other 1", + "component.test.entity.switch.other2.name": "Other 2", + "component.test.entity.switch.other3.name": "Other 3", + "component.test.entity.switch.other4.name": "Other 4", + "component.test.entity.switch.outlet.name": "Outlet {placeholder}", + } - translations = await translation.async_get_translations(hass, "de", "state") - assert "component.switch.something" not in translations - assert translations["component.switch.state.string1"] == "German Value 1" - assert translations["component.switch.state.string2"] == "German Value 2" + translations = await translation.async_get_translations( + hass, "de", "entity", {"test"} + ) + + assert translations == { + "component.test.entity.switch.other1.name": "Anderes 1", + "component.test.entity.switch.other2.name": "Other 2", + "component.test.entity.switch.other3.name": "", + "component.test.entity.switch.other4.name": "Other 4", + "component.test.entity.switch.outlet.name": "Outlet {placeholder}", + } # Test a partial translation - translations = await translation.async_get_translations(hass, "es", "state") - assert translations["component.switch.state.string1"] == "Spanish Value 1" - assert translations["component.switch.state.string2"] == "Value 2" + translations = await translation.async_get_translations( + hass, "es", "entity", {"test"} + ) + + assert translations == { + "component.test.entity.switch.other1.name": "Otra 1", + "component.test.entity.switch.other2.name": "Otra 2", + "component.test.entity.switch.other3.name": "Otra 3", + "component.test.entity.switch.other4.name": "Otra 4", + "component.test.entity.switch.outlet.name": "Enchufe {placeholder}", + } # Test that an untranslated language falls back to English. translations = await translation.async_get_translations( - hass, "invalid-language", "state" + hass, "invalid-language", "entity", {"test"} ) - assert translations["component.switch.state.string1"] == "Value 1" - assert translations["component.switch.state.string2"] == "Value 2" + + assert translations == { + "component.test.entity.switch.other1.name": "Other 1", + "component.test.entity.switch.other2.name": "Other 2", + "component.test.entity.switch.other3.name": "Other 3", + "component.test.entity.switch.other4.name": "Other 4", + "component.test.entity.switch.outlet.name": "Outlet {placeholder}", + } async def test_get_translations_loads_config_flows( @@ -348,162 +362,6 @@ async def test_get_translation_categories(hass: HomeAssistant) -> None: assert "component.light.device_automation.action_type.turn_on" in translations -async def test_legacy_platform_translations_not_used_built_in_integrations( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture -) -> None: - """Test legacy platform translations are not used for built-in integrations.""" - hass.config.components.add("moon.sensor") - hass.config.components.add("sensor") - - load_requests = [] - - def mock_load_translations_files_by_language(files): - load_requests.append(files) - return {} - - with patch( - "homeassistant.helpers.translation._load_translations_files_by_language", - mock_load_translations_files_by_language, - ): - await translation.async_get_translations(hass, "en", "state") - - assert len(load_requests) == 1 - to_load = load_requests[0] - assert len(to_load) == 1 - en_load = to_load["en"] - assert len(en_load) == 1 - assert "sensor" in en_load - assert "moon.sensor" not in en_load - - -async def test_translation_merging_custom_components( - hass: HomeAssistant, - caplog: pytest.LogCaptureFixture, - enable_custom_integrations: None, -) -> None: - """Test we merge translations of two integrations. - - Legacy state translations only used for custom integrations. - """ - hass.config.components.add("test_legacy_state_translations.sensor") - hass.config.components.add("sensor") - - orig_load_translations = translation._load_translations_files_by_language - - def mock_load_translations_files(files): - """Mock loading.""" - result = orig_load_translations(files) - result["en"]["test_legacy_state_translations.sensor"] = { - "state": { - "test_legacy_state_translations__phase": { - "first_quarter": "First Quarter" - } - } - } - return result - - with patch( - "homeassistant.helpers.translation._load_translations_files_by_language", - side_effect=mock_load_translations_files, - ): - translations = await translation.async_get_translations(hass, "en", "state") - - assert ( - "component.sensor.state.test_legacy_state_translations__phase.first_quarter" - in translations - ) - - hass.config.components.add("test_legacy_state_translations_bad_data.sensor") - - # Patch in some bad translation data - def mock_load_bad_translations_files(files): - """Mock loading.""" - result = orig_load_translations(files) - result["en"]["test_legacy_state_translations_bad_data.sensor"] = { - "state": "bad data" - } - return result - - with patch( - "homeassistant.helpers.translation._load_translations_files_by_language", - side_effect=mock_load_bad_translations_files, - ): - translations = await translation.async_get_translations(hass, "en", "state") - - assert ( - "component.sensor.state.test_legacy_state_translations__phase.first_quarter" - in translations - ) - - assert ( - "An integration providing translations for sensor provided invalid data:" - " bad data" - ) in caplog.text - - -async def test_translation_merging_loaded_apart_custom_integrations( - hass: HomeAssistant, - caplog: pytest.LogCaptureFixture, - enable_custom_integrations: None, -) -> None: - """Test we merge translations of two integrations when they are not loaded at the same time. - - Legacy state translations only used for custom integrations. - """ - orig_load_translations = translation._load_translations_files_by_language - - def mock_load_translations_files(files): - """Mock loading.""" - result = orig_load_translations(files) - result["en"]["test_legacy_state_translations.sensor"] = { - "state": { - "test_legacy_state_translations__phase": { - "first_quarter": "First Quarter" - } - } - } - return result - - hass.config.components.add("sensor") - - with patch( - "homeassistant.helpers.translation._load_translations_files_by_language", - side_effect=mock_load_translations_files, - ): - translations = await translation.async_get_translations(hass, "en", "state") - - assert ( - "component.sensor.state.test_legacy_state_translations__phase.first_quarter" - not in translations - ) - - hass.config.components.add("test_legacy_state_translations.sensor") - - with patch( - "homeassistant.helpers.translation._load_translations_files_by_language", - side_effect=mock_load_translations_files, - ): - translations = await translation.async_get_translations(hass, "en", "state") - - assert ( - "component.sensor.state.test_legacy_state_translations__phase.first_quarter" - in translations - ) - - with patch( - "homeassistant.helpers.translation._load_translations_files_by_language", - side_effect=mock_load_translations_files, - ): - translations = await translation.async_get_translations( - hass, "en", "state", integrations={"sensor"} - ) - - assert ( - "component.sensor.state.test_legacy_state_translations__phase.first_quarter" - in translations - ) - - async def test_translation_merging_loaded_together( hass: HomeAssistant, caplog: pytest.LogCaptureFixture ) -> None: @@ -592,14 +450,14 @@ async def test_caching(hass: HomeAssistant) -> None: # Patch with same method so we can count invocations with patch( - "homeassistant.helpers.translation._merge_resources", - side_effect=translation._merge_resources, - ) as mock_merge: + "homeassistant.helpers.translation.build_resources", + side_effect=translation.build_resources, + ) as mock_build_resources: load1 = await translation.async_get_translations(hass, "en", "entity_component") - assert len(mock_merge.mock_calls) == 1 + assert len(mock_build_resources.mock_calls) == 5 load2 = await translation.async_get_translations(hass, "en", "entity_component") - assert len(mock_merge.mock_calls) == 1 + assert len(mock_build_resources.mock_calls) == 5 assert load1 == load2 @@ -665,47 +523,58 @@ async def test_custom_component_translations( async def test_get_cached_translations( hass: HomeAssistant, mock_config_flows, enable_custom_integrations: None -): +) -> None: """Test the get cached translations helper.""" - translations = translation.async_get_cached_translations(hass, "en", "state") + translations = await translation.async_get_translations(hass, "en", "entity") assert translations == {} assert await async_setup_component(hass, "switch", {"switch": {"platform": "test"}}) await hass.async_block_till_done() - await translation._async_get_translations_cache(hass).async_load( - "en", hass.config.components + await translation._async_get_translations_cache(hass).async_load("en", {"test"}) + + translations = translation.async_get_cached_translations( + hass, "en", "entity", "test" ) - translations = translation.async_get_cached_translations(hass, "en", "state") + assert translations == { + "component.test.entity.switch.other1.name": "Other 1", + "component.test.entity.switch.other2.name": "Other 2", + "component.test.entity.switch.other3.name": "Other 3", + "component.test.entity.switch.other4.name": "Other 4", + "component.test.entity.switch.outlet.name": "Outlet {placeholder}", + } - assert translations["component.switch.state.string1"] == "Value 1" - assert translations["component.switch.state.string2"] == "Value 2" + await translation._async_get_translations_cache(hass).async_load("es", {"test"}) - await translation._async_get_translations_cache(hass).async_load( - "de", hass.config.components + # Test a partial translation + translations = translation.async_get_cached_translations( + hass, "es", "entity", "test" ) - translations = translation.async_get_cached_translations(hass, "de", "state") - assert "component.switch.something" not in translations - assert translations["component.switch.state.string1"] == "German Value 1" - assert translations["component.switch.state.string2"] == "German Value 2" - # Test a partial translation + assert translations == { + "component.test.entity.switch.other1.name": "Otra 1", + "component.test.entity.switch.other2.name": "Otra 2", + "component.test.entity.switch.other3.name": "Otra 3", + "component.test.entity.switch.other4.name": "Otra 4", + "component.test.entity.switch.outlet.name": "Enchufe {placeholder}", + } + await translation._async_get_translations_cache(hass).async_load( - "es", hass.config.components + "invalid-language", {"test"} ) - translations = translation.async_get_cached_translations(hass, "es", "state") - assert translations["component.switch.state.string1"] == "Spanish Value 1" - assert translations["component.switch.state.string2"] == "Value 2" # Test that an untranslated language falls back to English. - await translation._async_get_translations_cache(hass).async_load( - "invalid-language", hass.config.components - ) translations = translation.async_get_cached_translations( - hass, "invalid-language", "state" + hass, "invalid-language", "entity", "test" ) - assert translations["component.switch.state.string1"] == "Value 1" - assert translations["component.switch.state.string2"] == "Value 2" + + assert translations == { + "component.test.entity.switch.other1.name": "Other 1", + "component.test.entity.switch.other2.name": "Other 2", + "component.test.entity.switch.other3.name": "Other 3", + "component.test.entity.switch.other4.name": "Other 4", + "component.test.entity.switch.outlet.name": "Outlet {placeholder}", + } async def test_setup(hass: HomeAssistant): @@ -784,36 +653,6 @@ async def test_translate_state(hass: HomeAssistant): mock.assert_called_once_with(hass, hass.config.language, "entity_component") assert result == "TRANSLATED" - with patch( - "homeassistant.helpers.translation.async_get_cached_translations", - return_value={"component.binary_sensor.state.device_class.on": "TRANSLATED"}, - ) as mock: - result = translation.async_translate_state( - hass, "on", "binary_sensor", "platform", None, "device_class" - ) - mock.assert_has_calls( - [ - call(hass, hass.config.language, "entity_component"), - call(hass, hass.config.language, "state", "binary_sensor"), - ] - ) - assert result == "TRANSLATED" - - with patch( - "homeassistant.helpers.translation.async_get_cached_translations", - return_value={"component.binary_sensor.state._.on": "TRANSLATED"}, - ) as mock: - result = translation.async_translate_state( - hass, "on", "binary_sensor", "platform", None, None - ) - mock.assert_has_calls( - [ - call(hass, hass.config.language, "entity_component"), - call(hass, hass.config.language, "state", "binary_sensor"), - ] - ) - assert result == "TRANSLATED" - with patch( "homeassistant.helpers.translation.async_get_cached_translations", return_value={}, @@ -824,7 +663,6 @@ async def test_translate_state(hass: HomeAssistant): mock.assert_has_calls( [ call(hass, hass.config.language, "entity_component"), - call(hass, hass.config.language, "state", "binary_sensor"), ] ) assert result == "on" @@ -840,7 +678,6 @@ async def test_translate_state(hass: HomeAssistant): [ call(hass, hass.config.language, "entity"), call(hass, hass.config.language, "entity_component"), - call(hass, hass.config.language, "state", "binary_sensor"), ] ) assert result == "on" diff --git a/tests/testing_config/custom_components/test/translations/_broken.en.json b/tests/testing_config/custom_components/test/translations/_broken.json similarity index 100% rename from tests/testing_config/custom_components/test/translations/_broken.en.json rename to tests/testing_config/custom_components/test/translations/_broken.json diff --git a/tests/testing_config/custom_components/test/translations/en.json b/tests/testing_config/custom_components/test/translations/en.json index 56404508c4c5cb36b9fe87d1a12425ec51479d76..7ed32c224a71bd0f5f10b7b576ddf0eb8f6355f6 100644 --- a/tests/testing_config/custom_components/test/translations/en.json +++ b/tests/testing_config/custom_components/test/translations/en.json @@ -7,5 +7,6 @@ "other4": { "name": "Other 4" }, "outlet": { "name": "Outlet {placeholder}" } } - } + }, + "something": "else" } diff --git a/tests/testing_config/custom_components/test/translations/switch.de.json b/tests/testing_config/custom_components/test/translations/switch.de.json deleted file mode 100644 index fad78b12d63a90aeb6548930305ffb5905a7d430..0000000000000000000000000000000000000000 --- a/tests/testing_config/custom_components/test/translations/switch.de.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "state": { - "string1": "German Value 1", - "string2": "German Value 2" - } -} diff --git a/tests/testing_config/custom_components/test/translations/switch.en.json b/tests/testing_config/custom_components/test/translations/switch.en.json deleted file mode 100644 index 1cc764adb21c2f328c2f439c2dffc3c20556d02e..0000000000000000000000000000000000000000 --- a/tests/testing_config/custom_components/test/translations/switch.en.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "state": { - "string1": "Value 1", - "string2": "Value 2" - }, - "something": "else" -} diff --git a/tests/testing_config/custom_components/test/translations/switch.es.json b/tests/testing_config/custom_components/test/translations/switch.es.json deleted file mode 100644 index b3590a6d3210341205bbe86bd4e49e143a0eec9f..0000000000000000000000000000000000000000 --- a/tests/testing_config/custom_components/test/translations/switch.es.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "state": { - "string1": "Spanish Value 1" - } -}