Support translating entity names (#88242)

This commit is contained in:
Erik Montnemery 2023-03-12 15:55:04 +01:00 committed by GitHub
parent 376a6eb82a
commit cf7e500a8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 40 additions and 3 deletions

View file

@ -1003,6 +1003,10 @@ jobs:
run: |
. venv/bin/activate
pip install mysqlclient sqlalchemy_utils
- name: Compile English translations
run: |
. venv/bin/activate
python3 -m script.translations develop --all
- name: Run pytest (partially)
timeout-minutes: 20
shell: bash
@ -1107,6 +1111,10 @@ jobs:
run: |
. venv/bin/activate
pip install psycopg2 sqlalchemy_utils
- name: Compile English translations
run: |
. venv/bin/activate
python3 -m script.translations develop --all
- name: Run pytest (partially)
timeout-minutes: 20
shell: bash

View file

@ -126,7 +126,7 @@ async def async_setup_platform(
),
DemoSensor(
unique_id="sensor_10",
name="Thermostat mode",
name=None,
state="eco",
device_class=SensorDeviceClass.ENUM,
state_class=None,
@ -156,7 +156,7 @@ class DemoSensor(SensorEntity):
def __init__(
self,
unique_id: str,
name: str,
name: str | None,
state: StateType,
device_class: SensorDeviceClass,
state_class: SensorStateClass | None,
@ -167,7 +167,10 @@ class DemoSensor(SensorEntity):
) -> None:
"""Initialize the sensor."""
self._attr_device_class = device_class
if name is not None:
self._attr_name = name
else:
self._attr_has_entity_name = True
self._attr_native_unit_of_measurement = unit_of_measurement
self._attr_native_value = state
self._attr_state_class = state_class

View file

@ -98,6 +98,7 @@
},
"sensor": {
"thermostat_mode": {
"name": "Thermostat mode",
"state": {
"away": "Away",
"comfort": "Comfort",

View file

@ -319,6 +319,15 @@ class Entity(ABC):
"""Return the name of the entity."""
if hasattr(self, "_attr_name"):
return self._attr_name
if self.translation_key is not None and self.has_entity_name:
assert self.platform
name_translation_key = (
f"component.{self.platform.platform_name}.entity.{self.platform.domain}"
f".{self.translation_key}.name"
)
if name_translation_key in self.platform.entity_translations:
name: str = self.platform.entity_translations[name_translation_key]
return name
if hasattr(self, "entity_description"):
return self.entity_description.name
return None

View file

@ -39,6 +39,7 @@ from . import (
device_registry as dev_reg,
entity_registry as ent_reg,
service,
translation,
)
from .device_registry import DeviceRegistry
from .entity_registry import EntityRegistry, RegistryEntryDisabler, RegistryEntryHider
@ -124,6 +125,7 @@ class EntityPlatform:
self.entity_namespace = entity_namespace
self.config_entry: config_entries.ConfigEntry | None = None
self.entities: dict[str, Entity] = {}
self.entity_translations: dict[str, Any] = {}
self._tasks: list[asyncio.Task[None]] = []
# Stop tracking tasks after setup is completed
self._setup_complete = False
@ -276,6 +278,15 @@ class EntityPlatform:
hass = self.hass
full_name = f"{self.domain}.{self.platform_name}"
try:
self.entity_translations = await translation.async_get_translations(
hass, hass.config.language, "entity", {self.platform_name}
)
except Exception as err: # pylint: disable=broad-exception-caught
_LOGGER.debug(
"Could not load translations for %s", self.platform_name, exc_info=err
)
logger.info("Setting up %s", full_name)
warn_task = hass.loop.call_later(
SLOW_SETUP_WARNING,

View file

@ -286,6 +286,7 @@ def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema:
vol.Optional("entity"): {
str: {
str: {
vol.Optional("name"): cv.string_with_no_html,
vol.Optional("state_attributes"): {
str: {
vol.Optional("name"): cv.string_with_no_html,

View file

@ -214,6 +214,7 @@ async def test_setup_get_template_headers_params(hass: HomeAssistant) -> None:
},
)
await async_setup_component(hass, "homeassistant", {})
await hass.async_block_till_done()
assert respx.calls.last.request.headers["Accept"] == CONTENT_TYPE_JSON
assert respx.calls.last.request.headers["User-Agent"] == "Mozilla/5.0"

View file

@ -318,6 +318,7 @@ async def test_setup_get_templated_headers_params(hass: HomeAssistant) -> None:
},
)
await async_setup_component(hass, "homeassistant", {})
await hass.async_block_till_done()
assert respx.calls.last.request.headers["Accept"] == CONTENT_TYPE_JSON
assert respx.calls.last.request.headers["User-Agent"] == "Mozilla/5.0"

View file

@ -4748,5 +4748,7 @@ async def test_exclude_attributes(recorder_mock: Recorder, hass: HomeAssistant)
states: list[State] = await hass.async_add_executor_job(_fetch_states)
assert len(states) > 1
for state in states:
if state.domain != DOMAIN:
continue
assert ATTR_OPTIONS not in state.attributes
assert ATTR_FRIENDLY_NAME in state.attributes