Limit legacy state translations to custom components (#112295)
* Limit legacy state translations to custom components We were trying to load **thousands** of `*.light.json`, `*.switch.json` files at run time that did not exist. There have been replaced with entity translations: https://github.com/home-assistant/developers.home-assistant/pull/1557 https://github.com/home-assistant/core/pull/82701 https://github.com/home-assistant/core/pull/112023 will completely remove them, but for now we will only load them for custom components to reduce the number of files having to be examined * reduce * reduce * reduce * reduce * comment * coverage * try to remove empty dict in loaded_translations fallback when missing
This commit is contained in:
parent
d34e2c1f12
commit
fbabbc8f92
6 changed files with 106 additions and 26 deletions
|
@ -165,20 +165,21 @@ async def _async_get_component_strings(
|
||||||
for language in languages:
|
for language in languages:
|
||||||
files_to_load: dict[str, str] = {}
|
files_to_load: dict[str, str] = {}
|
||||||
files_to_load_by_language[language] = files_to_load
|
files_to_load_by_language[language] = files_to_load
|
||||||
|
translations_by_language[language] = {}
|
||||||
loaded_translations: dict[str, Any] = {}
|
|
||||||
translations_by_language[language] = loaded_translations
|
|
||||||
|
|
||||||
for loaded in components:
|
for loaded in components:
|
||||||
domain = loaded.partition(".")[0]
|
domain, _, platform = loaded.partition(".")
|
||||||
if not (integration := integrations.get(domain)):
|
if not (integration := integrations.get(domain)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
path = component_translation_path(loaded, language, integration)
|
if platform and integration.is_built_in:
|
||||||
# No translation available
|
# Legacy state translations are no longer used for built-in integrations
|
||||||
if path is None:
|
# and we avoid trying to load them. This is a temporary measure to allow
|
||||||
loaded_translations[loaded] = {}
|
# them to keep working for custom integrations until we can fully remove
|
||||||
else:
|
# them.
|
||||||
|
continue
|
||||||
|
|
||||||
|
if path := component_translation_path(loaded, language, integration):
|
||||||
files_to_load[loaded] = path
|
files_to_load[loaded] = path
|
||||||
|
|
||||||
if not files_to_load:
|
if not files_to_load:
|
||||||
|
|
|
@ -335,20 +335,57 @@ async def test_get_translation_categories(hass: HomeAssistant) -> None:
|
||||||
assert "component.light.device_automation.action_type.turn_on" in translations
|
assert "component.light.device_automation.action_type.turn_on" in translations
|
||||||
|
|
||||||
|
|
||||||
async def test_translation_merging(
|
async def test_legacy_platform_translations_not_used_built_in_integrations(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we merge translations of two integrations."""
|
"""Test legacy platform translations are not used for built-in integrations."""
|
||||||
hass.config.components.add("moon.sensor")
|
hass.config.components.add("moon.sensor")
|
||||||
hass.config.components.add("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
|
orig_load_translations = translation._load_translations_files_by_language
|
||||||
|
|
||||||
def mock_load_translations_files(files):
|
def mock_load_translations_files(files):
|
||||||
"""Mock loading."""
|
"""Mock loading."""
|
||||||
result = orig_load_translations(files)
|
result = orig_load_translations(files)
|
||||||
result["en"]["moon.sensor"] = {
|
result["en"]["test_legacy_state_translations.sensor"] = {
|
||||||
"state": {"moon__phase": {"first_quarter": "First Quarter"}}
|
"state": {
|
||||||
|
"test_legacy_state_translations__phase": {
|
||||||
|
"first_quarter": "First Quarter"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -358,15 +395,20 @@ async def test_translation_merging(
|
||||||
):
|
):
|
||||||
translations = await translation.async_get_translations(hass, "en", "state")
|
translations = await translation.async_get_translations(hass, "en", "state")
|
||||||
|
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
assert (
|
||||||
|
"component.sensor.state.test_legacy_state_translations__phase.first_quarter"
|
||||||
|
in translations
|
||||||
|
)
|
||||||
|
|
||||||
hass.config.components.add("season.sensor")
|
hass.config.components.add("test_legacy_state_translations_bad_data.sensor")
|
||||||
|
|
||||||
# Patch in some bad translation data
|
# Patch in some bad translation data
|
||||||
def mock_load_bad_translations_files(files):
|
def mock_load_bad_translations_files(files):
|
||||||
"""Mock loading."""
|
"""Mock loading."""
|
||||||
result = orig_load_translations(files)
|
result = orig_load_translations(files)
|
||||||
result["en"]["season.sensor"] = {"state": "bad data"}
|
result["en"]["test_legacy_state_translations_bad_data.sensor"] = {
|
||||||
|
"state": "bad data"
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
|
@ -375,7 +417,10 @@ async def test_translation_merging(
|
||||||
):
|
):
|
||||||
translations = await translation.async_get_translations(hass, "en", "state")
|
translations = await translation.async_get_translations(hass, "en", "state")
|
||||||
|
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
assert (
|
||||||
|
"component.sensor.state.test_legacy_state_translations__phase.first_quarter"
|
||||||
|
in translations
|
||||||
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
"An integration providing translations for sensor provided invalid data:"
|
"An integration providing translations for sensor provided invalid data:"
|
||||||
|
@ -383,17 +428,26 @@ async def test_translation_merging(
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_translation_merging_loaded_apart(
|
async def test_translation_merging_loaded_apart_custom_integrations(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
enable_custom_integrations: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we merge translations of two integrations when they are not loaded at the same time."""
|
"""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
|
orig_load_translations = translation._load_translations_files_by_language
|
||||||
|
|
||||||
def mock_load_translations_files(files):
|
def mock_load_translations_files(files):
|
||||||
"""Mock loading."""
|
"""Mock loading."""
|
||||||
result = orig_load_translations(files)
|
result = orig_load_translations(files)
|
||||||
result["en"]["moon.sensor"] = {
|
result["en"]["test_legacy_state_translations.sensor"] = {
|
||||||
"state": {"moon__phase": {"first_quarter": "First Quarter"}}
|
"state": {
|
||||||
|
"test_legacy_state_translations__phase": {
|
||||||
|
"first_quarter": "First Quarter"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -405,9 +459,12 @@ async def test_translation_merging_loaded_apart(
|
||||||
):
|
):
|
||||||
translations = await translation.async_get_translations(hass, "en", "state")
|
translations = await translation.async_get_translations(hass, "en", "state")
|
||||||
|
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" not in translations
|
assert (
|
||||||
|
"component.sensor.state.test_legacy_state_translations__phase.first_quarter"
|
||||||
|
not in translations
|
||||||
|
)
|
||||||
|
|
||||||
hass.config.components.add("moon.sensor")
|
hass.config.components.add("test_legacy_state_translations.sensor")
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.translation._load_translations_files_by_language",
|
"homeassistant.helpers.translation._load_translations_files_by_language",
|
||||||
|
@ -415,7 +472,10 @@ async def test_translation_merging_loaded_apart(
|
||||||
):
|
):
|
||||||
translations = await translation.async_get_translations(hass, "en", "state")
|
translations = await translation.async_get_translations(hass, "en", "state")
|
||||||
|
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
assert (
|
||||||
|
"component.sensor.state.test_legacy_state_translations__phase.first_quarter"
|
||||||
|
in translations
|
||||||
|
)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.translation._load_translations_files_by_language",
|
"homeassistant.helpers.translation._load_translations_files_by_language",
|
||||||
|
@ -425,7 +485,10 @@ async def test_translation_merging_loaded_apart(
|
||||||
hass, "en", "state", integrations={"sensor"}
|
hass, "en", "state", integrations={"sensor"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
assert (
|
||||||
|
"component.sensor.state.test_legacy_state_translations__phase.first_quarter"
|
||||||
|
in translations
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_translation_merging_loaded_together(
|
async def test_translation_merging_loaded_together(
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
"""Provide a mock package component."""
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"domain": "test_legacy_state_translations",
|
||||||
|
"name": "Test package for legacy state translations",
|
||||||
|
"documentation": "http://test-package.io",
|
||||||
|
"config_flow": true,
|
||||||
|
"version": "1.2.3"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
"""Provide a mock package component."""
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"domain": "test_legacy_state_translations_bad_data",
|
||||||
|
"name": "Test package for legacy state translations",
|
||||||
|
"documentation": "http://test-package.io",
|
||||||
|
"config_flow": true,
|
||||||
|
"version": "1.2.3"
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue