diff --git a/homeassistant/components/google_assistant_sdk/__init__.py b/homeassistant/components/google_assistant_sdk/__init__.py index b92b3c54579..4ea496f2824 100644 --- a/homeassistant/components/google_assistant_sdk/__init__.py +++ b/homeassistant/components/google_assistant_sdk/__init__.py @@ -26,11 +26,18 @@ from homeassistant.helpers.config_entry_oauth2_flow import ( ) from homeassistant.helpers.typing import ConfigType -from .const import DATA_MEM_STORAGE, DATA_SESSION, DOMAIN, SUPPORTED_LANGUAGE_CODES +from .const import ( + CONF_LANGUAGE_CODE, + DATA_MEM_STORAGE, + DATA_SESSION, + DOMAIN, + SUPPORTED_LANGUAGE_CODES, +) from .helpers import ( GoogleAssistantSDKAudioView, InMemoryStorage, async_send_text_commands, + best_matching_language_code, ) SERVICE_SEND_TEXT_COMMAND = "send_text_command" @@ -164,9 +171,16 @@ class GoogleAssistantConversationAgent(conversation.AbstractConversationAgent): if not session.valid_token: await session.async_ensure_token_valid() self.assistant = None - if not self.assistant or user_input.language != self.language: + + language = best_matching_language_code( + self.hass, + user_input.language, + self.entry.options.get(CONF_LANGUAGE_CODE), + ) + + if not self.assistant or language != self.language: credentials = Credentials(session.token[CONF_ACCESS_TOKEN]) # type: ignore[no-untyped-call] - self.language = user_input.language + self.language = language self.assistant = TextAssistant(credentials, self.language) resp = await self.hass.async_add_executor_job( @@ -174,7 +188,7 @@ class GoogleAssistantConversationAgent(conversation.AbstractConversationAgent): ) text_response = resp[0] or "" - intent_response = intent.IntentResponse(language=user_input.language) + intent_response = intent.IntentResponse(language=language) intent_response.async_set_speech(text_response) return conversation.ConversationResult( response=intent_response, conversation_id=user_input.conversation_id diff --git a/homeassistant/components/google_assistant_sdk/helpers.py b/homeassistant/components/google_assistant_sdk/helpers.py index 24da381e8e0..f9d332cd735 100644 --- a/homeassistant/components/google_assistant_sdk/helpers.py +++ b/homeassistant/components/google_assistant_sdk/helpers.py @@ -113,6 +113,33 @@ def default_language_code(hass: HomeAssistant) -> str: return DEFAULT_LANGUAGE_CODES.get(hass.config.language, "en-US") +def best_matching_language_code( + hass: HomeAssistant, assist_language: str, agent_language: str | None = None +) -> str: + """Get the best matching language, based on the preferred assist language and the configured agent language.""" + + # Use the assist language if supported + if assist_language in SUPPORTED_LANGUAGE_CODES: + return assist_language + language = assist_language.split("-")[0] + + # Use the agent language if assist and agent start with the same language part + if agent_language is not None and agent_language.startswith(language): + return best_matching_language_code(hass, agent_language) + + # If assist and agent are not matching, try to find the default language + default_language = DEFAULT_LANGUAGE_CODES.get(language) + if default_language is not None: + return default_language + + # If no default agent is available, use the agent language + if agent_language is not None: + return best_matching_language_code(hass, agent_language) + + # Fallback to the system default language + return default_language_code(hass) + + class InMemoryStorage: """Temporarily store and retrieve data from in memory storage.""" diff --git a/tests/components/google_assistant_sdk/test_helpers.py b/tests/components/google_assistant_sdk/test_helpers.py index 1090eb9da45..4632a86f40f 100644 --- a/tests/components/google_assistant_sdk/test_helpers.py +++ b/tests/components/google_assistant_sdk/test_helpers.py @@ -3,6 +3,7 @@ from homeassistant.components.google_assistant_sdk.const import SUPPORTED_LANGUAGE_CODES from homeassistant.components.google_assistant_sdk.helpers import ( DEFAULT_LANGUAGE_CODES, + best_matching_language_code, default_language_code, ) from homeassistant.core import HomeAssistant @@ -46,3 +47,42 @@ def test_default_language_code(hass: HomeAssistant) -> None: hass.config.language = "el" hass.config.country = "GR" assert default_language_code(hass) == "en-US" + + +def test_best_matching_language_code(hass: HomeAssistant) -> None: + """Test best_matching_language_code.""" + hass.config.language = "es" + hass.config.country = "MX" + + # Assist Language is supported + assert best_matching_language_code(hass, "de-DE", "en-AU") == "de-DE" + assert best_matching_language_code(hass, "de-DE") == "de-DE" + + # Assist Language is not supported, but agent language has the same "lang" part, and is supported + assert best_matching_language_code(hass, "en", "en-AU") == "en-AU" + assert best_matching_language_code(hass, "en-XYZ", "en-AU") == "en-AU" + # Assist Language is not supported, but agent language has the same "lang" part, but is not supported + assert best_matching_language_code(hass, "en", "en-XYZ") == "en-US" + assert best_matching_language_code(hass, "en-XYZ", "en-ABC") == "en-US" + + # Assist Language is not supported, agent is not matching or available, falling back to the default of assist lang + assert best_matching_language_code(hass, "de", "en-AU") == "de-DE" + assert best_matching_language_code(hass, "de-XYZ", "en-AU") == "de-DE" + assert best_matching_language_code(hass, "de") == "de-DE" + assert best_matching_language_code(hass, "de-XYZ") == "de-DE" + + # Assist language is not existing at all, agent is supported + assert best_matching_language_code(hass, "abc-XYZ", "en-AU") == "en-AU" + + # Assist language is not existing at all, agent is not supported, falling back to the agent default + assert best_matching_language_code(hass, "abc-XYZ", "de-XYZ") == "de-DE" + + # Assist language is not existing at all, agent is not existing or available, falling back to system default + assert best_matching_language_code(hass, "abc-XYZ", "def-XYZ") == "es-MX" + assert best_matching_language_code(hass, "abc-XYZ") == "es-MX" + + # Assist language is not existing at all, agent is not existing or available, system default is not supported + hass.config.language = "el" + hass.config.country = "GR" + assert best_matching_language_code(hass, "abc-XYZ", "def-XYZ") == "en-US" + assert best_matching_language_code(hass, "abc-XYZ") == "en-US"