Load translations at setup time if they were not loaded at bootstrap (#110921)
This commit is contained in:
parent
076ae22fdd
commit
dd80157dc7
4 changed files with 40 additions and 49 deletions
|
@ -5,10 +5,9 @@ import asyncio
|
||||||
from collections.abc import Iterable, Mapping
|
from collections.abc import Iterable, Mapping
|
||||||
import logging
|
import logging
|
||||||
import string
|
import string
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_COMPONENT_LOADED,
|
|
||||||
EVENT_CORE_CONFIG_UPDATE,
|
EVENT_CORE_CONFIG_UPDATE,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
|
@ -498,35 +497,6 @@ def async_setup(hass: HomeAssistant) -> None:
|
||||||
_LOGGER.debug("Loading translations for language: %s", new_language)
|
_LOGGER.debug("Loading translations for language: %s", new_language)
|
||||||
await cache.async_load(new_language, hass.config.components)
|
await cache.async_load(new_language, hass.config.components)
|
||||||
|
|
||||||
@callback
|
|
||||||
def _async_load_translations_for_component_filter(event: Event) -> bool:
|
|
||||||
"""Filter out unwanted events."""
|
|
||||||
component: str | None = event.data.get("component")
|
|
||||||
# Platforms don't have their own translations, skip them
|
|
||||||
return bool(
|
|
||||||
component
|
|
||||||
and "." not in component
|
|
||||||
and not cache.async_is_loaded(hass.config.language, {component})
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _async_load_translations_for_component(event: Event) -> None:
|
|
||||||
"""Load translations for a component."""
|
|
||||||
component: str | None = event.data.get("component")
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert component is not None
|
|
||||||
language = hass.config.language
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Loading translations for language: %s and component: %s",
|
|
||||||
language,
|
|
||||||
component,
|
|
||||||
)
|
|
||||||
await cache.async_load(language, {component})
|
|
||||||
|
|
||||||
hass.bus.async_listen(
|
|
||||||
EVENT_COMPONENT_LOADED,
|
|
||||||
_async_load_translations_for_component,
|
|
||||||
event_filter=_async_load_translations_for_component_filter,
|
|
||||||
)
|
|
||||||
hass.bus.async_listen(
|
hass.bus.async_listen(
|
||||||
EVENT_CORE_CONFIG_UPDATE,
|
EVENT_CORE_CONFIG_UPDATE,
|
||||||
_async_load_translations,
|
_async_load_translations,
|
||||||
|
@ -541,6 +511,14 @@ async def async_load_integrations(hass: HomeAssistant, integrations: set[str]) -
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_translations_loaded(hass: HomeAssistant, components: set[str]) -> bool:
|
||||||
|
"""Return if the given components are loaded for the language."""
|
||||||
|
return _async_get_translations_cache(hass).async_is_loaded(
|
||||||
|
hass.config.language, components
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_translate_state(
|
def async_translate_state(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|
|
@ -25,6 +25,7 @@ from .core import (
|
||||||
callback,
|
callback,
|
||||||
)
|
)
|
||||||
from .exceptions import DependencyError, HomeAssistantError
|
from .exceptions import DependencyError, HomeAssistantError
|
||||||
|
from .helpers import translation
|
||||||
from .helpers.issue_registry import IssueSeverity, async_create_issue
|
from .helpers.issue_registry import IssueSeverity, async_create_issue
|
||||||
from .helpers.typing import ConfigType, EventType
|
from .helpers.typing import ConfigType, EventType
|
||||||
from .util import ensure_unique_string
|
from .util import ensure_unique_string
|
||||||
|
@ -244,7 +245,7 @@ async def _async_process_dependencies(
|
||||||
return failed
|
return failed
|
||||||
|
|
||||||
|
|
||||||
async def _async_setup_component(
|
async def _async_setup_component( # noqa: C901
|
||||||
hass: core.HomeAssistant, domain: str, config: ConfigType
|
hass: core.HomeAssistant, domain: str, config: ConfigType
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Set up a component for Home Assistant.
|
"""Set up a component for Home Assistant.
|
||||||
|
@ -343,7 +344,19 @@ async def _async_setup_component(
|
||||||
|
|
||||||
start = timer()
|
start = timer()
|
||||||
_LOGGER.info("Setting up %s", domain)
|
_LOGGER.info("Setting up %s", domain)
|
||||||
with async_start_setup(hass, [domain]):
|
integration_set = {domain}
|
||||||
|
|
||||||
|
load_translations_task: asyncio.Task[None] | None = None
|
||||||
|
if not translation.async_translations_loaded(hass, integration_set):
|
||||||
|
# For most cases we expect the translations are already
|
||||||
|
# loaded since we try to load them in bootstrap ahead of time.
|
||||||
|
# If for some reason the background task in bootstrap was too slow
|
||||||
|
# or the integration was added after bootstrap, we will load them here.
|
||||||
|
load_translations_task = asyncio.create_task(
|
||||||
|
translation.async_load_integrations(hass, integration_set)
|
||||||
|
)
|
||||||
|
|
||||||
|
with async_start_setup(hass, integration_set):
|
||||||
if hasattr(component, "PLATFORM_SCHEMA"):
|
if hasattr(component, "PLATFORM_SCHEMA"):
|
||||||
# Entity components have their own warning
|
# Entity components have their own warning
|
||||||
warn_task = None
|
warn_task = None
|
||||||
|
@ -409,6 +422,8 @@ async def _async_setup_component(
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
await hass.config_entries.flow.async_wait_import_flow_initialized(domain)
|
await hass.config_entries.flow.async_wait_import_flow_initialized(domain)
|
||||||
|
|
||||||
|
if load_translations_task:
|
||||||
|
await load_translations_task
|
||||||
# Add to components before the entry.async_setup
|
# Add to components before the entry.async_setup
|
||||||
# call to avoid a deadlock when forwarding platforms
|
# call to avoid a deadlock when forwarding platforms
|
||||||
hass.config.components.add(domain)
|
hass.config.components.add(domain)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from unittest.mock import Mock, call, patch
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import loader
|
from homeassistant import loader
|
||||||
from homeassistant.const import EVENT_COMPONENT_LOADED, EVENT_CORE_CONFIG_UPDATE
|
from homeassistant.const import EVENT_CORE_CONFIG_UPDATE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import translation
|
from homeassistant.helpers import translation
|
||||||
from homeassistant.loader import async_get_integration
|
from homeassistant.loader import async_get_integration
|
||||||
|
@ -605,20 +605,6 @@ async def test_setup(hass: HomeAssistant):
|
||||||
"""Test the setup load listeners helper."""
|
"""Test the setup load listeners helper."""
|
||||||
translation.async_setup(hass)
|
translation.async_setup(hass)
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.helpers.translation._TranslationCache.async_load",
|
|
||||||
) as mock:
|
|
||||||
hass.bus.async_fire(EVENT_COMPONENT_LOADED, {"component": "loaded_component"})
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
mock.assert_called_once_with(hass.config.language, {"loaded_component"})
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.helpers.translation._TranslationCache.async_load",
|
|
||||||
) as mock:
|
|
||||||
hass.bus.async_fire(EVENT_COMPONENT_LOADED, {"component": "config.component"})
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
mock.assert_not_called()
|
|
||||||
|
|
||||||
# Should not be called if the language is the current language
|
# Should not be called if the language is the current language
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.translation._TranslationCache.async_load",
|
"homeassistant.helpers.translation._TranslationCache.async_load",
|
||||||
|
|
|
@ -11,7 +11,7 @@ from homeassistant import config_entries, setup
|
||||||
from homeassistant.const import EVENT_COMPONENT_LOADED, EVENT_HOMEASSISTANT_START
|
from homeassistant.const import EVENT_COMPONENT_LOADED, EVENT_HOMEASSISTANT_START
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import discovery
|
from homeassistant.helpers import discovery, translation
|
||||||
from homeassistant.helpers.config_validation import (
|
from homeassistant.helpers.config_validation import (
|
||||||
PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA,
|
||||||
PLATFORM_SCHEMA_BASE,
|
PLATFORM_SCHEMA_BASE,
|
||||||
|
@ -801,3 +801,15 @@ async def test_setup_config_entry_from_yaml(
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
hass.data.pop(setup.DATA_SETUP)
|
hass.data.pop(setup.DATA_SETUP)
|
||||||
hass.config.components.remove("test_integration_only_entry")
|
hass.config.components.remove("test_integration_only_entry")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_loading_component_loads_translations(hass: HomeAssistant) -> None:
|
||||||
|
"""Test that loading a component loads translations."""
|
||||||
|
assert translation.async_translations_loaded(hass, {"comp"}) is False
|
||||||
|
mock_setup = Mock(return_value=True)
|
||||||
|
|
||||||
|
mock_integration(hass, MockModule("comp", setup=mock_setup))
|
||||||
|
|
||||||
|
assert await setup.async_setup_component(hass, "comp", {})
|
||||||
|
assert mock_setup.called
|
||||||
|
assert translation.async_translations_loaded(hass, {"comp"}) is True
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue