Support requesting translations for multiple integrations in a single request (#71979)
parent
78f0716574
commit
a614ddca28
|
@ -667,7 +667,7 @@ def websocket_get_themes(
|
||||||
"type": "frontend/get_translations",
|
"type": "frontend/get_translations",
|
||||||
vol.Required("language"): str,
|
vol.Required("language"): str,
|
||||||
vol.Required("category"): str,
|
vol.Required("category"): str,
|
||||||
vol.Optional("integration"): str,
|
vol.Optional("integration"): vol.All(cv.ensure_list, [str]),
|
||||||
vol.Optional("config_flow"): bool,
|
vol.Optional("config_flow"): bool,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,6 +15,7 @@ from homeassistant.components.http.data_validator import RequestDataValidator
|
||||||
from homeassistant.components.http.view import HomeAssistantView
|
from homeassistant.components.http.view import HomeAssistantView
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.system_info import async_get_system_info
|
from homeassistant.helpers.system_info import async_get_system_info
|
||||||
|
from homeassistant.helpers.translation import async_get_translations
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_AREAS,
|
DEFAULT_AREAS,
|
||||||
|
@ -147,8 +148,8 @@ class UserOnboardingView(_BaseOnboardingView):
|
||||||
await person.async_create_person(hass, data["name"], user_id=user.id)
|
await person.async_create_person(hass, data["name"], user_id=user.id)
|
||||||
|
|
||||||
# Create default areas using the users supplied language.
|
# Create default areas using the users supplied language.
|
||||||
translations = await hass.helpers.translation.async_get_translations(
|
translations = await async_get_translations(
|
||||||
data["language"], "area", DOMAIN
|
hass, data["language"], "area", {DOMAIN}
|
||||||
)
|
)
|
||||||
|
|
||||||
area_registry = await hass.helpers.area_registry.async_get_registry()
|
area_registry = await hass.helpers.area_registry.async_get_registry()
|
||||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections import ChainMap
|
from collections import ChainMap
|
||||||
from collections.abc import Mapping
|
from collections.abc import Iterable, Mapping
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ async def async_get_translations(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
language: str,
|
language: str,
|
||||||
category: str,
|
category: str,
|
||||||
integration: str | None = None,
|
integrations: Iterable[str] | None = None,
|
||||||
config_flow: bool | None = None,
|
config_flow: bool | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Return all backend translations.
|
"""Return all backend translations.
|
||||||
|
@ -297,8 +297,8 @@ async def async_get_translations(
|
||||||
"""
|
"""
|
||||||
lock = hass.data.setdefault(TRANSLATION_LOAD_LOCK, asyncio.Lock())
|
lock = hass.data.setdefault(TRANSLATION_LOAD_LOCK, asyncio.Lock())
|
||||||
|
|
||||||
if integration is not None:
|
if integrations is not None:
|
||||||
components = {integration}
|
components = set(integrations)
|
||||||
elif config_flow:
|
elif config_flow:
|
||||||
components = (await async_get_config_flows(hass)) - hass.config.components
|
components = (await async_get_config_flows(hass)) - hass.config.components
|
||||||
elif category == "state":
|
elif category == "state":
|
||||||
|
@ -310,7 +310,10 @@ async def async_get_translations(
|
||||||
}
|
}
|
||||||
|
|
||||||
async with lock:
|
async with lock:
|
||||||
cache = hass.data.setdefault(TRANSLATION_FLATTEN_CACHE, _TranslationCache(hass))
|
if TRANSLATION_FLATTEN_CACHE in hass.data:
|
||||||
|
cache = hass.data[TRANSLATION_FLATTEN_CACHE]
|
||||||
|
else:
|
||||||
|
cache = hass.data[TRANSLATION_FLATTEN_CACHE] = _TranslationCache(hass)
|
||||||
cached = await cache.async_fetch(language, category, components)
|
cached = await cache.async_fetch(language, category, components)
|
||||||
|
|
||||||
return dict(ChainMap(*cached))
|
return dict(ChainMap(*cached))
|
||||||
|
|
|
@ -424,7 +424,7 @@ async def test_get_translations(hass, ws_client):
|
||||||
"""Test get_translations command."""
|
"""Test get_translations command."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.frontend.async_get_translations",
|
"homeassistant.components.frontend.async_get_translations",
|
||||||
side_effect=lambda hass, lang, category, integration, config_flow: {
|
side_effect=lambda hass, lang, category, integrations, config_flow: {
|
||||||
"lang": lang
|
"lang": lang
|
||||||
},
|
},
|
||||||
):
|
):
|
||||||
|
@ -444,6 +444,58 @@ async def test_get_translations(hass, ws_client):
|
||||||
assert msg["result"] == {"resources": {"lang": "nl"}}
|
assert msg["result"] == {"resources": {"lang": "nl"}}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_translations_for_integrations(hass, ws_client):
|
||||||
|
"""Test get_translations for integrations command."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.frontend.async_get_translations",
|
||||||
|
side_effect=lambda hass, lang, category, integration, config_flow: {
|
||||||
|
"lang": lang,
|
||||||
|
"integration": integration,
|
||||||
|
},
|
||||||
|
):
|
||||||
|
await ws_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "frontend/get_translations",
|
||||||
|
"integration": ["frontend", "http"],
|
||||||
|
"language": "nl",
|
||||||
|
"category": "lang",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
assert set(msg["result"]["resources"]["integration"]) == {"frontend", "http"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_translations_for_single_integration(hass, ws_client):
|
||||||
|
"""Test get_translations for integration command."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.frontend.async_get_translations",
|
||||||
|
side_effect=lambda hass, lang, category, integrations, config_flow: {
|
||||||
|
"lang": lang,
|
||||||
|
"integration": integrations,
|
||||||
|
},
|
||||||
|
):
|
||||||
|
await ws_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "frontend/get_translations",
|
||||||
|
"integration": "http",
|
||||||
|
"language": "nl",
|
||||||
|
"category": "lang",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == {"resources": {"lang": "nl", "integration": ["http"]}}
|
||||||
|
|
||||||
|
|
||||||
async def test_auth_load(hass):
|
async def test_auth_load(hass):
|
||||||
"""Test auth component loaded by default."""
|
"""Test auth component loaded by default."""
|
||||||
frontend = await async_get_integration(hass, "frontend")
|
frontend = await async_get_integration(hass, "frontend")
|
||||||
|
|
|
@ -290,12 +290,29 @@ async def test_translation_merging_loaded_apart(hass, caplog):
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
||||||
|
|
||||||
translations = await translation.async_get_translations(
|
translations = await translation.async_get_translations(
|
||||||
hass, "en", "state", integration="sensor"
|
hass, "en", "state", integrations={"sensor"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
assert "component.sensor.state.moon__phase.first_quarter" in translations
|
||||||
|
|
||||||
|
|
||||||
|
async def test_translation_merging_loaded_together(hass, caplog):
|
||||||
|
"""Test we merge translations of two integrations when they are loaded at the same time."""
|
||||||
|
hass.config.components.add("hue")
|
||||||
|
hass.config.components.add("homekit")
|
||||||
|
hue_translations = await translation.async_get_translations(
|
||||||
|
hass, "en", "config", integrations={"hue"}
|
||||||
|
)
|
||||||
|
homekit_translations = await translation.async_get_translations(
|
||||||
|
hass, "en", "config", integrations={"homekit"}
|
||||||
|
)
|
||||||
|
|
||||||
|
translations = await translation.async_get_translations(
|
||||||
|
hass, "en", "config", integrations={"hue", "homekit"}
|
||||||
|
)
|
||||||
|
assert translations == hue_translations | homekit_translations
|
||||||
|
|
||||||
|
|
||||||
async def test_caching(hass):
|
async def test_caching(hass):
|
||||||
"""Test we cache data."""
|
"""Test we cache data."""
|
||||||
hass.config.components.add("sensor")
|
hass.config.components.add("sensor")
|
||||||
|
@ -320,14 +337,14 @@ async def test_caching(hass):
|
||||||
)
|
)
|
||||||
|
|
||||||
load_sensor_only = await translation.async_get_translations(
|
load_sensor_only = await translation.async_get_translations(
|
||||||
hass, "en", "state", integration="sensor"
|
hass, "en", "state", integrations={"sensor"}
|
||||||
)
|
)
|
||||||
assert load_sensor_only
|
assert load_sensor_only
|
||||||
for key in load_sensor_only:
|
for key in load_sensor_only:
|
||||||
assert key.startswith("component.sensor.state.")
|
assert key.startswith("component.sensor.state.")
|
||||||
|
|
||||||
load_light_only = await translation.async_get_translations(
|
load_light_only = await translation.async_get_translations(
|
||||||
hass, "en", "state", integration="light"
|
hass, "en", "state", integrations={"light"}
|
||||||
)
|
)
|
||||||
assert load_light_only
|
assert load_light_only
|
||||||
for key in load_light_only:
|
for key in load_light_only:
|
||||||
|
@ -341,7 +358,7 @@ async def test_caching(hass):
|
||||||
side_effect=translation._build_resources,
|
side_effect=translation._build_resources,
|
||||||
) as mock_build:
|
) as mock_build:
|
||||||
load_sensor_only = await translation.async_get_translations(
|
load_sensor_only = await translation.async_get_translations(
|
||||||
hass, "en", "title", integration="sensor"
|
hass, "en", "title", integrations={"sensor"}
|
||||||
)
|
)
|
||||||
assert load_sensor_only
|
assert load_sensor_only
|
||||||
for key in load_sensor_only:
|
for key in load_sensor_only:
|
||||||
|
@ -349,12 +366,12 @@ async def test_caching(hass):
|
||||||
assert len(mock_build.mock_calls) == 0
|
assert len(mock_build.mock_calls) == 0
|
||||||
|
|
||||||
assert await translation.async_get_translations(
|
assert await translation.async_get_translations(
|
||||||
hass, "en", "title", integration="sensor"
|
hass, "en", "title", integrations={"sensor"}
|
||||||
)
|
)
|
||||||
assert len(mock_build.mock_calls) == 0
|
assert len(mock_build.mock_calls) == 0
|
||||||
|
|
||||||
load_light_only = await translation.async_get_translations(
|
load_light_only = await translation.async_get_translations(
|
||||||
hass, "en", "title", integration="media_player"
|
hass, "en", "title", integrations={"media_player"}
|
||||||
)
|
)
|
||||||
assert load_light_only
|
assert load_light_only
|
||||||
for key in load_light_only:
|
for key in load_light_only:
|
||||||
|
|
Loading…
Reference in New Issue