diff --git a/src/plugins/weather/render/weather.html b/src/plugins/weather/render/weather.html index 2be9e3ac5..6d6991101 100644 --- a/src/plugins/weather/render/weather.html +++ b/src/plugins/weather/render/weather.html @@ -6,7 +6,7 @@
{% if plugin_settings.displayRefreshTime == "true" %} -
Last refresh: {{ last_refresh_time }}
+
{{ last_refresh_label }}: {{ last_refresh_time }}
{% endif %}
@@ -21,7 +21,7 @@ Current Weather Icon
{{ current_temperature }}{{temperature_unit}}
-
Feels Like {{ feels_like }}{% if units != "standard" %}°{% endif %}
+
{{ feels_like_label }} {{ feels_like }}{% if units != "standard" %}°{% endif %}
{{ forecast[0].high }}{% if units != "standard" %}°{% endif %} / {{ forecast[0].low }}{% if units != "standard" %}°{% endif %}
@@ -38,7 +38,7 @@
{{ dp.label }}
{{ dp.measurement }}{% if dp.unit %}{{ dp.unit }}{% endif %} - {% if dp.label == "Wind" %} + {% if dp.key == "Wind" %} {{ dp.arrow }} {% endif %}
diff --git a/src/plugins/weather/settings.html b/src/plugins/weather/settings.html index 8e137ef86..82dc4afc6 100644 --- a/src/plugins/weather/settings.html +++ b/src/plugins/weather/settings.html @@ -1,6 +1,20 @@ +
+ + +
+
@@ -200,6 +214,12 @@

Select Location

}); if (loadPluginSettings) { + const language = document.getElementById('language'); + const hasConfiguredLanguage = Array.from(language.options).some( + (option) => option.value === pluginSettings.language + ); + language.value = hasConfiguredLanguage ? pluginSettings.language : 'en'; + document.getElementById('latitude').value = pluginSettings.latitude; document.getElementById('longitude').value = pluginSettings.longitude; @@ -236,6 +256,7 @@

Select Location

document.getElementById('customTitle').value = pluginSettings.customTitle || ''; } else { // set default values + document.getElementById('language').value = 'en'; document.getElementById('units').value = "imperial"; document.getElementById('displayRefreshTime').checked = true; document.getElementById('displayRefreshTime').value = "true"; diff --git a/src/plugins/weather/weather.py b/src/plugins/weather/weather.py index e5d829e83..362a1d999 100644 --- a/src/plugins/weather/weather.py +++ b/src/plugins/weather/weather.py @@ -60,6 +60,181 @@ def get_moon_phase_name(phase_age: float) -> str: "imperial": "temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch" } +# Locale data for date/day name translation. +# days: full weekday names (0=Monday), days_short: abbreviated (0=Monday), +# months: full month names (0=January). +# ui: translated UI strings used in the weather template and data points. +# "en": None uses strftime/English directly. +LOCALE_DATA = { + "de": { + "days": ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], + "days_short": ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], + "months": ["Januar", "Februar", "März", "April", "Mai", "Juni", + "Juli", "August", "September", "Oktober", "November", "Dezember"], + "ui": { + "last_refresh": "Letzte Aktualisierung", + "feels_like": "Gefühlt", + "sunrise": "Sonnenaufgang", + "sunset": "Sonnenuntergang", + "wind": "Wind", + "humidity": "Luftfeuchtigkeit", + "pressure": "Luftdruck", + "uv_index": "UV-Index", + "visibility": "Sichtweite", + "air_quality": "Luftqualität", + "aqi_scale": ["Gut", "Mäßig", "Mittelmäßig", "Schlecht", "Sehr schlecht"], + "aqi_scale_om": ["Gut", "Mäßig", "Mittelmäßig", "Schlecht", "Sehr schlecht", "Extrem schlecht"], + }, + }, + "en": None, # English uses strftime directly + "es": { + "days": ["Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], + "days_short": ["Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], + "months": ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", + "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], + "ui": { + "last_refresh": "Última actualización", + "feels_like": "Sensación", + "sunrise": "Amanecer", + "sunset": "Atardecer", + "wind": "Viento", + "humidity": "Humedad", + "pressure": "Presión", + "uv_index": "Índice UV", + "visibility": "Visibilidad", + "air_quality": "Calidad aire", + "aqi_scale": ["Buena", "Aceptable", "Moderada", "Mala", "Muy mala"], + "aqi_scale_om": ["Buena", "Aceptable", "Moderada", "Mala", "Muy mala", "Extrema"], + }, + }, + "fr": { + "days": ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], + "days_short": ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], + "months": ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", + "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + "ui": { + "last_refresh": "Dernière mise à jour", + "feels_like": "Ressenti", + "sunrise": "Lever du soleil", + "sunset": "Coucher du soleil", + "wind": "Vent", + "humidity": "Humidité", + "pressure": "Pression", + "uv_index": "Indice UV", + "visibility": "Visibilité", + "air_quality": "Qualité de l'air", + "aqi_scale": ["Bonne", "Correcte", "Moyenne", "Mauvaise", "Très mauvaise"], + "aqi_scale_om": ["Bonne", "Correcte", "Moyenne", "Mauvaise", "Très mauvaise", "Extrêmement mauvaise"], + }, + }, + "id": { + "days": ["Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], + "days_short": ["Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Min"], + "months": ["Januari", "Februari", "Maret", "April", "Mei", "Juni", + "Juli", "Agustus", "September", "Oktober", "November", "Desember"], + "ui": { + "last_refresh": "Pembaruan terakhir", + "feels_like": "Terasa", + "sunrise": "Matahari terbit", + "sunset": "Matahari terbenam", + "wind": "Angin", + "humidity": "Kelembaban", + "pressure": "Tekanan", + "uv_index": "Indeks UV", + "visibility": "Jarak pandang", + "air_quality": "Kualitas udara", + "aqi_scale": ["Baik", "Sedang", "Buruk ringan", "Buruk", "Sangat buruk"], + "aqi_scale_om": ["Baik", "Sedang", "Buruk ringan", "Buruk", "Sangat buruk", "Berbahaya"], + }, + }, + "it": { + "days": ["Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato", "Domenica"], + "days_short": ["Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], + "months": ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", + "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + "ui": { + "last_refresh": "Ultimo aggiornamento", + "feels_like": "Percepita", + "sunrise": "Alba", + "sunset": "Tramonto", + "wind": "Vento", + "humidity": "Umidità", + "pressure": "Pressione", + "uv_index": "Indice UV", + "visibility": "Visibilità", + "air_quality": "Qualità aria", + "aqi_scale": ["Buona", "Discreta", "Moderata", "Scarsa", "Pessima"], + "aqi_scale_om": ["Buona", "Discreta", "Moderata", "Scarsa", "Pessima", "Pericolosa"], + }, + }, + "nl": { + "days": ["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], + "days_short": ["Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + "months": ["Januari", "Februari", "Maart", "April", "Mei", "Juni", + "Juli", "Augustus", "September", "Oktober", "November", "December"], + "ui": { + "last_refresh": "Laatste verversing", + "feels_like": "Voelt als", + "sunrise": "Zonsopgang", + "sunset": "Zonsondergang", + "wind": "Wind", + "humidity": "Vochtigheid", + "pressure": "Luchtdruk", + "uv_index": "UV-index", + "visibility": "Zichtbaarheid", + "air_quality": "Luchtkwaliteit", + "aqi_scale": ["Goed", "Matig", "Onvoldoende", "Slecht", "Zeer slecht"], + "aqi_scale_om": ["Goed", "Matig", "Onvoldoende", "Slecht", "Zeer slecht", "Gevaarlijk"], + }, + }, + "pt": { + "days": ["Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + "days_short": ["Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + "months": ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", + "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + "ui": { + "last_refresh": "Última atualização", + "feels_like": "Sensação", + "sunrise": "Nascer do sol", + "sunset": "Pôr do sol", + "wind": "Vento", + "humidity": "Umidade", + "pressure": "Pressão", + "uv_index": "Índice UV", + "visibility": "Visibilidade", + "air_quality": "Qualidade ar", + "aqi_scale": ["Boa", "Razoável", "Moderada", "Ruim", "Muito ruim"], + "aqi_scale_om": ["Boa", "Razoável", "Moderada", "Ruim", "Muito ruim", "Péssima"], + }, + }, +} + + +def get_localized_date(dt, language): + """Return a localized date string equivalent to strftime('%A, %B %d').""" + locale = LOCALE_DATA.get(language) + if locale: + day_name = locale["days"][dt.weekday()] + month_name = locale["months"][dt.month - 1] + return f"{day_name}, {month_name} {dt.day:02d}" + return dt.strftime("%A, %B %d") + + +def get_localized_day_short(dt, language): + """Return a localized abbreviated weekday name equivalent to strftime('%a').""" + locale = LOCALE_DATA.get(language) + if locale: + return locale["days_short"][dt.weekday()] + return dt.strftime("%a") + + +def get_ui_label(key, language, default=None): + """Return a translated UI string for the given key and language.""" + locale = LOCALE_DATA.get(language) + if locale and "ui" in locale: + return locale["ui"].get(key, default or key) + return default or key + class Weather(BasePlugin): def generate_settings_template(self): template_params = super().generate_settings_template() @@ -83,6 +258,9 @@ def generate_image(self, settings, device_config): weather_provider = settings.get('weatherProvider', 'OpenWeatherMap') title = settings.get('customTitle', '') + language = settings.get('language', 'en') + if language not in LOCALE_DATA: + language = 'en' timezone = device_config.get_config("timezone", default="America/New_York") time_format = device_config.get_config("time_format", default="12h") @@ -100,15 +278,15 @@ def generate_image(self, settings, device_config): if settings.get('weatherTimeZone', 'locationTimeZone') == 'locationTimeZone': logger.info("Using location timezone for OpenWeatherMap data.") wtz = self.parse_timezone(weather_data) - template_params = self.parse_weather_data(weather_data, aqi_data, wtz, units, time_format, lat) + template_params = self.parse_weather_data(weather_data, aqi_data, wtz, units, time_format, lat, language) else: logger.info("Using configured timezone for OpenWeatherMap data.") - template_params = self.parse_weather_data(weather_data, aqi_data, tz, units, time_format, lat) + template_params = self.parse_weather_data(weather_data, aqi_data, tz, units, time_format, lat, language) elif weather_provider == "OpenMeteo": forecast_days = 7 weather_data = self.get_open_meteo_data(lat, long, units, forecast_days + 1) aqi_data = self.get_open_meteo_air_quality(lat, long) - template_params = self.parse_open_meteo_data(weather_data, aqi_data, tz, units, time_format, lat) + template_params = self.parse_open_meteo_data(weather_data, aqi_data, tz, units, time_format, lat, language) else: raise RuntimeError(f"Unknown weather provider: {weather_provider}") @@ -137,7 +315,7 @@ def generate_image(self, settings, device_config): raise RuntimeError("Failed to take screenshot, please check logs.") return image - def parse_weather_data(self, weather_data, aqi_data, tz, units, time_format, lat): + def parse_weather_data(self, weather_data, aqi_data, tz, units, time_format, lat, language="en"): current = weather_data.get("current") daily_forecast = weather_data.get("daily", []) dt = datetime.fromtimestamp(current.get('dt'), tz=timezone.utc).astimezone(tz) @@ -150,7 +328,7 @@ def parse_weather_data(self, weather_data, aqi_data, tz, units, time_format, lat if current_icon.endswith('n'): current_icon = current_icon.replace("n", "d") data = { - "current_date": dt.strftime("%A, %B %d"), + "current_date": get_localized_date(dt, language), "current_day_icon": self.get_plugin_dir(f'icons/{current_icon}.png'), "current_temperature": str(round(current.get("temp"))), "feels_like": str(round(current.get("feels_like"))), @@ -158,13 +336,15 @@ def parse_weather_data(self, weather_data, aqi_data, tz, units, time_format, lat "units": units, "time_format": time_format } - data['forecast'] = self.parse_forecast(weather_data.get('daily'), tz, current_suffix, lat) - data['data_points'] = self.parse_data_points(weather_data, aqi_data, tz, units, time_format) + data['forecast'] = self.parse_forecast(weather_data.get('daily'), tz, current_suffix, lat, language) + data['data_points'] = self.parse_data_points(weather_data, aqi_data, tz, units, time_format, language) + data['feels_like_label'] = get_ui_label('feels_like', language, 'Feels Like') + data['last_refresh_label'] = get_ui_label('last_refresh', language, 'Last refresh') data['hourly_forecast'] = self.parse_hourly(weather_data.get('hourly'), tz, time_format, units, daily_forecast) return data - def parse_open_meteo_data(self, weather_data, aqi_data, tz, units, time_format, lat): + def parse_open_meteo_data(self, weather_data, aqi_data, tz, units, time_format, lat, language="en"): current = weather_data.get("current", {}) daily = weather_data.get('daily', {}) dt = datetime.fromisoformat(current.get('time')).astimezone(tz) if current.get('time') else datetime.now(tz) @@ -175,7 +355,7 @@ def parse_open_meteo_data(self, weather_data, aqi_data, tz, units, time_format, temperature_conversion = 273.15 if units == "standard" else 0. data = { - "current_date": dt.strftime("%A, %B %d"), + "current_date": get_localized_date(dt, language), "current_day_icon": self.get_plugin_dir(f'icons/{current_icon}.png'), "current_temperature": str(round(current.get("temperature", 0) + temperature_conversion)), "feels_like": str(round(current.get("apparent_temperature", current.get("temperature", 0)) + temperature_conversion)), @@ -184,8 +364,10 @@ def parse_open_meteo_data(self, weather_data, aqi_data, tz, units, time_format, "time_format": time_format } - data['forecast'] = self.parse_open_meteo_forecast(weather_data.get('daily', {}), units, tz, is_day, lat) - data['data_points'] = self.parse_open_meteo_data_points(weather_data, aqi_data, units, tz, time_format) + data['forecast'] = self.parse_open_meteo_forecast(weather_data.get('daily', {}), units, tz, is_day, lat, language) + data['data_points'] = self.parse_open_meteo_data_points(weather_data, aqi_data, units, tz, time_format, language) + data['feels_like_label'] = get_ui_label('feels_like', language, 'Feels Like') + data['last_refresh_label'] = get_ui_label('last_refresh', language, 'Last refresh') data['hourly_forecast'] = self.parse_open_meteo_hourly(weather_data.get('hourly', {}), units, tz, time_format, daily.get('sunrise', []), daily.get('sunset', [])) return data @@ -260,7 +442,7 @@ def get_moon_phase_icon_path(self, phase_name: str, lat: float) -> str: return self.get_plugin_dir(f"icons/{phase_name}.png") - def parse_forecast(self, daily_forecast, tz, current_suffix, lat): + def parse_forecast(self, daily_forecast, tz, current_suffix, lat, language="en"): """ - daily_forecast: list of daily entries from One‑Call v3 (each has 'dt', 'weather', 'temp', 'moon_phase') - tz: your target tzinfo (e.g. from zoneinfo or pytz) @@ -311,7 +493,7 @@ def choose_phase_name(phase: float) -> str: # --- date & temps --- dt = datetime.fromtimestamp(day["dt"], tz=timezone.utc).astimezone(tz) - day_label = dt.strftime("%a") + day_label = get_localized_day_short(dt, language) forecast.append( { @@ -326,7 +508,7 @@ def choose_phase_name(phase: float) -> str: return forecast - def parse_open_meteo_forecast(self, daily_data, units, tz, is_day, lat): + def parse_open_meteo_forecast(self, daily_data, units, tz, is_day, lat, language="en"): """ Parse the daily forecast from Open-Meteo API and calculate moon phase and illumination using the local 'astral' library. """ @@ -342,7 +524,7 @@ def parse_open_meteo_forecast(self, daily_data, units, tz, is_day, lat): for i in range(0, len(times)): dt = datetime.fromisoformat(times[i]).replace(tzinfo=timezone.utc).astimezone(tz) - day_label = dt.strftime("%a") + day_label = get_localized_day_short(dt, language) code = weather_codes[i] if i < len(weather_codes) else 0 weather_icon = self.map_weather_code_to_icon(code, is_day=1) @@ -466,14 +648,15 @@ def parse_open_meteo_hourly(self, hourly_data, units, tz, time_format, sunrises, hourly.append(hour_forecast) return hourly - def parse_data_points(self, weather, air_quality, tz, units, time_format): + def parse_data_points(self, weather, air_quality, tz, units, time_format, language="en"): data_points = [] sunrise_epoch = weather.get('current', {}).get("sunrise") if sunrise_epoch: sunrise_dt = datetime.fromtimestamp(sunrise_epoch, tz=timezone.utc).astimezone(tz) data_points.append({ - "label": "Sunrise", + "key": "Sunrise", + "label": get_ui_label("sunrise", language, "Sunrise"), "measurement": self.format_time(sunrise_dt, time_format, include_am_pm=False), "unit": "" if time_format == "24h" else sunrise_dt.strftime('%p'), "icon": self.get_plugin_dir('icons/sunrise.png') @@ -485,7 +668,8 @@ def parse_data_points(self, weather, air_quality, tz, units, time_format): if sunset_epoch: sunset_dt = datetime.fromtimestamp(sunset_epoch, tz=timezone.utc).astimezone(tz) data_points.append({ - "label": "Sunset", + "key": "Sunset", + "label": get_ui_label("sunset", language, "Sunset"), "measurement": self.format_time(sunset_dt, time_format, include_am_pm=False), "unit": "" if time_format == "24h" else sunset_dt.strftime('%p'), "icon": self.get_plugin_dir('icons/sunset.png') @@ -496,7 +680,8 @@ def parse_data_points(self, weather, air_quality, tz, units, time_format): wind_deg = weather.get('current', {}).get("wind_deg", 0) wind_arrow = self.get_wind_arrow(wind_deg) data_points.append({ - "label": "Wind", + "key": "Wind", + "label": get_ui_label("wind", language, "Wind"), "measurement": weather.get('current', {}).get("wind_speed"), "unit": UNITS[units]["speed"], "icon": self.get_plugin_dir('icons/wind.png'), @@ -504,21 +689,24 @@ def parse_data_points(self, weather, air_quality, tz, units, time_format): }) data_points.append({ - "label": "Humidity", + "key": "Humidity", + "label": get_ui_label("humidity", language, "Humidity"), "measurement": weather.get('current', {}).get("humidity"), "unit": '%', "icon": self.get_plugin_dir('icons/humidity.png') }) data_points.append({ - "label": "Pressure", + "key": "Pressure", + "label": get_ui_label("pressure", language, "Pressure"), "measurement": weather.get('current', {}).get("pressure"), "unit": 'hPa', "icon": self.get_plugin_dir('icons/pressure.png') }) data_points.append({ - "label": "UV Index", + "key": "UV Index", + "label": get_ui_label("uv_index", language, "UV Index"), "measurement": weather.get('current', {}).get("uvi"), "unit": '', "icon": self.get_plugin_dir('icons/uvi.png') @@ -537,23 +725,27 @@ def parse_data_points(self, weather, air_quality, tz, units, time_format): if at_max_visibility: visibility_str = u"\u2265" + visibility_str data_points.append({ - "label": "Visibility", + "key": "Visibility", + "label": get_ui_label("visibility", language, "Visibility"), "measurement": visibility_str, "unit": UNITS[units]["distance"], "icon": self.get_plugin_dir('icons/visibility.png') }) - aqi = air_quality.get('list', [])[0].get("main", {}).get("aqi") + aqi = (air_quality.get('list') or [{}])[0].get("main", {}).get("aqi") + locale = LOCALE_DATA.get(language) + aqi_scale = locale["ui"]["aqi_scale"] if locale and "ui" in locale else ["Good", "Fair", "Moderate", "Poor", "Very Poor"] data_points.append({ - "label": "Air Quality", + "key": "Air Quality", + "label": get_ui_label("air_quality", language, "Air Quality"), "measurement": aqi, - "unit": ["Good", "Fair", "Moderate", "Poor", "Very Poor"][int(aqi)-1], + "unit": aqi_scale[int(aqi)-1] if (aqi is not None and str(aqi).isdigit() and 1 <= int(aqi) <= len(aqi_scale)) else "N/A", "icon": self.get_plugin_dir('icons/aqi.png') }) return data_points - def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_format): + def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_format, language="en"): """Parses current data points from Open-Meteo API response.""" data_points = [] daily_data = weather_data.get('daily', {}) @@ -567,7 +759,8 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f if sunrise_times: sunrise_dt = datetime.fromisoformat(sunrise_times[0]).astimezone(tz) data_points.append({ - "label": "Sunrise", + "key": "Sunrise", + "label": get_ui_label("sunrise", language, "Sunrise"), "measurement": self.format_time(sunrise_dt, time_format, include_am_pm=False), "unit": "" if time_format == "24h" else sunrise_dt.strftime('%p'), "icon": self.get_plugin_dir('icons/sunrise.png') @@ -580,7 +773,8 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f if sunset_times: sunset_dt = datetime.fromisoformat(sunset_times[0]).astimezone(tz) data_points.append({ - "label": "Sunset", + "key": "Sunset", + "label": get_ui_label("sunset", language, "Sunset"), "measurement": self.format_time(sunset_dt, time_format, include_am_pm=False), "unit": "" if time_format == "24h" else sunset_dt.strftime('%p'), "icon": self.get_plugin_dir('icons/sunset.png') @@ -594,7 +788,8 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f wind_arrow = self.get_wind_arrow(wind_deg) wind_unit = UNITS[units]["speed"] data_points.append({ - "label": "Wind", "measurement": wind_speed, "unit": wind_unit, + "key": "Wind", "label": get_ui_label("wind", language, "Wind"), + "measurement": wind_speed, "unit": wind_unit, "icon": self.get_plugin_dir('icons/wind.png'), "arrow": wind_arrow }) @@ -611,7 +806,8 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f logger.warning(f"Could not parse time string {time_str} for humidity.") continue data_points.append({ - "label": "Humidity", "measurement": current_humidity, "unit": '%', + "key": "Humidity", "label": get_ui_label("humidity", language, "Humidity"), + "measurement": current_humidity, "unit": '%', "icon": self.get_plugin_dir('icons/humidity.png') }) @@ -628,7 +824,8 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f logger.warning(f"Could not parse time string {time_str} for pressure.") continue data_points.append({ - "label": "Pressure", "measurement": current_pressure, "unit": 'hPa', + "key": "Pressure", "label": get_ui_label("pressure", language, "Pressure"), + "measurement": current_pressure, "unit": 'hPa', "icon": self.get_plugin_dir('icons/pressure.png') }) @@ -645,12 +842,14 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f logger.warning(f"Could not parse time string {time_str} for UV Index.") continue data_points.append({ - "label": "UV Index", "measurement": current_uv_index, "unit": '', + "key": "UV Index", "label": get_ui_label("uv_index", language, "UV Index"), + "measurement": current_uv_index, "unit": '', "icon": self.get_plugin_dir('icons/uvi.png') }) # Visibility - current_visibility = "N/A" + current_visibility = None + at_max_visibility = False visibility_hourly_times = hourly_data.get('time', []) visibility_values = hourly_data.get('visibility', []) if units == "imperial": @@ -668,11 +867,15 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f except ValueError: logger.warning(f"Could not parse time string {time_str} for visibility.") continue - visibility_str = f"{current_visibility:.1f}" - if at_max_visibility: - visibility_str = u"\u2265" + visibility_str + if current_visibility is None: + visibility_str = "N/A" + else: + visibility_str = f"{current_visibility:.1f}" + if at_max_visibility: + visibility_str = u"\u2265" + visibility_str data_points.append({ - "label": "Visibility", + "key": "Visibility", + "label": get_ui_label("visibility", language, "Visibility"), "measurement": visibility_str, "unit": UNITS[units]["distance"], "icon": self.get_plugin_dir('icons/visibility.png') @@ -692,9 +895,12 @@ def parse_open_meteo_data_points(self, weather_data, aqi_data, units, tz, time_f continue scale = "" if current_aqi and current_aqi != "N/A": - scale = ["Good","Fair","Moderate","Poor","Very Poor","Ext Poor"][min(current_aqi//20,5)] + locale = LOCALE_DATA.get(language) + aqi_scale_om = locale["ui"]["aqi_scale_om"] if locale and "ui" in locale else ["Good","Fair","Moderate","Poor","Very Poor","Ext Poor"] + scale = aqi_scale_om[min(int(current_aqi)//20, 5)] data_points.append({ - "label": "Air Quality", "measurement": current_aqi, + "key": "Air Quality", "label": get_ui_label("air_quality", language, "Air Quality"), + "measurement": current_aqi, "unit": scale, "icon": self.get_plugin_dir('icons/aqi.png') })