From 3c029fafdb608f77469b0196c9dc48bc75600c45 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Tue, 4 Feb 2025 14:27:36 -0600 Subject: [PATCH] Translate state name in responses, accounting for English fallback --- .../components/conversation/default_agent.py | 32 ++++++++++++ .../conversation/test_default_agent.py | 52 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/homeassistant/components/conversation/default_agent.py b/homeassistant/components/conversation/default_agent.py index bd7450e5a0f..71a1cd00b04 100644 --- a/homeassistant/components/conversation/default_agent.py +++ b/homeassistant/components/conversation/default_agent.py @@ -810,6 +810,37 @@ class DefaultAgent(ConversationEntity): elif intent_response.unmatched_states: state1 = intent_response.unmatched_states[0] + state1_translated = "" + if state1 is not None: + device_class = state1.attributes.get("device_class", "_") + state_translations = await translation.async_get_translations( + self.hass, language, "state", {state1.domain} + ) + entity_component_translations = await translation.async_get_translations( + self.hass, language, "entity_component", {state1.domain} + ) + + state_key = f"component.{state1.domain}.state.{device_class}.{state1.state}" + entity_component_key = f"component.{state1.domain}.entity_component.{device_class}.state.{state1.state}" + + state_translation = state_translations.get(state_key) + entity_component_translation = entity_component_translations.get( + entity_component_key, state_translation + ) + + if (not state_translation) and entity_component_translation: + # Missing "state._" translation + state1_translated = entity_component_translation + elif state_translation and (not entity_component_translation): + # Missing "entity_component._.state" translation + state1_translated = state_translation + if state_translation and ( + state_translation != entity_component_translation + ): + # Prefer "state._" translation since English is the fallback + # language and doesn't necessarily have it. + state1_translated = state_translation + # Render response template speech_slots = { entity_name: entity_value.text or entity_value.value @@ -827,6 +858,7 @@ class DefaultAgent(ConversationEntity): if state1 is not None else None ), + "state_translated": state1_translated, "query": { # Entity states that matched the query (e.g, "on") "matched": [ diff --git a/tests/components/conversation/test_default_agent.py b/tests/components/conversation/test_default_agent.py index 54aa30b3fcf..4045f9b0c7d 100644 --- a/tests/components/conversation/test_default_agent.py +++ b/tests/components/conversation/test_default_agent.py @@ -3178,3 +3178,55 @@ async def test_state_names_are_not_translated( mock_async_render.call_args.args[0]["state"].state == weather.ATTR_CONDITION_PARTLYCLOUDY ) + + +@pytest.mark.usefixtures("init_components") +async def test_state_translated_slot( + hass: HomeAssistant, + init_components: None, +) -> None: + """Test the state_translated speech slot.""" + await async_setup_component(hass, "weather", {}) + + hass.states.async_set("weather.test_weather", weather.ATTR_CONDITION_PARTLYCLOUDY) + expose_entity(hass, "weather.test_weather", True) + + with patch( + "homeassistant.helpers.template.Template.async_render" + ) as mock_async_render: + result = await conversation.async_converse( + hass, "what is the weather like?", None, Context(), None + ) + assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER + mock_async_render.assert_called_once() + + assert ( + mock_async_render.call_args.args[0]["state_translated"] == "Partly cloudy" + ) + + +@pytest.mark.usefixtures("init_components") +async def test_state_translated_slot_different_system_language( + hass: HomeAssistant, + init_components: None, +) -> None: + """Test the state_translated speech slot when system language is different than pipeline language.""" + assert hass.config.language == "en" + await async_setup_component(hass, "weather", {}) + + hass.states.async_set("weather.test_weather", weather.ATTR_CONDITION_PARTLYCLOUDY) + expose_entity(hass, "weather.test_weather", True) + + with patch( + "homeassistant.helpers.template.Template.async_render" + ) as mock_async_render: + result = await conversation.async_converse( + hass, "wat voor weer is het?", None, Context(), "nl" + ) + assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER + mock_async_render.assert_called_once() + + assert ( + mock_async_render.call_args.args[0]["state_translated"] + == "Gedeeltelijk bewolkt" + )