Source code for xmm.models.fields.i18n

from collections import Mapping

import flask
from flask_babel import lazy_gettext as _

from xmm.util.i18n import LanguageDict
from .collection import DictField


class MultilingualField(DictField):
    """A language mapping field."""

    field_name = _('Mehrsprachig')
    type_name = 'i18n'

    def __init__(self, field, *args, **kwargs):
        kwargs['field'] = field
        super().__init__(*args, **kwargs)

    def __set__(self, instance, value):
        if not isinstance(value, LanguageDict):
            if isinstance(value, Mapping):
                value = LanguageDict(value, instance, self.name)
                for k, v in list(value.items()):
                    if v is None:
                        del value[k]
            else:
                old_value = instance._data.get(self.name) or {}
                if value is None:
                    if flask.g.lang_code in old_value:
                        del old_value[flask.g.lang_code]
                else:
                    old_value[flask.g.lang_code] = value
                value = old_value
        super().__set__(instance, value)

    def __get__(self, instance, owner):
        if instance is None:
            return self
        dct = super().__get__(instance, owner)
        if dct is None:
            dct = {}
            dct = LanguageDict(dct, instance, self.name)
            super().__set__(instance, dct)
        elif not isinstance(dct, LanguageDict):
            dct = LanguageDict(dct, instance, self.name)
            super().__set__(instance, dct)
        return dct

    def __getattr__(self, item):
        if hasattr(self.field, item):
            field = self.get_field()
            return getattr(field, item)
        raise AttributeError(item)

    def _to_thing(self, thing, value, **options):
        if not isinstance(value, dict):
            value = {flask.current_app.config['DEFAULT_LANGUAGE']: value}
        thing_fun = getattr(self.get_field(), 'to_{}'.format(thing))
        mapped = {}
        langs = options.get('langs') or flask.current_app.config['LANGUAGES']
        for lang in langs:
            if thing == 'json':
                options['lang'] = lang
            mapped[lang] = thing_fun(value.get(lang), **options)
        return LanguageDict(mapped, None, self.name)

    def to_type(self, value):
        return self._to_thing('type', value)

    def to_json(self, value, **options):
        return self._to_thing('json', value, **options)

    def to_python(self, value):
        return self._to_thing('python', value)

    def to_mongo(self, value):
        if isinstance(value, Mapping):
            return self._to_thing('mongo', value)
        return super().to_mongo(value)

    def to_str(self, value, format_spec=None):
        if isinstance(value, LanguageDict):
            if format_spec is None:
                value = value.get(flask.current_app.config['LANGUAGES'])
            else:
                value = value.get(format_spec)
        ret = self.get_field().to_str(value)
        if ret is None:
            return None
        return str(ret)