Support requesting translations for multiple integrations in a single request (#71979)

pull/71988/head
J. Nick Koston 2022-05-17 01:23:11 -05:00 committed by GitHub
parent 78f0716574
commit a614ddca28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 15 deletions

View File

@ -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,
} }
) )

View File

@ -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()

View File

@ -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))

View File

@ -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")

View File

@ -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: