Icon translations #980
-
ContextWe just love Material Design Icons. ❤️ Really, we do. TL;DR: Icons are defined in many places, frontend, backend, and on the integration level. It is all over the place. We use them everywhere! For example, we use them on entities and, if implemented by the integration, the state of entities. We also have defaults in some instances if there is a device class, and even those can be state-sensitive. However, in this case, they are not defined in the integration but mainly by the frontend. That is not all the frontend does; it also has defaults for domains, and sometimes... even more magic. Did you know the frontend will handle adding an icon if, for example, a climate preset "Home" is seen? This screenshot is odd; in this case, not all presets of my thermostat are known by the frontend. But, adding/defining icons from the backend isn't possible. Talking about defining them from the backend: Integrations regularly add logic to the backend to make icons more dynamic. The most common examples are found in binary sensors: having different icons for "on" versus "off" and they do so by implementing logic in the icon property. @property
def icon(self) -> str:
"""Return WiFi status sensor icon."""
return "mdi:wifi" if self.is_on else "mdi:wifi-off" So, for the context, icons are everywhere. Which is not directly problematic, but it isn't pretty either. That said, there is one place that is affected by this unneeded: The state machine. I want to address this and propose a solution using this architectural proposal. ProposalTL;DR: Introduce an Introduce icon translations. I suggest creating an file that can be defined in each integration (including entity components) called: These work pretty much like our normal string translation files, the difference is that this will translate it to MDI icons, and of course, will not have the different languages. Here is an example of an {
"entity": {
"sensor": {
"phase": {
"default": "mdi:moon",
"state": {
"new_moon": "mdi:moon-new",
"first_quarter": "mdi:moon-first-quarter",
"full_moon": "mdi:moon-full",
"last_quarter": "mdi:moon-last-quarter"
}
}
}
}
} Ref: https://developers.home-assistant.io/docs/internationalization/core#state-of-entities Different/new in this structure is the Entity state attributesEntity state attributes can be translated as well. Climate presets, as provided in the context of this proposal, are a good example. But we could also add icons to things like select entities (input_select maybe even in the future) and provide button-like interfaces in our Tile cards. {
"entity": {
"climate": {
"ubercool": {
"state_attributes": {
"preset_mode": {
"default": "mdi:confused",
"state": {
"vacation": "mdi:umbrella-beach",
"night": "mdi:weather-night"
}
}
}
}
}
}
} Ref: https://developers.home-assistant.io/docs/internationalization/core#entity-state-attributes Entity componentsEntity components are providing the defaults. Include the defaults per device class, and even state attributes. Again, this is the same as we currently do for translations. {
"entity_component": {
"_": {
"default": "mdi:circle",
"state": {
"off": "mdi:off",
"on": "mdi:on"
}
},
"problem": {
"state": {
"off": "mdi:off",
"on": "mdi:alert"
}
}
}
} The The Ref: https://developers.home-assistant.io/docs/internationalization/core#state-of-entity-components Sharing translation keysAll of this would need translation keys. In the first example of the moon integration, the translation key was "phase". The suggestion is not to introduce a new translation key, but to share the icon translation key with the strings translation key. Reference other icon translationsOur translation have a way to reference other strings. For example, we re-use translations using a syntax that looks like this:
The proposal is not to bring this logic to the icon translations. ValidationA nice future expansion that this proposal makes easily possible is to validate that used icons exist. This can be done by adding a script to hassfest that checks this for every PR and commit. ConsequencesThere are not many consequences, but let's list them:
What will happen with all the old stuff?We will keep supporting implementing the icon property method on integrations. These are still useful for some dynamic cases that need more complex. Also, we need to keep them around for backward-compatible purposes. Okay, so there are multiple ways to define it. Which wins?Good question! Really, again, it's not that different from translations. This is the suggested priority, where the first matching one wins:
Other considered alternatives
Note: Many used icons in the examples do not exist. That is fine, it is just an example 😉 |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 6 replies
-
1 more thing to consider: There are 2 ways of loading icons in the frontend, all the default domain and state icons SVG's are currently inlined in the code. For all other icons, that are provided by the integration or the user in the format I would love to have a way to make the default state icons still be super quick, and not having to go through the database. |
Beta Was this translation helpful? Give feedback.
-
Would be nice to have some core wide defaults for common states, like home/not home for device trackers from routers. @property
def icon(self) -> str:
"""Return device icon."""
if self.is_connected:
return "mdi:lan-connect"
return "mdi:lan-disconnect" but not all. |
Beta Was this translation helpful? Give feedback.
-
This proposal has been discussed on several occasions and meetings, it has been supported widely, and no other objects or concerns have been raised. The plan is to move forward with the implementation. |
Beta Was this translation helpful? Give feedback.
-
Merged in home-assistant/core#103294 Dev blog: https://developers.home-assistant.io/blog/2024/01/19/icon-translations/ |
Beta Was this translation helpful? Give feedback.
This proposal has been discussed on several occasions and meetings, it has been supported widely, and no other objects or concerns have been raised.
The plan is to move forward with the implementation.