Custom Templates

Piotr, hi.
Smth strange is happening in 2023.9.2 (may be happened earlier…)
This works:

Translated en: {{ "sun.sun" | ct_state_translated("en") }}
Translated ru: {{ "sun.sun" | ct_state_translated("ru") }}

but this does not:

Translated en: {{ ct_state_translated("sun.sun", "en") }}
Translated ru: {{ ct_state_translated("sun.sun", "ru") }}

Same for ct_translated:

Same for ct_state_attr_translated:

Also ct_all_translations - does not work:

For ct_eval - none of variants works:

Now the interesting part.
All this things work in Markdown:

State: {{ states("sun.sun") }}
Translated en: {{ ct_state_translated("sun.sun", "en") }}
Translated en: {{ "sun.sun" | ct_state_translated("en") }}
Translated ru: {{ ct_state_translated("sun.sun", "ru") }}
Translated ru: {{ "sun.sun" | ct_state_translated("ru") }}

Attribute: {{ state_attr("automation.test", "mode") }}
Translated en: {{ ct_state_attr_translated("automation.test", "mode", "en") }}
Translated en: {{ "automation.test" | ct_state_attr_translated("mode", "en") }}
Translated ru: {{ ct_state_attr_translated("automation.test", "mode", "ru") }}
Translated u: {{ "automation.test" | ct_state_attr_translated("mode", "ru") }}

Translated en: {{ ct_translated("component.sun.entity_component._.state.below_horizon", "en") }}
Translated en: {{ "component.sun.entity_component._.state.below_horizon" | ct_translated("en") }}
Translated ru: {{ ct_translated("component.sun.entity_component._.state.below_horizon", "ru") }}
Translated ru: {{ "component.sun.entity_component._.state.below_horizon" | ct_translated("ru") }}

{% set template_text = "{{ states('sun.sun') }}" -%}
{{ ct_eval(template_text) }}
{{ template_text | ct_eval }}

I did not put a code with ct_all_translations - output is too large.

So, the plugin partly does not work in Dev tools → Template, but seems to work in Markdown.

Please create an issue with your findings, that’s a really weird behavior

Fixed in v1.2.2

Piotr, thank you!
Seems to be OK:

1 Like

Piotr, any official news regarding adding your work into the Core?
Seems that this is your PR.

Yup, it has been merged, so it should be included in HA 2024.3

1 Like

Piotr, still using your original plugin in 2024.3 since the recently added “state_translated” function only works with a current system language. In some cases it is needed to have a translation for a different language.
Any chance the added function will allow using a different language?

It was my first approach, but the problem was more on the architectural side - to not add additional configurations (especially yaml). A list of languages has to be known at the start of HA - to load appropriate translations to cache.

1 Like

I still using you original plugin in 2024.3 too, because there is no translation for attributes?

Please add attribute translation soon.

Thanks, Steffen

I plan to, but wanted to add states first :+1:

1 Like

As requested, here’s a real life example for dict_merge.

For a lot of my sensor attributes, I will use a for loop to create a dictionary. Currently, that ends up involving me creating a list of items (eg, ['a',1]) and then adding that to the list. This is rather cumbersome and often ends up confusing.

Here’s the first example I found.

I use the Grocy integration to track my chores for my wife and I. I’ve added the ability to create and edit the chores in Grocy via HA along with marking chores off on an ESPHome based display.

The data itself is presented as a list of dictionaries, though. Since each dictionary has two unique items in it (the name and ID), it made more sense for the data to be arranged as a dictionary which would allow me to create automations that can quickly go through the data.

Here’s some example input data from the Grocy sensor:

    "id": 4,
    "name": "Clean Living Room",
    "description": null,
    "period_type": "weekly",
    "period_config": "saturday",
    "period_days": 1,
    "track_date_only": true,
    "rollover": false,
    "assignment_type": "in-alphabetical-order",
    "assignment_config": "2,3",
    "next_execution_assigned_to_user_id": 2,
    "userfields": null,
    "last_tracked_time": "2024-03-23T00:00:00",
    "next_estimated_execution_time": "2024-03-30T23:59:59",
    "last_done_by": {
      "id": 3,
      "username": "monica",
      "first_name": "Monica",
      "last_name": "Carroll",
      "display_name": "Monica Carroll"
    "track_count": 0,
    "next_execution_assigned_user": {
      "id": 2,
      "username": "michael",
      "first_name": "Michael",
      "last_name": "Carroll",
      "display_name": "Michael Carroll"

To change this to a dict ordered by the ID, I’m currently using:

{% set chores = state_attr('sensor.grocy_chores','chores') %}
{% set ns = namespace(chores=[]) %}
{% for chore in chores %}
  {% set tmp = [chore.get('id'), chore] %}
  {% set ns.chores = ns.chores + [tmp] %}
{% endfor %}
{{ dict.from_items(ns.chores) }}

With ct_dict_merge, I instead can use:

{% set chores = state_attr('sensor.grocy_chores','chores') %}
{% set ns = namespace(chores={}) %}
{% for chore in chores %}
  {% set tmp = {chore.get('id'): chore} %}
  {% set ns.chores = ct_dict_merge(ns.chores, tmp) %}
{% endfor %}
{{ ns.chores }}

dict.from_items is rather an anti-pattern. It requires you to remember that each item inside the list is a list of two items, the first being the key and the second being the item itself. It also does not adjust the subitems; if one key has a value which should be a nested dictionary, you need to remember to turn it into a dictionary before adding it to the list.

ct_dict_merge is more straightforward. It takes two or more dictionaries and turns them into a single dictionary. You’re always working with the correct data type and don’t need to convert them just to work with it.

If you are just combining dictionaries, you don’t need to convert the items into lists, join them, and then convert back into a dictionary. You can just merge them.

1 Like

To fix compatibility with new Home Assistant versions you have to update to the latest release. Without this update integration will not work.