Skip to content

Commit

Permalink
Merge pull request #32 from jdejaegh/language-picker
Browse files Browse the repository at this point in the history
Add language picker to override default Home Assistant language in the integration
  • Loading branch information
jdejaegh committed May 24, 2024
2 parents 92d4084 + 6bc5489 commit 4decfe7
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 39 deletions.
9 changes: 7 additions & 2 deletions custom_components/irm_kmi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryError

from .const import (CONF_DARK_MODE, CONF_STYLE, CONF_USE_DEPRECATED_FORECAST,
CONFIG_FLOW_VERSION, DOMAIN,
from .const import (CONF_DARK_MODE, CONF_LANGUAGE_OVERRIDE, CONF_STYLE,
CONF_USE_DEPRECATED_FORECAST, CONFIG_FLOW_VERSION, DOMAIN,
OPTION_DEPRECATED_FORECAST_NOT_USED, OPTION_STYLE_STD,
PLATFORMS)
from .coordinator import IrmKmiCoordinator
Expand Down Expand Up @@ -68,6 +68,11 @@ async def async_migrate_entry(hass, config_entry: ConfigEntry):
config_entry.version = 3
hass.config_entries.async_update_entry(config_entry, data=new)

if config_entry.version == 3:
new = new | {CONF_LANGUAGE_OVERRIDE: None}
config_entry.version = 4
hass.config_entries.async_update_entry(config_entry, data=new)

_LOGGER.debug(f"Migration to version {config_entry.version} successful")

return True
26 changes: 20 additions & 6 deletions custom_components/irm_kmi/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
SelectSelectorMode)

from .api import IrmKmiApiClient
from .const import (CONF_DARK_MODE, CONF_STYLE, CONF_STYLE_OPTIONS,
CONF_USE_DEPRECATED_FORECAST,
from .const import (CONF_DARK_MODE, CONF_LANGUAGE_OVERRIDE,
CONF_LANGUAGE_OVERRIDE_OPTIONS, CONF_STYLE,
CONF_STYLE_OPTIONS, CONF_USE_DEPRECATED_FORECAST,
CONF_USE_DEPRECATED_FORECAST_OPTIONS, CONFIG_FLOW_VERSION,
DOMAIN, OPTION_DEPRECATED_FORECAST_NOT_USED,
OPTION_STYLE_STD, OUT_OF_BENELUX)
Expand Down Expand Up @@ -49,7 +50,7 @@ async def async_step_user(self, user_input: dict | None = None) -> FlowResult:
if not errors:
api_data = {}
try:
async with async_timeout.timeout(10):
async with async_timeout.timeout(60):
api_data = await IrmKmiApiClient(
session=async_get_clientsession(self.hass)).get_forecasts_coord(
{'lat': zone.attributes[ATTR_LATITUDE],
Expand All @@ -71,7 +72,8 @@ async def async_step_user(self, user_input: dict | None = None) -> FlowResult:
data={CONF_ZONE: user_input[CONF_ZONE],
CONF_STYLE: user_input[CONF_STYLE],
CONF_DARK_MODE: user_input[CONF_DARK_MODE],
CONF_USE_DEPRECATED_FORECAST: user_input[CONF_USE_DEPRECATED_FORECAST]},
CONF_USE_DEPRECATED_FORECAST: user_input[CONF_USE_DEPRECATED_FORECAST],
CONF_LANGUAGE_OVERRIDE: user_input[CONF_LANGUAGE_OVERRIDE]},
)

return self.async_show_form(
Expand All @@ -92,7 +94,12 @@ async def async_step_user(self, user_input: dict | None = None) -> FlowResult:
vol.Optional(CONF_USE_DEPRECATED_FORECAST, default=OPTION_DEPRECATED_FORECAST_NOT_USED):
SelectSelector(SelectSelectorConfig(options=CONF_USE_DEPRECATED_FORECAST_OPTIONS,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_USE_DEPRECATED_FORECAST))
translation_key=CONF_USE_DEPRECATED_FORECAST)),

vol.Optional(CONF_LANGUAGE_OVERRIDE, default='none'):
SelectSelector(SelectSelectorConfig(options=CONF_LANGUAGE_OVERRIDE_OPTIONS,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_LANGUAGE_OVERRIDE))

}))

Expand All @@ -105,6 +112,7 @@ def __init__(self, config_entry: ConfigEntry) -> None:
async def async_step_init(self, user_input: dict | None = None) -> FlowResult:
"""Manage the options."""
if user_input is not None:
_LOGGER.debug(user_input)
return self.async_create_entry(data=user_input)

return self.async_show_form(
Expand All @@ -122,7 +130,13 @@ async def async_step_init(self, user_input: dict | None = None) -> FlowResult:
default=get_config_value(self.config_entry, CONF_USE_DEPRECATED_FORECAST)):
SelectSelector(SelectSelectorConfig(options=CONF_USE_DEPRECATED_FORECAST_OPTIONS,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_USE_DEPRECATED_FORECAST))
translation_key=CONF_USE_DEPRECATED_FORECAST)),

vol.Optional(CONF_LANGUAGE_OVERRIDE,
default=get_config_value(self.config_entry, CONF_LANGUAGE_OVERRIDE)):
SelectSelector(SelectSelectorConfig(options=CONF_LANGUAGE_OVERRIDE_OPTIONS,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_LANGUAGE_OVERRIDE))
}
),
)
8 changes: 7 additions & 1 deletion custom_components/irm_kmi/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

DOMAIN: Final = 'irm_kmi'
PLATFORMS: Final = [Platform.WEATHER, Platform.CAMERA, Platform.BINARY_SENSOR, Platform.SENSOR]
CONFIG_FLOW_VERSION = 3
CONFIG_FLOW_VERSION = 4

OUT_OF_BENELUX: Final = ["außerhalb der Benelux (Brussels)",
"Hors de Belgique (Bxl)",
Expand Down Expand Up @@ -58,6 +58,12 @@
OPTION_DEPRECATED_FORECAST_HOURLY
]

CONF_LANGUAGE_OVERRIDE: Final = 'language_override'

CONF_LANGUAGE_OVERRIDE_OPTIONS: Final = [
'none', "fr", "nl", "de", "en"
]

REPAIR_SOLUTION: Final = "repair_solution"
REPAIR_OPT_MOVE: Final = "repair_option_move"
REPAIR_OPT_DELETE: Final = "repair_option_delete"
Expand Down
9 changes: 5 additions & 4 deletions custom_components/irm_kmi/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
ProcessedCoordinatorData, RadarAnimationData, WarningData)
from .pollen import PollenParser
from .rain_graph import RainGraph
from .utils import disable_from_config, get_config_value
from .utils import disable_from_config, get_config_value, preferred_language

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -128,7 +128,7 @@ async def _async_animation_data(self, api_data: dict) -> RadarAnimationData:
localisation = images_from_api[0]
images_from_api = images_from_api[1:]

lang = self.hass.config.language if self.hass.config.language in LANGS else 'en'
lang = preferred_language(self.hass, self._config_entry)
radar_animation = RadarAnimationData(
hint=api_data.get('animation', {}).get('sequenceHint', {}).get(lang),
unit=api_data.get('animation', {}).get('unit', {}).get(lang),
Expand Down Expand Up @@ -340,6 +340,7 @@ def daily_list_to_forecast(self, data: List[dict] | None) -> List[Forecast] | No

forecasts = list()
n_days = 0
lang = preferred_language(self.hass, self._config_entry)

for (idx, f) in enumerate(data):
precipitation = None
Expand Down Expand Up @@ -377,7 +378,7 @@ def daily_list_to_forecast(self, data: List[dict] | None) -> List[Forecast] | No
precipitation_probability=f.get('precipChance', None),
wind_bearing=wind_bearing,
is_daytime=is_daytime,
text=f.get('text', {}).get(self.hass.config.language, ""),
text=f.get('text', {}).get(lang, ""),
)
# Swap temperature and templow if needed
if (forecast['native_templow'] is not None
Expand Down Expand Up @@ -441,6 +442,7 @@ def warnings_from_data(self, warning_data: list | None) -> List[WarningData]:
if warning_data is None or not isinstance(warning_data, list) or len(warning_data) == 0:
return []

lang = preferred_language(self.hass, self._config_entry)
result = list()
for data in warning_data:
try:
Expand All @@ -456,7 +458,6 @@ def warnings_from_data(self, warning_data: list | None) -> List[WarningData]:
except TypeError:
level = None

lang = self.hass.config.language if self.hass.config.language in LANGS else 'en'
result.append(
WarningData(
slug=SLUG_MAP.get(warning_id, 'unknown'),
Expand Down
16 changes: 14 additions & 2 deletions custom_components/irm_kmi/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
"user": {
"title": "Configuration",
"data": {
"zone": "Zone",
"style": "Style of the radar",
"dark_mode": "Radar dark mode",
"use_deprecated_forecast_attribute": "Use the deprecated forecat attribute"
"use_deprecated_forecast_attribute": "Use the deprecated forecat attribute",
"language_override": "Language"
}
}
},
Expand Down Expand Up @@ -43,6 +45,15 @@
"repair_option_move": "I moved the zone in Benelux",
"repair_option_delete": "Delete that config entry"
}
},
"language_override": {
"options": {
"none": "Follow Home Assistant server language",
"fr": "French",
"nl": "Dutch",
"de": "German",
"en": "English"
}
}
},
"options": {
Expand All @@ -52,7 +63,8 @@
"data": {
"style": "Style of the radar",
"dark_mode": "Radar dark mode",
"use_deprecated_forecast_attribute": "Use the deprecated forecat attribute"
"use_deprecated_forecast_attribute": "Use the deprecated forecat attribute",
"language_override": "Language"
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions custom_components/irm_kmi/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
"user": {
"title": "Configuration",
"data": {
"zone": "Zone",
"style": "Style du radar",
"dark_mode": "Radar en mode sombre",
"use_deprecated_forecast_attribute": "Utiliser l'attribut forecat (déprécié)"
"use_deprecated_forecast_attribute": "Utiliser l'attribut forecat (déprécié)",
"language_override": "Langue"
}
}
},
Expand Down Expand Up @@ -43,6 +45,15 @@
"repair_option_move": "J'ai déplacé la zone dans le Benelux",
"repair_option_delete": "Supprimer cette configuration"
}
},
"language_override": {
"options": {
"none": "Langue du serveur Home Assistant",
"fr": "Français",
"nl": "Néerlandais",
"de": "Allemand",
"en": "Anglais"
}
}
},
"options": {
Expand All @@ -52,7 +63,8 @@
"data": {
"style": "Style du radar",
"dark_mode": "Radar en mode sombre",
"use_deprecated_forecast_attribute": "Utiliser l'attribut forecat (déprécié)"
"use_deprecated_forecast_attribute": "Utiliser l'attribut forecat (déprécié)",
"language_override": "Langue"
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions custom_components/irm_kmi/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
"user": {
"title": "Instellingen",
"data": {
"zone": "Zone",
"style": "Radarstijl",
"dark_mode": "Radar in donkere modus",
"use_deprecated_forecast_attribute": "Gebruik het forecat attribuut (afgeschaft)"
"use_deprecated_forecast_attribute": "Gebruik het forecat attribuut (afgeschaft)",
"language_override": "Taal"
}
}
},
Expand Down Expand Up @@ -43,6 +45,15 @@
"repair_option_move": "Ik heb de zone verplaats naar de Benelux",
"repair_option_delete": "Deze configuratie verwijderen"
}
},
"language_override": {
"options": {
"none": "Zelfde als Home Assistant server taal",
"fr": "Frans",
"nl": "Nederlands",
"de": "Duits",
"en": "Engels"
}
}
},
"options": {
Expand All @@ -52,7 +63,8 @@
"data": {
"style": "Radarstijl",
"dark_mode": "Radar in donkere modus",
"use_deprecated_forecast_attribute": "Gebruik het forecat attribuut (afgeschaft)"
"use_deprecated_forecast_attribute": "Gebruik het forecat attribuut (afgeschaft)",
"language_override": "Taal"
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions custom_components/irm_kmi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry

from .const import CONF_LANGUAGE_OVERRIDE, LANGS

_LOGGER = logging.getLogger(__name__)


Expand All @@ -29,3 +31,10 @@ def get_config_value(config_entry: ConfigEntry, key: str) -> Any:
if config_entry.options and key in config_entry.options:
return config_entry.options[key]
return config_entry.data[key]


def preferred_language(hass: HomeAssistant, config_entry: ConfigEntry) -> str:
if get_config_value(config_entry, CONF_LANGUAGE_OVERRIDE) == 'none':
return hass.config.language if hass.config.language in LANGS else 'en'

return get_config_value(config_entry, CONF_LANGUAGE_OVERRIDE)
2 changes: 2 additions & 0 deletions custom_components/irm_kmi/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ def get_forecasts_radar_service(self, include_past_forecasts: bool = False) -> L
now = dt.now()
now = now.replace(minute=(now.minute // 10) * 10, second=0, microsecond=0)

# TODO adapt the return value to match the weather.get_forecasts in next breaking change release
# return { 'forecast': [...] }
return [f for f in self.coordinator.data.get('radar_forecast')
if include_past_forecasts or datetime.fromisoformat(f.get('datetime')) >= now]

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
aiohttp==3.9.5
async-timeout==4.0.3
homeassistant==2024.5.2
homeassistant==2024.5.4
voluptuous==0.13.1
pytz==2024.1
svgwrite==1.4.3
4 changes: 2 additions & 2 deletions requirements_tests.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
homeassistant==2024.5.2
homeassistant==2024.5.4
pytest
pytest_homeassistant_custom_component==0.13.122
pytest_homeassistant_custom_component==0.13.124
freezegun
isort
8 changes: 5 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from custom_components.irm_kmi.const import (
CONF_DARK_MODE, CONF_STYLE, CONF_USE_DEPRECATED_FORECAST, DOMAIN,
OPTION_DEPRECATED_FORECAST_NOT_USED,
OPTION_DEPRECATED_FORECAST_TWICE_DAILY, OPTION_STYLE_STD)
OPTION_DEPRECATED_FORECAST_TWICE_DAILY, OPTION_STYLE_STD, CONF_LANGUAGE_OVERRIDE)


def get_api_data(fixture: str) -> dict:
Expand Down Expand Up @@ -52,7 +52,8 @@ def mock_config_entry() -> MockConfigEntry:
data={CONF_ZONE: "zone.home",
CONF_STYLE: OPTION_STYLE_STD,
CONF_DARK_MODE: True,
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED},
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED,
CONF_LANGUAGE_OVERRIDE: 'none'},
unique_id="zone.home",
)

Expand All @@ -66,7 +67,8 @@ def mock_config_entry_with_deprecated() -> MockConfigEntry:
data={CONF_ZONE: "zone.home",
CONF_STYLE: OPTION_STYLE_STD,
CONF_DARK_MODE: True,
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_TWICE_DAILY},
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_TWICE_DAILY,
CONF_LANGUAGE_OVERRIDE: 'none'},
unique_id="zone.home",
)

Expand Down
13 changes: 8 additions & 5 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@

from custom_components.irm_kmi import async_migrate_entry
from custom_components.irm_kmi.const import (
CONF_DARK_MODE, CONF_STYLE, CONF_USE_DEPRECATED_FORECAST,
CONFIG_FLOW_VERSION, DOMAIN, OPTION_DEPRECATED_FORECAST_NOT_USED,
OPTION_STYLE_SATELLITE, OPTION_STYLE_STD)
CONF_DARK_MODE, CONF_LANGUAGE_OVERRIDE, CONF_STYLE,
CONF_USE_DEPRECATED_FORECAST, CONFIG_FLOW_VERSION, DOMAIN,
OPTION_DEPRECATED_FORECAST_NOT_USED, OPTION_STYLE_SATELLITE,
OPTION_STYLE_STD)


async def test_full_user_flow(
Expand All @@ -40,7 +41,8 @@ async def test_full_user_flow(
assert result2.get("data") == {CONF_ZONE: ENTITY_ID_HOME,
CONF_STYLE: OPTION_STYLE_STD,
CONF_DARK_MODE: False,
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED}
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED,
CONF_LANGUAGE_OVERRIDE: 'none'}


async def test_config_flow_out_benelux_zone(
Expand Down Expand Up @@ -128,7 +130,8 @@ async def test_option_flow(
assert result["data"] == {
CONF_STYLE: OPTION_STYLE_SATELLITE,
CONF_DARK_MODE: True,
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED,
CONF_LANGUAGE_OVERRIDE: 'none'
}


Expand Down
Loading

0 comments on commit 4decfe7

Please sign in to comment.