Source code for betty.locale.localizable.config

"""
Provide localizable configuration.
"""

from contextlib import suppress
from typing import Self, cast, overload, final

from betty.assertion import assert_len_min
from betty.locale.localizable import (
    ShorthandStaticTranslations,
    Localizable,
    StaticTranslationsLocalizable,
)
from betty.locale.localizable.assertion import assert_static_translations
from betty.locale.localizer import Localizer
from typing_extensions import override

from betty.config import Configuration
from betty.locale import UNDETERMINED_LOCALE
from betty.serde.dump import VoidableDump, Dump, minimize
from betty.typing import Void


[docs] @final class StaticTranslationsLocalizableConfiguration(Configuration, Localizable): """ Provide configuration for a :py:class:`betty.locale.Localizable`. Read more at :doc:`multiple translations </usage/configuration/static-translations-localizable>`. """ _translations: dict[str, str]
[docs] def __init__( self, translations: ShorthandStaticTranslations | None = None, *, minimum: int = 1, ): """ :param translations: Keys are locales, values are translations. """ super().__init__() self._minimum = minimum self._translations: dict[str, str] if translations is not None: self.set(translations) else: self._translations = {}
def __getitem__(self, locale: str) -> str: return self._translations[locale] def __setitem__(self, locale: str, translation: str) -> None: self._translations[locale] = translation def __len__(self) -> int: return len(self._translations)
[docs] def set(self, translations: ShorthandStaticTranslations) -> None: """ Set the translations. """ translations = assert_static_translations()(translations) assert_len_min(self._minimum)(translations) self._translations = dict(translations)
[docs] @override def localize(self, localizer: Localizer) -> str: if self._translations: return StaticTranslationsLocalizable(self._translations).localize(localizer) return ""
[docs] @override def update(self, other: Self) -> None: self._translations = other._translations
[docs] @override def load(self, dump: Dump) -> None: self._translations.clear() translations = assert_static_translations()(dump) assert_len_min(self._minimum)(translations) for locale, translation in translations.items(): self[locale] = translation
[docs] @override def dump(self) -> VoidableDump: if not len(self._translations): return Void if len(self._translations) == 1: with suppress(KeyError): return self._translations[UNDETERMINED_LOCALE] return minimize( self._translations.copy() # type: ignore[arg-type] )
[docs] @final class StaticTranslationsLocalizableConfigurationProperty: """ A property (similar to :py:func:`property`) that contains :py:class:`betty.locale.localizable.StaticTranslationsLocalizableConfiguration`. """
[docs] def __init__(self, attr_name: str, *, minimum: int = 1): self._attr_name = f"_{attr_name}" self._minimum = minimum
def _get(self, instance: object) -> StaticTranslationsLocalizableConfiguration: try: return cast( StaticTranslationsLocalizableConfiguration, getattr(instance, self._attr_name), ) except AttributeError: translations = StaticTranslationsLocalizableConfiguration( minimum=self._minimum ) setattr(instance, self._attr_name, translations) return translations @overload def __get__(self, instance: None, _: type) -> Self: pass # pragma: no cover @overload def __get__( self, instance: object, _: type ) -> StaticTranslationsLocalizableConfiguration: pass # pragma: no cover def __get__(self, instance, _): if instance is None: return self return self._get(instance) def __set__( self, instance: object, translations: ShorthandStaticTranslations ) -> None: self._get(instance).set(translations) def __delete__(self, instance: object) -> None: self._get(instance).set({})