1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-26 14:08:21 +00:00

Add foundation for state translations (#34443)

This commit is contained in:
Paulus Schoutsen
2020-04-19 20:35:49 -07:00
committed by GitHub
parent 75e5f085d3
commit 4720a7a891
13 changed files with 225 additions and 89 deletions

View File

@@ -7,6 +7,9 @@ from typing import Dict
import voluptuous as vol
from voluptuous.humanize import humanize_error
import homeassistant.helpers.config_validation as cv
from homeassistant.util import slugify
from .model import Config, Integration
_LOGGER = logging.getLogger(__name__)
@@ -88,7 +91,9 @@ def gen_strings_schema(config: Config, integration: Integration):
vol.Optional("trigger_type"): {str: str},
vol.Optional("trigger_subtype"): {str: str},
},
vol.Optional("state"): {str: str},
vol.Optional("state"): cv.schema_with_slug_keys(
cv.schema_with_slug_keys(str)
),
}
)
@@ -109,6 +114,33 @@ def gen_auth_schema(config: Config, integration: Integration):
)
def gen_platform_strings_schema(config: Config, integration: Integration):
"""Generate platform strings schema like strings.sensor.json."""
def device_class_validator(value):
"""Key validator."""
if not value.startswith(f"{integration.domain}__"):
raise vol.Invalid(
f"Device class need to start with '{integration.domain}__'. Key {value} is invalid"
)
slug_friendly = value.replace("__", "_", 1)
slugged = slugify(slug_friendly)
if slug_friendly != slugged:
raise vol.Invalid(f"invalid device class {value}")
return value
return vol.Schema(
{
vol.Optional("state"): cv.schema_with_slug_keys(
cv.schema_with_slug_keys(str), slug_validator=device_class_validator
)
}
)
ONBOARDING_SCHEMA = vol.Schema({vol.Required("area"): {str: str}})
@@ -116,24 +148,35 @@ def validate_translation_file(config: Config, integration: Integration):
"""Validate translation files for integration."""
strings_file = integration.path / "strings.json"
if not strings_file.is_file():
return
if strings_file.is_file():
strings = json.loads(strings_file.read_text())
strings = json.loads(strings_file.read_text())
if integration.domain == "auth":
schema = gen_auth_schema(config, integration)
elif integration.domain == "onboarding":
schema = ONBOARDING_SCHEMA
else:
schema = gen_strings_schema(config, integration)
if integration.domain == "auth":
schema = gen_auth_schema(config, integration)
elif integration.domain == "onboarding":
schema = ONBOARDING_SCHEMA
else:
schema = gen_strings_schema(config, integration)
try:
schema(strings)
except vol.Invalid as err:
integration.add_error(
"translations", f"Invalid strings.json: {humanize_error(strings, err)}"
)
try:
schema(strings)
except vol.Invalid as err:
integration.add_error(
"translations", f"Invalid strings.json: {humanize_error(strings, err)}"
)
for path in integration.path.glob("strings.*.json"):
strings = json.loads(path.read_text())
schema = gen_platform_strings_schema(config, integration)
try:
schema(strings)
except vol.Invalid as err:
msg = f"Invalid {path.name}: {humanize_error(strings, err)}"
if config.specific_integrations:
integration.add_warning("translations", msg)
else:
integration.add_error("translations", msg)
def validate(integrations: Dict[str, Integration], config: Config):

View File

@@ -3,11 +3,10 @@ from pprint import pprint
import requests
from .const import CORE_PROJECT_ID
from .util import get_lokalise_token
def get_api(project_id=CORE_PROJECT_ID, debug=False) -> "Lokalise":
def get_api(project_id, debug=False) -> "Lokalise":
"""Get Lokalise API."""
return Lokalise(project_id, get_lokalise_token(), debug)

View File

@@ -11,29 +11,38 @@ def create_lookup(results):
return {key["key_name"]["web"]: key for key in results}
def rename_keys(to_migrate):
def rename_keys(project_id, to_migrate):
"""Rename keys.
to_migrate is Dict[from_key] = to_key.
"""
updates = []
lokalise = get_api()
lokalise = get_api(project_id)
from_key_data = lokalise.keys_list({"filter_keys": ",".join(to_migrate)})
if len(from_key_data) != len(to_migrate):
print(
f"Lookin up keys in Lokalise returns {len(from_key_data)} results, expected {len(to_migrate)}"
)
return
from_key_lookup = create_lookup(from_key_data)
print("Gathering IDs")
for from_key, to_key in to_migrate.items():
key_data = lokalise.keys_list({"filter_keys": from_key})
if len(key_data) != 1:
print(
f"Lookin up {from_key} key in Lokalise returns {len(key_data)} results, expected 1"
)
continue
updates.append({"key_id": key_data[0]["key_id"], "key_name": to_key})
updates.append(
{"key_id": from_key_lookup[from_key]["key_id"], "key_name": to_key}
)
pprint(updates)
print()
while input("Type YES to confirm: ") != "YES":
pass
return
print()
print("Updating keys")
pprint(lokalise.keys_bulk_update(updates).json())
@@ -123,7 +132,7 @@ def find_and_rename_keys():
to_key = f"component::{integration.name}::title"
to_migrate[from_key] = to_key
rename_keys(to_migrate)
rename_keys(CORE_PROJECT_ID, to_migrate)
def find_different_languages():
@@ -163,6 +172,22 @@ def interactive_update():
def run():
"""Migrate translations."""
interactive_update()
rename_keys(
CORE_PROJECT_ID,
{
"component::moon::platform::sensor::state::new_moon": "component::moon::platform::sensor::state::moon__phase::new_moon",
"component::moon::platform::sensor::state::waxing_crescent": "component::moon::platform::sensor::state::moon__phase::waxing_crescent",
"component::moon::platform::sensor::state::first_quarter": "component::moon::platform::sensor::state::moon__phase::first_quarter",
"component::moon::platform::sensor::state::waxing_gibbous": "component::moon::platform::sensor::state::moon__phase::waxing_gibbous",
"component::moon::platform::sensor::state::full_moon": "component::moon::platform::sensor::state::moon__phase::full_moon",
"component::moon::platform::sensor::state::waning_gibbous": "component::moon::platform::sensor::state::moon__phase::waning_gibbous",
"component::moon::platform::sensor::state::last_quarter": "component::moon::platform::sensor::state::moon__phase::last_quarter",
"component::moon::platform::sensor::state::waning_crescent": "component::moon::platform::sensor::state::moon__phase::waning_crescent",
"component::season::platform::sensor::state::spring": "component::season::platform::sensor::state::season__season__::spring",
"component::season::platform::sensor::state::summer": "component::season::platform::sensor::state::season__season__::summer",
"component::season::platform::sensor::state::autumn": "component::season::platform::sensor::state::season__season__::autumn",
"component::season::platform::sensor::state::winter": "component::season::platform::sensor::state::season__season__::winter",
},
)
return 0