betty.locale.localizable.config - Betty documentation

Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
Toggle table of contents sidebar

# 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

    @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]

        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)

        def set(self, translations: ShorthandStaticTranslations) -> None:
            """
            Set the translations.
            """
            translations = assert_static_translations()(translations)
            assert_len_min(self._minimum)(translations)
            self._translations = dict(translations)

        @override
        def localize(self, localizer: Localizer) -> str:
            if self._translations:
                return StaticTranslationsLocalizable(self._translations).localize(localizer)
            return ""

        @override
        def update(self, other: Self) -> None:
            self._translations = other._translations

        @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

        @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]
            )

    @final
    class StaticTranslationsLocalizableConfigurationProperty:
        """
        A property (similar to :py:func:`property`) that contains :py:class:`betty.locale.localizable.StaticTranslationsLocalizableConfiguration`.
        """

        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({})