diff --git a/homeassistant/helpers/translation.py b/homeassistant/helpers/translation.py index 40e8351a3ac..641d200afe3 100644 --- a/homeassistant/helpers/translation.py +++ b/homeassistant/helpers/translation.py @@ -163,6 +163,7 @@ async def _async_get_component_strings( translations_by_language: dict[str, dict[str, Any]] = {} # Determine paths of missing components/platforms files_to_load_by_language: dict[str, dict[str, str]] = {} + loaded_translations_by_language: dict[str, dict[str, Any]] = {} has_files_to_load = False for language in languages: files_to_load: dict[str, str] = {} @@ -171,7 +172,10 @@ async def _async_get_component_strings( for comp in components: domain, _, platform = comp.partition(".") - if not (integration := integrations.get(domain)): + if ( + not (integration := integrations.get(domain)) + or not integration.has_translations + ): continue if platform and integration.is_built_in: @@ -185,22 +189,23 @@ async def _async_get_component_strings( files_to_load[comp] = path has_files_to_load = True - if not has_files_to_load: - return translations_by_language + if has_files_to_load: + loaded_translations_by_language = await hass.async_add_executor_job( + _load_translations_files_by_language, files_to_load_by_language + ) - # Load files - loaded_translations_by_language = await hass.async_add_executor_job( - _load_translations_files_by_language, files_to_load_by_language - ) - - # Translations that miss "title" will get integration put in. - for language, loaded_translations in loaded_translations_by_language.items(): - for loaded, loaded_translation in loaded_translations.items(): - if "." in loaded: + for language in languages: + loaded_translations = loaded_translations_by_language.setdefault(language, {}) + for comp in components: + if "." in comp: continue - if "title" not in loaded_translation: - loaded_translation["title"] = integrations[loaded].name + # Translations that miss "title" will get integration put in. + component_translations = loaded_translations.setdefault(comp, {}) + if "title" not in component_translations and ( + integration := integrations.get(comp) + ): + component_translations["title"] = integration.name translations_by_language[language].update(loaded_translations) diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 57c91f84818..622c8524709 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -825,6 +825,11 @@ class Integration: # In the future, we want to default to True for all integrations. return self.manifest.get("import_executor", self.is_built_in) + @cached_property + def has_translations(self) -> bool: + """Return if the integration has translations.""" + return "translations" in self._top_level_files + @property def mqtt(self) -> list[str] | None: """Return Integration MQTT entries.""" diff --git a/tests/helpers/test_translation.py b/tests/helpers/test_translation.py index 772b5d05f79..45c43144da7 100644 --- a/tests/helpers/test_translation.py +++ b/tests/helpers/test_translation.py @@ -832,3 +832,35 @@ async def test_translate_state(hass: HomeAssistant): ] ) assert result == "on" + + +async def test_get_translations_still_has_title_without_translations_files( + hass: HomeAssistant, mock_config_flows +) -> None: + """Test the title still gets added in if there are no translation files.""" + mock_config_flows["integration"].append("component1") + integration = Mock(file_path=pathlib.Path(__file__)) + integration.name = "Component 1" + + with patch( + "homeassistant.helpers.translation.component_translation_path", + return_value="bla.json", + ), patch( + "homeassistant.helpers.translation._load_translations_files_by_language", + return_value={}, + ), patch( + "homeassistant.helpers.translation.async_get_integrations", + return_value={"component1": integration}, + ): + translations = await translation.async_get_translations( + hass, "en", "title", config_flow=True + ) + translations_again = await translation.async_get_translations( + hass, "en", "title", config_flow=True + ) + + assert translations == translations_again + + assert translations == { + "component.component1.title": "Component 1", + } diff --git a/tests/testing_config/custom_components/test_legacy_state_translations/translations/en.json b/tests/testing_config/custom_components/test_legacy_state_translations/translations/en.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/tests/testing_config/custom_components/test_legacy_state_translations/translations/en.json @@ -0,0 +1 @@ +{} diff --git a/tests/testing_config/custom_components/test_legacy_state_translations_bad_data/translations/en.json b/tests/testing_config/custom_components/test_legacy_state_translations_bad_data/translations/en.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/tests/testing_config/custom_components/test_legacy_state_translations_bad_data/translations/en.json @@ -0,0 +1 @@ +{}