"""
Provide the Locale API.
"""
from __future__ import annotations
from typing import Sequence, TypeAlias
from babel import Locale, negotiate_locale as babel_negotiate_locale
from babel.core import UnknownLocaleError
from langcodes import Language
from betty import fs
from betty.json.schema import String
_LOCALE_DIRECTORY_PATH = fs.ASSETS_DIRECTORY_PATH / "locale"
NO_LINGUISTIC_CONTENT = "zxx"
UNDETERMINED_LOCALE = "und"
UNCODED_LOCALE = "mis"
MULTIPLE_LOCALES = "mul"
SPECIAL_LOCALES = (
NO_LINGUISTIC_CONTENT,
UNDETERMINED_LOCALE,
UNCODED_LOCALE,
MULTIPLE_LOCALES,
)
DEFAULT_LOCALE = "en-US"
[docs]
def merge_locales(*locales: str) -> str:
"""
Merge locales into a single locale.
"""
unique_locales = set(locales)
if len(unique_locales) == 0:
return NO_LINGUISTIC_CONTENT
elif len(unique_locales) == 1:
return next(iter(unique_locales))
# Strip locales without linguistic content.
if NO_LINGUISTIC_CONTENT in unique_locales:
return merge_locales(*(unique_locales - {NO_LINGUISTIC_CONTENT}))
return MULTIPLE_LOCALES
[docs]
def to_babel_identifier(locale: Localey) -> str:
"""
Convert a locale or locale metadata to a Babel locale identifier.
:raises ValueError:
"""
if isinstance(locale, Locale):
return str(locale)
language_data = Language.get(locale)
return "_".join(
part
for part in [
language_data.language,
language_data.script,
language_data.territory,
]
if part
)
[docs]
def to_locale(locale: Localey) -> str:
"""
Ensure that a locale or locale metadata is a locale.
"""
if isinstance(locale, str):
return locale
return "-".join(
part
for part in [
locale.language,
locale.script,
locale.territory,
]
if part
)
Localey: TypeAlias = str | Locale
[docs]
def get_data(locale: Localey) -> Locale:
"""
Get locale metadata.
:raises betty.locale.InvalidLocale: Raised if the given identifier is not a valid locale.
:raises betty.locale.LocaleNotFoundError: Raised if the given locale cannot be found.
"""
if isinstance(locale, Locale):
return locale
try:
return Locale.parse(to_babel_identifier(locale))
except ValueError:
from betty.locale.error import InvalidLocale
raise InvalidLocale(locale) from None
except UnknownLocaleError:
from betty.locale.error import LocaleNotFound
raise LocaleNotFound(locale) from None