mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-20 15:46:29 +00:00
Add support for loading add-on translation files (#2644)
* Add support for loading add-on translation files * Fix storing translations for installed add-ons * Allow YAML, force schema * Adjust schema
This commit is contained in:
parent
8d42513ba8
commit
7a542aeb38
@ -54,6 +54,7 @@ from ..const import (
|
|||||||
ATTR_STAGE,
|
ATTR_STAGE,
|
||||||
ATTR_STARTUP,
|
ATTR_STARTUP,
|
||||||
ATTR_STDIN,
|
ATTR_STDIN,
|
||||||
|
ATTR_TANSLATIONS,
|
||||||
ATTR_TIMEOUT,
|
ATTR_TIMEOUT,
|
||||||
ATTR_TMPFS,
|
ATTR_TMPFS,
|
||||||
ATTR_UART,
|
ATTR_UART,
|
||||||
@ -185,6 +186,11 @@ class AddonModel(CoreSysAttributes, ABC):
|
|||||||
"""Return repository of add-on."""
|
"""Return repository of add-on."""
|
||||||
return self.data[ATTR_REPOSITORY]
|
return self.data[ATTR_REPOSITORY]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def translations(self) -> dict:
|
||||||
|
"""Return add-on translations."""
|
||||||
|
return self.data[ATTR_TANSLATIONS]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_version(self) -> AwesomeVersion:
|
def latest_version(self) -> AwesomeVersion:
|
||||||
"""Return latest version of add-on."""
|
"""Return latest version of add-on."""
|
||||||
|
@ -21,6 +21,7 @@ from ..const import (
|
|||||||
ATTR_AUTO_UPDATE,
|
ATTR_AUTO_UPDATE,
|
||||||
ATTR_BOOT,
|
ATTR_BOOT,
|
||||||
ATTR_BUILD_FROM,
|
ATTR_BUILD_FROM,
|
||||||
|
ATTR_CONFIGURATION,
|
||||||
ATTR_DESCRIPTON,
|
ATTR_DESCRIPTON,
|
||||||
ATTR_DEVICES,
|
ATTR_DEVICES,
|
||||||
ATTR_DEVICETREE,
|
ATTR_DEVICETREE,
|
||||||
@ -71,6 +72,7 @@ from ..const import (
|
|||||||
ATTR_STATE,
|
ATTR_STATE,
|
||||||
ATTR_STDIN,
|
ATTR_STDIN,
|
||||||
ATTR_SYSTEM,
|
ATTR_SYSTEM,
|
||||||
|
ATTR_TANSLATIONS,
|
||||||
ATTR_TIMEOUT,
|
ATTR_TIMEOUT,
|
||||||
ATTR_TMPFS,
|
ATTR_TMPFS,
|
||||||
ATTR_UART,
|
ATTR_UART,
|
||||||
@ -343,12 +345,18 @@ SCHEMA_ADDON_USER = vol.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SCHEMA_ADDON_TRANSLATION = vol.Schema(
|
||||||
|
{vol.Optional(ATTR_CONFIGURATION): {str: str}}, extra=vol.REMOVE_EXTRA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
SCHEMA_ADDON_SYSTEM = vol.All(
|
SCHEMA_ADDON_SYSTEM = vol.All(
|
||||||
_migrate_addon_config(),
|
_migrate_addon_config(),
|
||||||
_SCHEMA_ADDON_CONFIG.extend(
|
_SCHEMA_ADDON_CONFIG.extend(
|
||||||
{
|
{
|
||||||
vol.Required(ATTR_LOCATON): str,
|
vol.Required(ATTR_LOCATON): str,
|
||||||
vol.Required(ATTR_REPOSITORY): str,
|
vol.Required(ATTR_REPOSITORY): str,
|
||||||
|
vol.Optional(ATTR_TANSLATIONS, default={}): SCHEMA_ADDON_TRANSLATION,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -82,6 +82,7 @@ from ..const import (
|
|||||||
ATTR_STARTUP,
|
ATTR_STARTUP,
|
||||||
ATTR_STATE,
|
ATTR_STATE,
|
||||||
ATTR_STDIN,
|
ATTR_STDIN,
|
||||||
|
ATTR_TANSLATIONS,
|
||||||
ATTR_UART,
|
ATTR_UART,
|
||||||
ATTR_UDEV,
|
ATTR_UDEV,
|
||||||
ATTR_UPDATE_AVAILABLE,
|
ATTR_UPDATE_AVAILABLE,
|
||||||
@ -265,6 +266,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_SERVICES: _pretty_services(addon),
|
ATTR_SERVICES: _pretty_services(addon),
|
||||||
ATTR_DISCOVERY: addon.discovery,
|
ATTR_DISCOVERY: addon.discovery,
|
||||||
ATTR_IP_ADDRESS: None,
|
ATTR_IP_ADDRESS: None,
|
||||||
|
ATTR_TANSLATIONS: addon.translations,
|
||||||
ATTR_INGRESS: addon.with_ingress,
|
ATTR_INGRESS: addon.with_ingress,
|
||||||
ATTR_INGRESS_ENTRY: None,
|
ATTR_INGRESS_ENTRY: None,
|
||||||
ATTR_INGRESS_URL: None,
|
ATTR_INGRESS_URL: None,
|
||||||
|
@ -109,6 +109,7 @@ ATTR_CHANNEL = "channel"
|
|||||||
ATTR_CHASSIS = "chassis"
|
ATTR_CHASSIS = "chassis"
|
||||||
ATTR_CLI = "cli"
|
ATTR_CLI = "cli"
|
||||||
ATTR_CONFIG = "config"
|
ATTR_CONFIG = "config"
|
||||||
|
ATTR_CONFIGURATION = "configuration"
|
||||||
ATTR_CONNECTED = "connected"
|
ATTR_CONNECTED = "connected"
|
||||||
ATTR_CONNECTIONS = "connections"
|
ATTR_CONNECTIONS = "connections"
|
||||||
ATTR_CONTAINERS = "containers"
|
ATTR_CONTAINERS = "containers"
|
||||||
@ -271,6 +272,7 @@ ATTR_TIMEZONE = "timezone"
|
|||||||
ATTR_TITLE = "title"
|
ATTR_TITLE = "title"
|
||||||
ATTR_TMPFS = "tmpfs"
|
ATTR_TMPFS = "tmpfs"
|
||||||
ATTR_TOTP = "totp"
|
ATTR_TOTP = "totp"
|
||||||
|
ATTR_TANSLATIONS = "translations"
|
||||||
ATTR_TYPE = "type"
|
ATTR_TYPE = "type"
|
||||||
ATTR_UART = "uart"
|
ATTR_UART = "uart"
|
||||||
ATTR_UDEV = "udev"
|
ATTR_UDEV = "udev"
|
||||||
|
@ -6,11 +6,12 @@ from typing import Any, Dict
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from voluptuous.humanize import humanize_error
|
from voluptuous.humanize import humanize_error
|
||||||
|
|
||||||
from ..addons.validate import SCHEMA_ADDON_CONFIG
|
from ..addons.validate import SCHEMA_ADDON_CONFIG, SCHEMA_ADDON_TRANSLATION
|
||||||
from ..const import (
|
from ..const import (
|
||||||
ATTR_LOCATON,
|
ATTR_LOCATON,
|
||||||
ATTR_REPOSITORY,
|
ATTR_REPOSITORY,
|
||||||
ATTR_SLUG,
|
ATTR_SLUG,
|
||||||
|
ATTR_TANSLATIONS,
|
||||||
FILE_SUFFIX_CONFIGURATION,
|
FILE_SUFFIX_CONFIGURATION,
|
||||||
REPOSITORY_CORE,
|
REPOSITORY_CORE,
|
||||||
REPOSITORY_LOCAL,
|
REPOSITORY_LOCAL,
|
||||||
@ -129,6 +130,7 @@ class StoreData(CoreSysAttributes):
|
|||||||
# store
|
# store
|
||||||
addon_config[ATTR_REPOSITORY] = repository
|
addon_config[ATTR_REPOSITORY] = repository
|
||||||
addon_config[ATTR_LOCATON] = str(addon.parent)
|
addon_config[ATTR_LOCATON] = str(addon.parent)
|
||||||
|
addon_config[ATTR_TANSLATIONS] = self._read_addon_translations(addon.parent)
|
||||||
self.addons[addon_slug] = addon_config
|
self.addons[addon_slug] = addon_config
|
||||||
|
|
||||||
def _set_builtin_repositories(self):
|
def _set_builtin_repositories(self):
|
||||||
@ -145,3 +147,29 @@ class StoreData(CoreSysAttributes):
|
|||||||
|
|
||||||
# local repository
|
# local repository
|
||||||
self.repositories[REPOSITORY_LOCAL] = builtin_data[REPOSITORY_LOCAL]
|
self.repositories[REPOSITORY_LOCAL] = builtin_data[REPOSITORY_LOCAL]
|
||||||
|
|
||||||
|
def _read_addon_translations(self, addon_path: Path) -> dict:
|
||||||
|
"""Read translations from add-ons folder."""
|
||||||
|
translations_dir = addon_path / "translations"
|
||||||
|
translations = {}
|
||||||
|
|
||||||
|
if not translations_dir.exists():
|
||||||
|
return translations
|
||||||
|
|
||||||
|
translation_files = [
|
||||||
|
translation
|
||||||
|
for translation in translations_dir.glob("*")
|
||||||
|
if translation.suffix in FILE_SUFFIX_CONFIGURATION
|
||||||
|
]
|
||||||
|
|
||||||
|
for translation in translation_files:
|
||||||
|
try:
|
||||||
|
translations[translation.stem] = SCHEMA_ADDON_TRANSLATION(
|
||||||
|
read_json_or_yaml_file(translation)
|
||||||
|
)
|
||||||
|
|
||||||
|
except (JsonFileError, YamlFileError, vol.Invalid):
|
||||||
|
_LOGGER.warning("Can't read translations from %s", translation)
|
||||||
|
continue
|
||||||
|
|
||||||
|
return translations
|
||||||
|
34
tests/store/test_translation_load.py
Normal file
34
tests/store/test_translation_load.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
"""Test loading add-translation."""
|
||||||
|
# pylint: disable=import-error,protected-access
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
|
from supervisor.coresys import CoreSys
|
||||||
|
|
||||||
|
_YAML = YAML()
|
||||||
|
_YAML.allow_duplicate_keys = True
|
||||||
|
|
||||||
|
|
||||||
|
def test_loading_traslations(coresys: CoreSys, tmp_path):
|
||||||
|
"""Test loading add-translation."""
|
||||||
|
os.makedirs(tmp_path / "translations")
|
||||||
|
# no transaltions
|
||||||
|
assert coresys.store.data._read_addon_translations(tmp_path) == {}
|
||||||
|
|
||||||
|
for file in ("en.json", "es.json"):
|
||||||
|
with open(tmp_path / "translations" / file, "w") as lang_file:
|
||||||
|
lang_file.write(json.dumps({"configuration": {"test": "test"}}))
|
||||||
|
|
||||||
|
for file in ("no.yaml", "de.yaml"):
|
||||||
|
_YAML.dump(
|
||||||
|
{"configuration": {"test": "test"}}, tmp_path / "translations" / file
|
||||||
|
)
|
||||||
|
|
||||||
|
translations = coresys.store.data._read_addon_translations(tmp_path)
|
||||||
|
|
||||||
|
assert translations["en"]["configuration"]["test"] == "test"
|
||||||
|
assert translations["es"]["configuration"]["test"] == "test"
|
||||||
|
assert translations["no"]["configuration"]["test"] == "test"
|
||||||
|
assert translations["de"]["configuration"]["test"] == "test"
|
Loading…
x
Reference in New Issue
Block a user