From b5ac2ab931f720e13285b8f46048c8b31b719f98 Mon Sep 17 00:00:00 2001 From: Felix Stupp Date: Sun, 19 Mar 2023 10:29:28 +0100 Subject: [PATCH] Add module for localization tags (namely country & language tags) --- .../models/localization/__init__.py | 2 + .../models/localization/common.py | 6 ++ .../models/localization/country.py | 96 +++++++++++++++++++ .../models/localization/language.py | 94 ++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 server/entertainment_decider/models/localization/__init__.py create mode 100644 server/entertainment_decider/models/localization/common.py create mode 100644 server/entertainment_decider/models/localization/country.py create mode 100644 server/entertainment_decider/models/localization/language.py diff --git a/server/entertainment_decider/models/localization/__init__.py b/server/entertainment_decider/models/localization/__init__.py new file mode 100644 index 0000000..8e1cddf --- /dev/null +++ b/server/entertainment_decider/models/localization/__init__.py @@ -0,0 +1,2 @@ +from .country import find_country, get_country_tag +from .language import find_language, get_language_tag diff --git a/server/entertainment_decider/models/localization/common.py b/server/entertainment_decider/models/localization/common.py new file mode 100644 index 0000000..8cdcd45 --- /dev/null +++ b/server/entertainment_decider/models/localization/common.py @@ -0,0 +1,6 @@ +from __future__ import annotations + + +class LocalizationError(Exception): + def __init__(self, identifier: str | int, kind: str): + super().__init__(f"Couldn't find {kind} with {identifier!r}") diff --git a/server/entertainment_decider/models/localization/country.py b/server/entertainment_decider/models/localization/country.py new file mode 100644 index 0000000..e337ceb --- /dev/null +++ b/server/entertainment_decider/models/localization/country.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +from typing import Literal, Optional, TypedDict + +from pycountry import countries # type: ignore + +from ..entities import Tag, TagKey +from .common import LocalizationError + + +def get_country_tag(identifier: str | int) -> Tag: + country = find_country(identifier) + if country is None: + raise LocalizationError(identifier=identifier, kind="country") + TagKey.get_or_create_tag( # ensure it is created + ".localization/country", + title="Countries", + notes="Collection for all country tags", + use_for_preferences=False, + ) + return TagKey.get_or_create_tag( + f".localization/country/{country.alpha_3.lower()}", + title=country.common_name, + notes="Country", + use_for_preferences=True, + super_tags=[".localization/country"], + ) + + +def find_country(identifier: str | int) -> Optional[Country]: + if isinstance(identifier, int): + if identifier < 0: + return None + identifier = str(identifier) + return Country(countries.lookup(identifier)._fields) + + +class Country: + __data: _CountryData + + def __init__(self, country_data: _CountryData) -> None: + self.__data = country_data + + @property + def alpha_2(self) -> str: + return self.__data["alpha_2"] + + @property + def alpha_3(self) -> str: + return self.__data["alpha_3"] + + @property + def flag(self) -> str: + return self.__data["flag"] + + @property + def numeric(self) -> str: + return self.__data["numeric"] + + @property + def name(self) -> str: + return self.__get_first("name", "common_name", "official_name") + + @property + def common_name(self) -> str: + return self.__get_first("common_name", "name", "official_name") + + @property + def official_name(self) -> str: + return self.__get_first("official_name", "name", "common_name") + + def __get_first( + self, + *keys: Literal[ + "common_name", + "name", + "official_name", + ], + ) -> str: + for k in keys: + if k in self.__data: + return self.__data[k] + raise AttributeError(self.__data) + + +class _CountryDataTotal(TypedDict): + alpha_2: str + alpha_3: str + flag: str + name: str + numeric: str + + +class _CountryData(_CountryDataTotal, total=False): + common_name: str + official_name: str diff --git a/server/entertainment_decider/models/localization/language.py b/server/entertainment_decider/models/localization/language.py new file mode 100644 index 0000000..f42c29e --- /dev/null +++ b/server/entertainment_decider/models/localization/language.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +from typing import Literal, Optional, TypedDict + +from pycountry import languages # type: ignore + +from ..entities import Tag, TagKey +from .common import LocalizationError + + +def get_language_tag(identifier: str) -> Tag: + language = find_language(identifier) + if language is None: + raise LocalizationError(identifier=identifier, kind="language") + TagKey.get_or_create_tag( # ensure it is created + ".localization/language", + title="Languages", + notes="Collection for all language tags", + use_for_preferences=False, + ) + return TagKey.get_or_create_tag( + f".localization/language/{language.alpha_3.lower()}", + title=language.common_name, + notes="Language", + use_for_preferences=True, + super_tags=[".localization/language"], + ) + + +def find_language(identifier: str) -> Optional[Language]: + return Language(languages.lookup(identifier)._fields) + + +class Language: + __data: _LanguageData + + def __init__(self, language_data: _LanguageData) -> None: + self.__data = language_data + + @property + def alpha_2(self) -> str: + return self.__data["alpha_2"] + + @property + def alpha_3(self) -> str: + return self.__data["alpha_3"] + + @property + def scope(self) -> str: + return self.__data["scope"] + + @property + def type(self) -> str: + return self.__data["type"] + + @property + def legacy_bibliographic(self) -> str: + return self.__get_first("bibliographic", "alpha_3") + + @property + def name(self) -> str: + return self.__get_first("name", "common_name") + + @property + def common_name(self) -> str: + return self.__get_first("common_name", "name") + + def __get_first( + self, + *keys: Literal[ + "alpha_3", + "bibliographic", + "common_name", + "name", + ], + ) -> str: + for k in keys: + if k in self.__data: + return self.__data[k] + raise AttributeError(self.__data) + + +class _LanguageDataTotal(TypedDict): + alpha_3: str + name: str + scope: str + type: str + + +class _LanguageData(_LanguageDataTotal, total=False): + alpha_2: str + bibliographic: str + common_name: str + inverted_name: str