mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Use order in preferred regions list (#91959)
* Use order in preferred regions list * Use float for score (inf = exact match)
This commit is contained in:
parent
b601fb17d3
commit
b4bd3b97f8
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterable
|
||||
from dataclasses import dataclass
|
||||
import math
|
||||
import operator
|
||||
import re
|
||||
|
||||
@ -15,7 +16,7 @@ def preferred_regions(
|
||||
language: str,
|
||||
country: str | None = None,
|
||||
code: str | None = None,
|
||||
) -> Iterable[str | None]:
|
||||
) -> Iterable[str]:
|
||||
"""Yield an ordered list of regions for a language based on country/code hints.
|
||||
|
||||
Regions should be checked for support in the returned order if no other
|
||||
@ -70,7 +71,7 @@ class Dialect:
|
||||
# Regions are upper-cased
|
||||
self.region = self.region.upper()
|
||||
|
||||
def score(self, dialect: Dialect, country: str | None = None) -> int:
|
||||
def score(self, dialect: Dialect, country: str | None = None) -> float:
|
||||
"""Return score for match with another dialect where higher is better.
|
||||
|
||||
Score < 0 indicates a failure to match.
|
||||
@ -79,27 +80,46 @@ class Dialect:
|
||||
# Not a match
|
||||
return -1
|
||||
|
||||
if self.region == dialect.region:
|
||||
# Language + region match
|
||||
if (self.region is None) and (dialect.region is None):
|
||||
# Weak match with no region constraint
|
||||
return 1
|
||||
|
||||
pref_regions: set[str | None] = set()
|
||||
if (self.region is None) or (dialect.region is None):
|
||||
# Generate a set of preferred regions
|
||||
pref_regions = set(
|
||||
preferred_regions(
|
||||
self.language,
|
||||
country=country,
|
||||
code=self.code,
|
||||
)
|
||||
if (self.region is not None) and (dialect.region is not None):
|
||||
if self.region == dialect.region:
|
||||
# Exact language + region match
|
||||
return math.inf
|
||||
|
||||
# Regions are both set, but don't match
|
||||
return 0
|
||||
|
||||
# Generate ordered list of preferred regions
|
||||
pref_regions = list(
|
||||
preferred_regions(
|
||||
self.language,
|
||||
country=country,
|
||||
code=self.code,
|
||||
)
|
||||
)
|
||||
|
||||
# Replace missing regions with preferred
|
||||
regions = pref_regions if self.region is None else {self.region}
|
||||
other_regions = pref_regions if dialect.region is None else {dialect.region}
|
||||
try:
|
||||
# Determine score based on position in the preferred regions list.
|
||||
if self.region is not None:
|
||||
region_idx = pref_regions.index(self.region)
|
||||
elif dialect.region is not None:
|
||||
region_idx = pref_regions.index(dialect.region)
|
||||
else:
|
||||
# Can't happen, but mypy is not smart enough
|
||||
raise ValueError()
|
||||
|
||||
# Better match if there is overlap in regions
|
||||
return 2 if regions.intersection(other_regions) else 0
|
||||
# More preferred regions are at the front.
|
||||
# Add 1 to boost above a weak match where no regions are set.
|
||||
return 1 + (len(pref_regions) - region_idx)
|
||||
except ValueError:
|
||||
# Region was not in preferred list
|
||||
pass
|
||||
|
||||
# Not a preferred region
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def parse(tag: str) -> Dialect:
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""Test Home Assistant language util methods."""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.const import MATCH_ALL
|
||||
from homeassistant.util import language
|
||||
|
||||
@ -95,26 +97,54 @@ def test_language_as_region() -> None:
|
||||
|
||||
|
||||
def test_zh_hant() -> None:
|
||||
"""Test that the zh-Hant matches HK or TW first."""
|
||||
"""Test that the zh-Hant matches HK or TW."""
|
||||
assert language.matches(
|
||||
"zh-Hant",
|
||||
["en-US", "en-GB", "zh-CN", "zh-HK", "zh-TW"],
|
||||
["en-US", "en-GB", "zh-CN", "zh-HK"],
|
||||
) == [
|
||||
"zh-HK",
|
||||
"zh-TW",
|
||||
"zh-CN",
|
||||
]
|
||||
|
||||
assert language.matches(
|
||||
"zh-Hant",
|
||||
["en-US", "en-GB", "zh-CN", "zh-TW", "zh-HK"],
|
||||
["en-US", "en-GB", "zh-CN", "zh-TW"],
|
||||
) == [
|
||||
"zh-TW",
|
||||
"zh-HK",
|
||||
"zh-CN",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("target", ["zh-Hant", "zh-Hans"])
|
||||
def test_zh_with_country(target: str) -> None:
|
||||
"""Test that the zh-Hant/zh-Hans still matches country when provided."""
|
||||
supported = ["en-US", "en-GB", "zh-CN", "zh-HK", "zh-TW"]
|
||||
assert (
|
||||
language.matches(
|
||||
target,
|
||||
supported,
|
||||
country="TW",
|
||||
)[0]
|
||||
== "zh-TW"
|
||||
)
|
||||
assert (
|
||||
language.matches(
|
||||
target,
|
||||
supported,
|
||||
country="HK",
|
||||
)[0]
|
||||
== "zh-HK"
|
||||
)
|
||||
assert (
|
||||
language.matches(
|
||||
target,
|
||||
supported,
|
||||
country="CN",
|
||||
)[0]
|
||||
== "zh-CN"
|
||||
)
|
||||
|
||||
|
||||
def test_zh_hans() -> None:
|
||||
"""Test that the zh-Hans matches CN first."""
|
||||
assert language.matches(
|
||||
|
Loading…
x
Reference in New Issue
Block a user