Take integration title from manifest if not translated (#34283)

This commit is contained in:
Paulus Schoutsen 2020-04-16 08:38:54 -07:00 committed by GitHub
parent 3d9ae1b8bd
commit 94a3cec4bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 26 deletions

View File

@ -1,5 +1,4 @@
{
"title": "Philips Hue",
"config": {
"step": {
"init": {

View File

@ -1,8 +1,11 @@
"""Translation string lookup helpers."""
import asyncio
import logging
from typing import Any, Dict, Iterable, Optional
from homeassistant.core import callback
from homeassistant.loader import (
Integration,
async_get_config_flows,
async_get_integration,
bind_hass,
@ -32,8 +35,9 @@ def flatten(data: Dict) -> Dict[str, Any]:
return recursive_flatten("", data)
async def component_translation_file(
hass: HomeAssistantType, component: str, language: str
@callback
def component_translation_file(
component: str, language: str, integration: Integration
) -> Optional[str]:
"""Return the translation json file location for a component.
@ -49,9 +53,6 @@ async def component_translation_file(
domain = parts[-1]
is_platform = len(parts) == 2
integration = await async_get_integration(hass, domain)
assert integration is not None, domain
if is_platform:
filename = f"{parts[0]}.{language}.json"
return str(integration.file_path / ".translations" / filename)
@ -105,26 +106,47 @@ def build_resources(
async def async_get_component_resources(
hass: HomeAssistantType, language: str
) -> Dict[str, Any]:
"""Return translation resources for all components."""
if TRANSLATION_STRING_CACHE not in hass.data:
hass.data[TRANSLATION_STRING_CACHE] = {}
if language not in hass.data[TRANSLATION_STRING_CACHE]:
hass.data[TRANSLATION_STRING_CACHE][language] = {}
translation_cache = hass.data[TRANSLATION_STRING_CACHE][language]
"""Return translation resources for all components.
# Get the set of components
We go through all loaded components and platforms:
- see if they have already been loaded (exist in translation_cache)
- load them if they have not been loaded yet
- write them to cache
- flatten the cache and return
"""
# Get cache for this language
cache = hass.data.setdefault(TRANSLATION_STRING_CACHE, {})
translation_cache = cache.setdefault(language, {})
# Get the set of components to check
components = hass.config.components | await async_get_config_flows(hass)
# Calculate the missing components
missing_components = components - set(translation_cache)
# Calculate the missing components and platforms
missing_loaded = components - set(translation_cache)
missing_domains = {loaded.split(".")[-1] for loaded in missing_loaded}
missing_integrations = dict(
zip(
missing_domains,
await asyncio.gather(
*[async_get_integration(hass, domain) for domain in missing_domains]
),
)
)
# Determine paths of missing components/platforms
missing_files = {}
for component in missing_components:
path = await component_translation_file(hass, component, language)
for loaded in missing_loaded:
parts = loaded.split(".")
domain = parts[-1]
integration = missing_integrations[domain]
path = component_translation_file(loaded, language, integration)
# No translation available
if path is None:
translation_cache[component] = {}
translation_cache[loaded] = {}
else:
missing_files[component] = path
missing_files[loaded] = path
# Load missing files
if missing_files:
@ -134,6 +156,14 @@ async def async_get_component_resources(
assert load_translations_job is not None
loaded_translations = await load_translations_job
# Translations that miss "title" will get integration put in.
for loaded, translations in loaded_translations.items():
if "." in loaded:
continue
if "title" not in translations:
translations["title"] = missing_integrations[loaded].name
# Update cache
translation_cache.update(loaded_translations)

View File

@ -1,12 +1,14 @@
"""Test the translation helper."""
# pylint: disable=protected-access
import asyncio
from os import path
from unittest.mock import patch
import pathlib
from asynctest import Mock, patch
import pytest
from homeassistant.generated import config_flows
import homeassistant.helpers.translation as translation
from homeassistant.loader import async_get_integration
from homeassistant.setup import async_setup_component
from tests.common import mock_coro
@ -43,14 +45,28 @@ async def test_component_translation_file(hass):
assert await async_setup_component(hass, "test_standalone", {"test_standalone"})
assert await async_setup_component(hass, "test_package", {"test_package"})
(
int_test,
int_test_embedded,
int_test_standalone,
int_test_package,
) = await asyncio.gather(
async_get_integration(hass, "test"),
async_get_integration(hass, "test_embedded"),
async_get_integration(hass, "test_standalone"),
async_get_integration(hass, "test_package"),
)
assert path.normpath(
await translation.component_translation_file(hass, "switch.test", "en")
translation.component_translation_file("switch.test", "en", int_test)
) == path.normpath(
hass.config.path("custom_components", "test", ".translations", "switch.en.json")
)
assert path.normpath(
await translation.component_translation_file(hass, "switch.test_embedded", "en")
translation.component_translation_file(
"switch.test_embedded", "en", int_test_embedded
)
) == path.normpath(
hass.config.path(
"custom_components", "test_embedded", ".translations", "switch.en.json"
@ -58,12 +74,14 @@ async def test_component_translation_file(hass):
)
assert (
await translation.component_translation_file(hass, "test_standalone", "en")
translation.component_translation_file(
"test_standalone", "en", int_test_standalone
)
is None
)
assert path.normpath(
await translation.component_translation_file(hass, "test_package", "en")
translation.component_translation_file("test_package", "en", int_test_package)
) == path.normpath(
hass.config.path(
"custom_components", "test_package", ".translations", "en.json"
@ -118,6 +136,8 @@ async def test_get_translations(hass, mock_config_flows):
async def test_get_translations_loads_config_flows(hass, mock_config_flows):
"""Test the get translations helper loads config flow translations."""
mock_config_flows.append("component1")
integration = Mock(file_path=pathlib.Path(__file__))
integration.name = "Component 1"
with patch.object(
translation, "component_translation_file", return_value=mock_coro("bla.json")
@ -125,6 +145,12 @@ async def test_get_translations_loads_config_flows(hass, mock_config_flows):
translation,
"load_translations_files",
return_value={"component1": {"hello": "world"}},
), patch(
"homeassistant.helpers.translation.async_get_integration",
return_value=integration,
):
translations = await translation.async_get_translations(hass, "en")
assert translations == {"component.component1.hello": "world"}
assert translations == {
"component.component1.title": "Component 1",
"component.component1.hello": "world",
}