diff --git a/docs/design.md b/docs/design.md
index b9326a48..74404f91 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -104,9 +104,9 @@ RSS 来源可以按地点 ID 限定范围,并配置正文清洗规则。`verba
和风天气使用 `QWeatherJWTAuthenticator` 签发短期 JWT。认证输入包括项目 ID、凭据 ID、专属 API Host 和 Base64 编码的 Ed25519 私钥。实现不支持用长期 API Key 代替该流程。
-`OpenMeteoProvider` 提供全球天气,并从独立接口读取空气质量和欧洲花粉数据。适配器在生成来源正文前把 WMO 天气代码转换为可读的中文天气现象;未知代码保留为“未识别天气现象”并写入安全日志。公开接口适用于非商业使用,没有 SLA;Base URL 和可选 API Key 可以替换。
+`OpenMeteoProvider` 提供全球天气,并从独立接口读取空气质量和欧洲花粉数据。Open-Meteo API 返回语言中立的结构化数据,适配器把天气、空气质量和花粉统一转换为固定 `en` 来源正文。WMO 天气代码映射在模块加载时完成验证,未知代码保留为 “Unrecognized weather condition” 并写入安全日志。`SourceDocument` 记录英文来源语言,模型按地点配置的目标语言生成最终简报。公开接口适用于非商业使用,没有 SLA;Base URL 和可选 API Key 可以替换。
-`AQICNProvider` 只在最终天气结果缺少空气质量时补充当前观测。它不参与未来日期查询,也不把 PM2.5 单项 AQI 换算为浓度。
+`AQICNProvider` 只在最终天气结果缺少空气质量时补充当前观测。AQICN 的结构化数据也统一转换为固定 `en` 来源正文。它不参与未来日期查询,也不把 PM2.5 单项 AQI 换算为浓度。
`NEASingaporeNowcastProvider` 只提供新加坡两小时预报。`JMAJapanForecastProvider` 只提供地点所配置预报区的日本本地预报。它们没有完整天气服务所需的全部数据,因此与 Open-Meteo 组合,而不是作为完整天气 fallback。
diff --git a/tests/test_air_quality.py b/tests/test_air_quality.py
index c40eb3d4..4e7e6515 100644
--- a/tests/test_air_quality.py
+++ b/tests/test_air_quality.py
@@ -35,14 +35,16 @@ def handler(request: httpx.Request) -> httpx.Response:
assert snapshot.aqi == 120
assert snapshot.aqi_standard == "US EPA"
+ assert snapshot.category == "Unhealthy for sensitive groups"
assert snapshot.effective_at is not None
assert snapshot.effective_at.to_iso8601_string() == "2026-07-13T08:00:00+08:00"
assert snapshot.time_kind is AirQualityTimeKind.OBSERVATION
assert snapshot.pm25_aqi == 100
assert snapshot.pm25_concentration is None
+ assert snapshot.output_language == "en"
document = air_quality_to_document(snapshot)
- assert "AQI:120(标准:US EPA" in document.content
- assert "PM2.5 不可用" in document.content
+ assert "AQI: 120 (Standard: US EPA" in document.content
+ assert "PM2.5 concentration: Unavailable" in document.content
assert "原始浓度" not in document.content
assert "折算" not in document.content
diff --git a/tests/test_allergen.py b/tests/test_allergen.py
index 353156bf..4096d072 100644
--- a/tests/test_allergen.py
+++ b/tests/test_allergen.py
@@ -13,28 +13,28 @@
def test_allergen_guidance_zero_is_none() -> None:
category, guidance = allergen_guidance(0)
- assert category == "无"
+ assert category == "None"
assert guidance
def test_allergen_guidance_low_band() -> None:
category, _ = allergen_guidance(5)
- assert category == "低"
+ assert category == "Low"
def test_allergen_guidance_moderate_band() -> None:
category, _ = allergen_guidance(20)
- assert category == "中"
+ assert category == "Moderate"
def test_allergen_guidance_high_band() -> None:
category, _ = allergen_guidance(50)
- assert category == "高"
+ assert category == "High"
def test_allergen_guidance_extreme_band() -> None:
category, _ = allergen_guidance(500)
- assert category == "极高"
+ assert category == "Very high"
@pytest.mark.parametrize("concentration", [-1, float("nan"), float("inf"), float("-inf")])
diff --git a/tests/test_languages.py b/tests/test_languages.py
index 0f105d87..82bdbf66 100644
--- a/tests/test_languages.py
+++ b/tests/test_languages.py
@@ -50,7 +50,7 @@ def test_weather_provider_language_metadata_distinguishes_selectable_and_fixed_s
assert QWEATHER_LANGUAGE_SUPPORT.select("ja") == "ja"
assert QWEATHER_LANGUAGE_SUPPORT.api_code("ja") == "ja"
assert OPEN_METEO_LANGUAGE_SUPPORT.selectable is False
- assert OPEN_METEO_LANGUAGE_SUPPORT.default == "zh-CN"
+ assert OPEN_METEO_LANGUAGE_SUPPORT.default == "en"
@pytest.mark.parametrize(
diff --git a/tests/test_reference_data.py b/tests/test_reference_data.py
index 59d60bf4..ee6c4e3a 100644
--- a/tests/test_reference_data.py
+++ b/tests/test_reference_data.py
@@ -78,7 +78,7 @@ def test_packaged_reference_data_is_available() -> None:
96,
99,
}
- assert weather_codes[53] == "中等强度毛毛雨"
+ assert weather_codes[53] == "Moderate drizzle"
assert localization_table("weather_document")["ja"]["forecast"] == "天気予報"
assert localization_table("briefing")["zh-Hans"]["weather"] == "天气信息"
classification = telegram_error_classification()
@@ -90,12 +90,12 @@ def test_packaged_reference_data_is_available() -> None:
"value",
(
{},
- {"descriptions_zh_CN": {}},
- {"descriptions_zh_CN": {"unknown": "晴朗"}},
- {"descriptions_zh_CN": {"00": "晴朗"}},
- {"descriptions_zh_CN": {"9" * 5_000: "未知"}},
- {"descriptions_zh_CN": {"0": ""}},
- {"descriptions_zh_CN": {"0": "晴朗"}, "unknown": {}},
+ {"descriptions_en": {}},
+ {"descriptions_en": {"unknown": "Clear sky"}},
+ {"descriptions_en": {"00": "Clear sky"}},
+ {"descriptions_en": {"9" * 5_000: "Unknown"}},
+ {"descriptions_en": {"0": ""}},
+ {"descriptions_en": {"0": "Clear sky"}, "unknown": {}},
),
)
def test_open_meteo_weather_codes_reject_invalid_data(monkeypatch, value) -> None:
diff --git a/tests/test_render.py b/tests/test_render.py
index 42857fec..afc06a47 100644
--- a/tests/test_render.py
+++ b/tests/test_render.py
@@ -79,7 +79,7 @@ def test_renderers_fall_back_to_source_id_for_legacy_blank_name() -> None:
def test_telegram_html_renderer_uses_context_source_name_as_attribution() -> None:
context = SourceDocument(
"allergen:open-meteo",
- "Open-Meteo / CAMS ENSEMBLE 花粉过敏原",
+ "Open-Meteo / CAMS ENSEMBLE pollen allergens",
"https://open-meteo.com/en/docs/air-quality-api",
"Pollen data",
)
@@ -93,14 +93,14 @@ def test_telegram_html_renderer_uses_context_source_name_as_attribution() -> Non
rendered = TelegramHTMLRenderer().render_briefing(result, (), (context,))
assert (
- 'Open-Meteo / CAMS ENSEMBLE 花粉过敏原'
+ 'Open-Meteo / CAMS ENSEMBLE pollen allergens'
) in rendered.body
def test_plain_text_renderer_uses_context_source_name_as_attribution() -> None:
context = SourceDocument(
"allergen:open-meteo",
- "Open-Meteo / CAMS ENSEMBLE 花粉过敏原",
+ "Open-Meteo / CAMS ENSEMBLE pollen allergens",
"https://open-meteo.com/en/docs/air-quality-api",
"Pollen data",
)
@@ -113,7 +113,9 @@ def test_plain_text_renderer_uses_context_source_name_as_attribution() -> None:
rendered = PlainTextRenderer().render_briefing(result, (), (context,))
- assert ("Open-Meteo / CAMS ENSEMBLE 花粉过敏原: https://open-meteo.com/en/docs/air-quality-api") in rendered.body
+ assert (
+ "Open-Meteo / CAMS ENSEMBLE pollen allergens: https://open-meteo.com/en/docs/air-quality-api"
+ ) in rendered.body
def test_telegram_html_renders_active_warnings_section() -> None:
diff --git a/tests/test_weather_context.py b/tests/test_weather_context.py
index 9a81643d..23a6c226 100644
--- a/tests/test_weather_context.py
+++ b/tests/test_weather_context.py
@@ -533,7 +533,9 @@ def handler(request: httpx.Request) -> httpx.Response:
).fetch(52.52, 13.41)
assert len(snapshot.weather_forecast) == 2
- assert "局部多云" in snapshot.weather_forecast[0]
+ assert snapshot.output_language == "en"
+ assert "Partly cloudy" in snapshot.weather_forecast[0]
+ assert "maximum precipitation probability 10%" in snapshot.weather_forecast[0]
assert "WMO" not in snapshot.weather_forecast[0]
assert snapshot.observed_at.to_iso8601_string() == "2026-07-13T08:00:00+02:00"
assert snapshot.observed_at.timezone_name == "Europe/Berlin"
@@ -544,14 +546,23 @@ def handler(request: httpx.Request) -> httpx.Response:
def test_open_meteo_weather_code_uses_readable_description() -> None:
- assert _open_meteo_weather_description(53) == "中等强度毛毛雨"
+ assert _open_meteo_weather_description(53) == "Moderate drizzle"
+
+
+def test_open_meteo_weather_code_lookup_uses_cached_loader_boundary(monkeypatch) -> None:
+ monkeypatch.setattr(
+ "weather_briefing.weather_context.open_meteo_weather_code_descriptions",
+ lambda: {53: "Reloaded description"},
+ )
+
+ assert _open_meteo_weather_description(53) == "Reloaded description"
def test_open_meteo_unknown_weather_code_uses_readable_fallback(caplog) -> None:
with caplog.at_level("WARNING", logger="weather_briefing.weather_context"):
description = _open_meteo_weather_description(100)
- assert description == "未识别天气现象"
+ assert description == "Unrecognized weather condition"
assert "Unknown Open-Meteo weather code code=100" in caplog.text
@@ -559,7 +570,7 @@ def test_open_meteo_invalid_weather_code_uses_readable_fallback(caplog) -> None:
with caplog.at_level("WARNING", logger="weather_briefing.weather_context"):
description = _open_meteo_weather_description("53")
- assert description == "未识别天气现象"
+ assert description == "Unrecognized weather condition"
assert "Invalid Open-Meteo weather code value_type=str" in caplog.text
@@ -615,7 +626,7 @@ def handler(request: httpx.Request) -> httpx.Response:
).fetch_for_date(39.9, 116.3, target_date)
assert len(snapshot.weather_forecast) == 1
- assert snapshot.weather_forecast[0].startswith("2026-07-15:")
+ assert snapshot.weather_forecast[0].startswith("2026-07-15: ")
assert snapshot.air_quality is not None
assert snapshot.air_quality.aqi == 90
assert snapshot.air_quality.effective_at is not None
@@ -1884,15 +1895,17 @@ def handler(request: httpx.Request) -> httpx.Response:
assert snapshot.air_quality is not None
assert snapshot.allergen is not None
assert snapshot.allergen.source_id == "allergen:open-meteo"
- assert snapshot.allergen.source_name == "Open-Meteo / CAMS ENSEMBLE 花粉过敏原"
+ assert snapshot.allergen.source_name == "Open-Meteo / CAMS ENSEMBLE pollen allergens"
+ assert snapshot.allergen.output_language == "en"
level_names = {level.name for level in snapshot.allergen.levels}
- assert {"桤木", "桦木", "禾本"} == level_names
- birch = next(level for level in snapshot.allergen.levels if level.name == "桦木")
- assert birch.category == "中"
+ assert {"Alder", "Birch", "Grass"} == level_names
+ birch = next(level for level in snapshot.allergen.levels if level.name == "Birch")
+ assert birch.category == "Moderate"
assert birch.concentration == 15
- assert snapshot.allergen.overall_category == "中"
+ assert snapshot.allergen.overall_category == "Moderate"
documents = snapshot_to_documents(snapshot)
assert "allergen:open-meteo" in [doc.id for doc in documents]
+ assert all(doc.language == "en" for doc in documents)
async def test_open_meteo_provider_returns_no_allergen_when_pollen_absent() -> None:
@@ -1947,7 +1960,7 @@ def handler(request: httpx.Request) -> httpx.Response:
assert snapshot.allergen is not None
level_names = {level.name for level in snapshot.allergen.levels}
- assert level_names == {"禾本"}
+ assert level_names == {"Grass"}
async def test_open_meteo_allergen_handles_missing_time_gracefully() -> None:
diff --git a/weather_briefing/air_quality.py b/weather_briefing/air_quality.py
index ad15046c..446c6e9d 100644
--- a/weather_briefing/air_quality.py
+++ b/weather_briefing/air_quality.py
@@ -91,7 +91,7 @@ async def fetch(
pm25_unit=None,
category=category,
health_guidance=guidance,
- output_language="zh-CN",
+ output_language="en",
)
diff --git a/weather_briefing/data/air_quality_guidance.json b/weather_briefing/data/air_quality_guidance.json
index 1624d4d1..077617f0 100644
--- a/weather_briefing/data/air_quality_guidance.json
+++ b/weather_briefing/data/air_quality_guidance.json
@@ -3,33 +3,33 @@
"bands": [
{
"maximum_aqi": 50,
- "category": "优",
- "guidance": "空气污染风险很低,一般无需因空气质量调整户外活动。"
+ "category": "Good",
+ "guidance": "Air pollution risk is low; no activity changes are generally needed."
},
{
"maximum_aqi": 100,
- "category": "良",
- "guidance": "极少数异常敏感人群应减少长时间、高强度户外活动。"
+ "category": "Moderate",
+ "guidance": "Unusually sensitive people should consider reducing prolonged or heavy outdoor exertion."
},
{
"maximum_aqi": 150,
- "category": "对敏感人群不健康",
- "guidance": "儿童、活跃成年人和呼吸系统疾病人群应减少长时间户外活动。"
+ "category": "Unhealthy for sensitive groups",
+ "guidance": "Children, active adults, and people with respiratory disease should reduce prolonged outdoor exertion."
},
{
"maximum_aqi": 200,
- "category": "不健康",
- "guidance": "敏感人群应避免长时间户外活动,其他人群也应适当减少户外活动。"
+ "category": "Unhealthy",
+ "guidance": "Sensitive groups should avoid prolonged outdoor exertion; everyone else should reduce it."
},
{
"maximum_aqi": 300,
- "category": "非常不健康",
- "guidance": "所有人应减少户外活动,敏感人群尽量避免外出。"
+ "category": "Very unhealthy",
+ "guidance": "Everyone should reduce outdoor activity, and sensitive groups should avoid going outdoors."
},
{
"maximum_aqi": null,
- "category": "危险",
- "guidance": "所有人应避免户外活动,并关注当地健康部门建议。"
+ "category": "Hazardous",
+ "guidance": "Everyone should avoid outdoor activity and follow local public health advice."
}
]
}
diff --git a/weather_briefing/data/allergen_guidance.json b/weather_briefing/data/allergen_guidance.json
index fe98dcef..9a3b1e1d 100644
--- a/weather_briefing/data/allergen_guidance.json
+++ b/weather_briefing/data/allergen_guidance.json
@@ -1,37 +1,37 @@
{
"pollen_types": {
- "alder": "桤木",
- "birch": "桦木",
- "grass": "禾本",
- "mugwort": "蒿属",
- "olive": "橄榄",
- "ragweed": "豚草"
+ "alder": "Alder",
+ "birch": "Birch",
+ "grass": "Grass",
+ "mugwort": "Mugwort",
+ "olive": "Olive",
+ "ragweed": "Ragweed"
},
"bands": [
{
"maximum_concentration": 0,
- "category": "无",
- "guidance": "花粉浓度极低,过敏体质人群一般无需因花粉调整户外活动。"
+ "category": "None",
+ "guidance": "Pollen concentrations are negligible; no activity changes are generally needed."
},
{
"maximum_concentration": 10,
- "category": "低",
- "guidance": "花粉浓度较低,少数极度敏感者可做适当防护。"
+ "category": "Low",
+ "guidance": "Pollen concentrations are low; highly sensitive people may take routine precautions."
},
{
"maximum_concentration": 30,
- "category": "中",
- "guidance": "花粉浓度中等,过敏体质人群户外活动后建议清洗面部和鼻腔。"
+ "category": "Moderate",
+ "guidance": "Pollen concentrations are moderate; sensitive people should wash their face and nose after outdoor activity."
},
{
"maximum_concentration": 100,
- "category": "高",
- "guidance": "花粉浓度较高,花粉过敏者应减少户外活动,外出佩戴口罩。"
+ "category": "High",
+ "guidance": "Pollen concentrations are high; people with pollen allergies should limit outdoor activity and wear a mask outside."
},
{
"maximum_concentration": null,
- "category": "极高",
- "guidance": "花粉浓度很高,花粉过敏者应尽量避免外出,关好门窗并使用空气净化设备。"
+ "category": "Very high",
+ "guidance": "Pollen concentrations are very high; people with pollen allergies should avoid going outside, close windows, and use air filtration."
}
]
}
diff --git a/weather_briefing/data/open_meteo_weather_codes.json b/weather_briefing/data/open_meteo_weather_codes.json
index 85401122..15acaf88 100644
--- a/weather_briefing/data/open_meteo_weather_codes.json
+++ b/weather_briefing/data/open_meteo_weather_codes.json
@@ -1,32 +1,32 @@
{
- "descriptions_zh_CN": {
- "0": "晴朗",
- "1": "大致晴朗",
- "2": "局部多云",
- "3": "阴天",
- "45": "有雾",
- "48": "雾凇",
- "51": "轻微毛毛雨",
- "53": "中等强度毛毛雨",
- "55": "强毛毛雨",
- "56": "轻微冻毛毛雨",
- "57": "强冻毛毛雨",
- "61": "小雨",
- "63": "中雨",
- "65": "大雨",
- "66": "轻微冻雨",
- "67": "强冻雨",
- "71": "小雪",
- "73": "中雪",
- "75": "大雪",
- "77": "米雪",
- "80": "轻微阵雨",
- "81": "中等强度阵雨",
- "82": "强阵雨",
- "85": "轻微阵雪",
- "86": "强阵雪",
- "95": "雷暴",
- "96": "雷暴伴轻微冰雹",
- "99": "雷暴伴强冰雹"
+ "descriptions_en": {
+ "0": "Clear sky",
+ "1": "Mainly clear",
+ "2": "Partly cloudy",
+ "3": "Overcast",
+ "45": "Fog",
+ "48": "Depositing rime fog",
+ "51": "Light drizzle",
+ "53": "Moderate drizzle",
+ "55": "Dense drizzle",
+ "56": "Light freezing drizzle",
+ "57": "Dense freezing drizzle",
+ "61": "Slight rain",
+ "63": "Moderate rain",
+ "65": "Heavy rain",
+ "66": "Light freezing rain",
+ "67": "Heavy freezing rain",
+ "71": "Slight snowfall",
+ "73": "Moderate snowfall",
+ "75": "Heavy snowfall",
+ "77": "Snow grains",
+ "80": "Slight rain showers",
+ "81": "Moderate rain showers",
+ "82": "Violent rain showers",
+ "85": "Slight snow showers",
+ "86": "Heavy snow showers",
+ "95": "Thunderstorm",
+ "96": "Thunderstorm with slight hail",
+ "99": "Thunderstorm with heavy hail"
}
}
diff --git a/weather_briefing/reference_data.py b/weather_briefing/reference_data.py
index 8002e2a3..c270c70e 100644
--- a/weather_briefing/reference_data.py
+++ b/weather_briefing/reference_data.py
@@ -144,11 +144,11 @@ def reference_string_tuple(filename: str, *path: str) -> tuple[str, ...]:
@cache
def open_meteo_weather_code_descriptions() -> Mapping[int, str]:
- """Return validated Chinese descriptions for Open-Meteo WMO weather codes."""
+ """Return validated English descriptions for Open-Meteo WMO weather codes."""
value = load_reference_data("open_meteo_weather_codes.json")
- descriptions = value.get("descriptions_zh_CN")
- if set(value) != {"descriptions_zh_CN"} or not isinstance(descriptions, dict) or not descriptions:
- raise ReferenceDataError("Open-Meteo weather codes must contain Chinese descriptions")
+ descriptions = value.get("descriptions_en")
+ if set(value) != {"descriptions_en"} or not isinstance(descriptions, dict) or not descriptions:
+ raise ReferenceDataError("Open-Meteo weather codes must contain English descriptions")
validated: dict[int, str] = {}
for code, description in descriptions.items():
diff --git a/weather_briefing/weather_context.py b/weather_briefing/weather_context.py
index 083a6f37..cdb70978 100644
--- a/weather_briefing/weather_context.py
+++ b/weather_briefing/weather_context.py
@@ -46,10 +46,11 @@
supported=("zh-CN", "zh-TW", "en", "ja"),
api_codes=(("zh-CN", "zh"), ("zh-TW", "zh-hant"), ("en", "en"), ("ja", "ja")),
)
-OPEN_METEO_LANGUAGE_SUPPORT = LanguageSupport.fixed("zh-CN")
+OPEN_METEO_LANGUAGE_SUPPORT = LanguageSupport.fixed("en")
_WEATHER_DOCUMENT_LABELS = localization_table("weather_document")
_QWEATHER_FORMATS = localization_table("qweather")
+open_meteo_weather_code_descriptions()
class WeatherContextError(RuntimeError):
@@ -672,7 +673,7 @@ def _parse_allergen(
)
return AllergenSnapshot(
source_id="allergen:open-meteo",
- source_name="Open-Meteo / CAMS ENSEMBLE 花粉过敏原",
+ source_name="Open-Meteo / CAMS ENSEMBLE pollen allergens",
source_url="https://open-meteo.com/en/docs/air-quality-api",
observed_at=observed_at,
levels=tuple(levels),
@@ -1025,18 +1026,19 @@ def _float_value(value: object) -> float:
def _format_open_meteo_day(daily: dict[str, object], index: int) -> str:
return (
- f"{_open_meteo_daily_value(daily, 'time', index)}:"
- f"{_open_meteo_weather_description(_open_meteo_daily_value(daily, 'weather_code', index))},"
+ f"{_open_meteo_daily_value(daily, 'time', index)}: "
+ f"{_open_meteo_weather_description(_open_meteo_daily_value(daily, 'weather_code', index))}, "
f"{_open_meteo_daily_value(daily, 'temperature_2m_min', index)}~"
- f"{_open_meteo_daily_value(daily, 'temperature_2m_max', index)}℃,"
- f"体感{_open_meteo_daily_value(daily, 'apparent_temperature_min', index)}~"
- f"{_open_meteo_daily_value(daily, 'apparent_temperature_max', index)}℃,"
- f"预计降水{_open_meteo_daily_value(daily, 'precipitation_sum', index)}毫米,"
- f"最高降水概率{_open_meteo_daily_value(daily, 'precipitation_probability_max', index)}%,"
- f"最大风速{_open_meteo_daily_value(daily, 'wind_speed_10m_max', index)}千米/小时,"
- f"最大阵风{_open_meteo_daily_value(daily, 'wind_gusts_10m_max', index)}千米/小时,"
- f"主导风向{_open_meteo_daily_value(daily, 'wind_direction_10m_dominant', index)}°,"
- f"最高紫外线指数{_open_meteo_daily_value(daily, 'uv_index_max', index)}"
+ f"{_open_meteo_daily_value(daily, 'temperature_2m_max', index)} °C, "
+ f"feels like {_open_meteo_daily_value(daily, 'apparent_temperature_min', index)}~"
+ f"{_open_meteo_daily_value(daily, 'apparent_temperature_max', index)} °C, "
+ f"expected precipitation {_open_meteo_daily_value(daily, 'precipitation_sum', index)} mm, "
+ f"maximum precipitation probability "
+ f"{_open_meteo_daily_value(daily, 'precipitation_probability_max', index)}%, "
+ f"maximum wind speed {_open_meteo_daily_value(daily, 'wind_speed_10m_max', index)} km/h, "
+ f"maximum gust {_open_meteo_daily_value(daily, 'wind_gusts_10m_max', index)} km/h, "
+ f"dominant wind direction {_open_meteo_daily_value(daily, 'wind_direction_10m_dominant', index)}°, "
+ f"maximum UV index {_open_meteo_daily_value(daily, 'uv_index_max', index)}"
)
@@ -1048,4 +1050,4 @@ def _open_meteo_weather_description(value: object) -> str:
_LOGGER.warning("Unknown Open-Meteo weather code code=%d", value)
else:
_LOGGER.warning("Invalid Open-Meteo weather code value_type=%s", type(value).__name__)
- return "未识别天气现象"
+ return "Unrecognized weather condition"