TRANSLATION_FILES = tuple(getattr(settings, "MODELTRANSLATION_TRANSLATION_FILES", ()))
AVAILABLE_LANGUAGES = list(
    getattr(
        settings,
        "MODELTRANSLATION_LANGUAGES",
        (val for val, label in settings.LANGUAGES),
    )
)
DEFAULT_LANGUAGE = getattr(settings, "MODELTRANSLATION_DEFAULT_LANGUAGE", None)
    DEFAULT_LANGUAGE = AVAILABLE_LANGUAGES[0]
PREPOPULATE_LANGUAGE = getattr(settings, "MODELTRANSLATION_PREPOPULATE_LANGUAGE", None)
CUSTOM_FIELDS = getattr(settings, "MODELTRANSLATION_CUSTOM_FIELDS", ())
ENABLE_REGISTRATIONS = getattr(settings, "MODELTRANSLATION_ENABLE_REGISTRATIONS", settings.USE_I18N)
DEBUG = getattr(settings, "MODELTRANSLATION_DEBUG", False)
AUTO_POPULATE = getattr(settings, "MODELTRANSLATION_AUTO_POPULATE", False)
FALLBACK_LANGUAGES = getattr(settings, "MODELTRANSLATION_FALLBACK_LANGUAGES", (DEFAULT_LANGUAGE,))
    FALLBACK_LANGUAGES = {"default": tuple(FALLBACK_LANGUAGES)}
ENABLE_FALLBACKS = getattr(settings, "MODELTRANSLATION_ENABLE_FALLBACKS", True)
LOADDATA_RETAIN_LOCALE = getattr(settings, "MODELTRANSLATION_LOADDATA_RETAIN_LOCALE", True)
JQUERY_URL = getattr(
    settings,
    "JQUERY_URL",
    "//ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js",
)
JQUERY_UI_URL = getattr(
    settings,
    "JQUERY_UI_URL",
    "//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js",
) class NONE:
    """
    Used for fallback options when they are not provided (``None`` can be
    given as a fallback or undefined value) or to mark that a nullable value
    is not yet known and needs to be computed (e.g. field default).
    """

    pass def create_translation_field(model, field_name, lang, empty_value):
    """
    Translation field factory. Returns a ``TranslationField`` based on a
    fieldname and a language.

    The list of supported fields can be extended by defining a tuple of field
    names in the projects settings.py like this::

        MODELTRANSLATION_CUSTOM_FIELDS = ('MyField', 'MyOtherField',)

    If the class is neither a subclass of fields in ``SUPPORTED_FIELDS``, nor
    in ``CUSTOM_FIELDS`` an ``ImproperlyConfigured`` exception will be raised.
    """
    if empty_value not in ('', 'both', None, NONE):
        raise ImproperlyConfigured('%s is not a valid empty_value.' % empty_value)
    field = model._meta.get_field(field_name)
    cls_name = field.__class__.__name__
    if not (isinstance(field, SUPPORTED_FIELDS) or cls_name in mt_settings.CUSTOM_FIELDS):
        raise ImproperlyConfigured('%s is not supported by modeltranslation.' % cls_name)
    translation_class = field_factory(field.__class__)
    return translation_class(translated_field=field, language=lang, empty_value=empty_value) class TranslationFieldDescriptor(object):
    """
    A descriptor used for the original translated field.
    """

    def __init__(
        self, field, fallback_languages=None, fallback_value=NONE, fallback_undefined=NONE
    ):
        """
        Stores fallback options and the original field, so we know it's name
        and default.
        """
        self.field = field
        self.fallback_languages = fallback_languages
        self.fallback_value = fallback_value
        self.fallback_undefined = fallback_undefined

    def __set__(self, instance, value):
        """
        Updates the translation field for the current language.
        """
        # In order for deferred fields to work, we also need to set the base value
        instance.__dict__[self.field.name] = value
        if isinstance(self.field, fields.related.ForeignKey):
            instance.__dict__[self.field.get_attname()] = None if value is None else value.pk
        if getattr(instance, '_mt_init', False) or getattr(instance, '_mt_disable', False):
            # When assignment takes place in model instance constructor, don't set value.
            # This is essential for only/defer to work, but I think it's sensible anyway.
            # Setting the localized field may also be disabled by setting _mt_disable.
            return
        loc_field_name = build_localized_fieldname(self.field.name, get_language())
        setattr(instance, loc_field_name, value)

    def meaningful_value(self, val, undefined):
        """
        Check if val is considered non-empty.
        """
        if isinstance(val, fields.files.FieldFile):
            return val.name and not (
                isinstance(undefined, fields.files.FieldFile) and val == undefined
            )
        return val is not None and val != undefined

    def __get__(self, instance, owner):
        """
        Returns value from the translation field for the current language, or
        value for some another language according to fallback languages, or the
        custom fallback value, or field's default value.
        """
        if instance is None:
            return self
        default = NONE
        undefined = self.fallback_undefined
        if undefined is NONE:
            default = self.field.get_default()
            undefined = default
        langs = resolution_order(get_language(), self.fallback_languages)
        for lang in langs:
            loc_field_name = build_localized_fieldname(self.field.name, lang)
            val = getattr(instance, loc_field_name, None)
            if self.meaningful_value(val, undefined):
                return val
        if mt_settings.ENABLE_FALLBACKS and self.fallback_value is not NONE:
            return self.fallback_value
        else:
            if default is NONE:
                default = self.field.get_default()
            # Some fields like FileField behave strange, as their get_default() doesn't return
            # instance of attr_class, but rather None or ''.
            # Normally this case is handled in the descriptor, but since we have overridden it, we
            # must mock it up.
            if isinstance(self.field, fields.files.FileField) and not isinstance(
                default, self.field.attr_class
            ):
                return self.field.attr_class(instance, self.field, default)
            return default class TranslatedRelationIdDescriptor(object):
    """
    A descriptor used for the original '_id' attribute of a translated
    ForeignKey field.
    """

    def __init__(self, field_name, fallback_languages):
        self.field_name = field_name  # The name of the original field (excluding '_id')
        self.fallback_languages = fallback_languages

    def __set__(self, instance, value):
        lang = get_language()
        loc_field_name = build_localized_fieldname(self.field_name, lang)
        # Localized field name with '_id'
        loc_attname = instance._meta.get_field(loc_field_name).get_attname()
        setattr(instance, loc_attname, value)
        base_attname = instance._meta.get_field(self.field_name).get_attname()
        instance.__dict__[base_attname] = value

    def __get__(self, instance, owner):
        if instance is None:
            return self
        langs = resolution_order(get_language(), self.fallback_languages)
        for lang in langs:
            loc_field_name = build_localized_fieldname(self.field_name, lang)
            # Localized field name with '_id'
            loc_attname = instance._meta.get_field(loc_field_name).get_attname()
            val = getattr(instance, loc_attname, None)
            if val is not None:
                return val
        return None class LanguageCacheSingleObjectDescriptor(object):
    """
    A Mixin for RelatedObjectDescriptors which use current language in cache lookups.
    """

    accessor = None  # needs to be set on instance

    @property
    def cache_name(self):
        """
        Used in django 1.x
        """
        lang = get_language()
        cache = build_localized_fieldname(self.accessor, lang)
        return "_%s_cache" % cache

    def get_cache_name(self):
        """
        Used in django > 2.x
        """
        return build_localized_fieldname(self.accessor, get_language()) class MultilingualManager(MultilingualQuerysetManager):
    def rewrite(self, *args, **kwargs):
        return self.get_queryset().rewrite(*args, **kwargs)

    def populate(self, *args, **kwargs):
        return self.get_queryset().populate(*args, **kwargs)

    def raw_values(self, *args, **kwargs):
        return self.get_queryset().raw_values(*args, **kwargs)

    def get_queryset(self):
        """
        This method is repeated because some managers that don't use super() or alter queryset class
        may return queryset that is not subclass of MultilingualQuerySet.
        """
        qs = super(MultilingualManager, self).get_queryset()
        if isinstance(qs, MultilingualQuerySet):
            # Is already patched by MultilingualQuerysetManager - in most of the cases
            # when custom managers use super() properly in get_queryset.
            return qs
        return self._patch_queryset(qs) class MultilingualQuerysetManager(models.Manager):
    """
    This class gets hooked in MRO just before plain Manager, so that every call to
    get_queryset returns MultilingualQuerySet.
    """

    def get_queryset(self):
        qs = super(MultilingualQuerysetManager, self).get_queryset()
        return self._patch_queryset(qs)

    def _patch_queryset(self, qs):
        qs.__class__ = multilingual_queryset_factory(qs.__class__, instantiate=False)
        qs._post_init()
        qs._rewrite_applied_operations()
        return qs def rewrite_lookup_key(model, lookup_key):
    try:
        pieces = lookup_key.split('__', 1)
        original_key = pieces[0]

        translatable_fields = get_translatable_fields_for_model(model)
        if translatable_fields is not None:
            # If we are doing a lookup on a translatable field,
            # we want to rewrite it to the actual field name
            # For example, we want to rewrite "name__startswith" to "name_fr__startswith"
            if pieces[0] in translatable_fields:
                pieces[0] = build_localized_fieldname(pieces[0], get_language())

        if len(pieces) > 1:
            # Check if we are doing a lookup to a related trans model
            fields_to_trans_models = get_fields_to_translatable_models(model)
            # Check ``original key``, as pieces[0] may have been already rewritten.
            if original_key in fields_to_trans_models:
                transmodel = fields_to_trans_models[original_key]
                pieces[1] = rewrite_lookup_key(transmodel, pieces[1])
        return '__'.join(pieces)
    except AttributeError:
        return lookup_key def append_translated(model, fields):
    "If translated field is encountered, add also all its translation fields."
    fields = set(fields)
    from modeltranslation.translator import translator

    opts = translator.get_options_for_model(model)
    for key, translated in opts.fields.items():
        if key in fields:
            fields = fields.union(f.name for f in translated)
    return fields def build_localized_fieldname(field_name, lang):
    if lang == 'id':
        # The 2-letter Indonesian language code is problematic with the
        # current naming scheme as Django foreign keys also add "id" suffix.
        lang = 'ind'
    return str('%s_%s' % (field_name, lang.replace('-', '_'))) def parse_field(setting, field_name, default):
    """
    Extract result from single-value or dict-type setting like fallback_values.
    """
    if isinstance(setting, dict):
        return setting.get(field_name, default)
    else:
        return setting def register(model_or_iterable, **options):
    """
    Registers the given model(s) with the given translation options.

    The model(s) should be Model classes, not instances.

    Fields declared for translation on a base class are inherited by
    subclasses. If the model or one of its subclasses is already
    registered for translation, this will raise an exception.

    @register(Author)
    class AuthorTranslation(TranslationOptions):
        pass
    """
    from modeltranslation.translator import translator, TranslationOptions

    def wrapper(opts_class):
        if not issubclass(opts_class, TranslationOptions):
            raise ValueError("Wrapped class must subclass TranslationOptions.")
        translator.register(model_or_iterable, opts_class, **options)
        return opts_class

    return wrapper
from functools import partial
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Manager, ForeignKey, OneToOneField, options
from django.db.models.base import ModelBase
from django.db.models.signals import post_init
from django.utils.functional import cached_property
from six import with_metaclass
from modeltranslation import settings as mt_settings
from modeltranslation.fields import (
    NONE,
    create_translation_field,
    TranslationFieldDescriptor,
    TranslatedRelationIdDescriptor,
    LanguageCacheSingleObjectDescriptor,
)
from modeltranslation.manager import (
    MultilingualManager,
    MultilingualQuerysetManager,
    rewrite_lookup_key,
    append_translated,
)
from modeltranslation.utils import build_localized_fieldname, parse_field
from modeltranslation.decorators import register  # NOQA re-export
import django
# -*- coding: utf-8 -*-




class AlreadyRegistered(Exception):
    pass


class NotRegistered(Exception):
    pass


class DescendantRegistered(Exception):
    pass


class FieldsAggregationMetaClass(type):
    """
    Metaclass to handle custom inheritance of fields between classes.
    """

    def __new__(cls, name, bases, attrs):
        attrs['fields'] = set(attrs.get('fields', ()))
        for base in bases:
            if isinstance(base, FieldsAggregationMetaClass):
                attrs['fields'].update(base.fields)
        attrs['fields'] = tuple(attrs['fields'])
        return super(FieldsAggregationMetaClass, cls).__new__(cls, name, bases, attrs)


class TranslationOptions(with_metaclass(FieldsAggregationMetaClass, object)):
    """
    Translatable fields are declared by registering a model using
    ``TranslationOptions`` class with appropriate ``fields`` attribute.
    Model-specific fallback values and languages can also be given as class
    attributes.

    Options instances hold info about translatable fields for a model and its
    superclasses. The ``local_fields`` and ``fields`` attributes are mappings
    from fields to sets of their translation fields; ``local_fields`` contains
    only those fields that are handled in the model's database table (those
    inherited from abstract superclasses, unless there is a concrete superclass
    in between in the inheritance chain), while ``fields`` also includes fields
    inherited from concrete supermodels (giving all translated fields available
    on a model).

    ``related`` attribute inform whether this model is related part of some relation
    with translated model. This model may be not translated itself.
    ``related_fields`` contains names of reverse lookup fields.
    """

    required_languages = ()

    def __init__(self, model):
        """
        Create fields dicts without any translation fields.
        """
        self.model = model
        self.registered = False
        self.related = False
        self.local_fields = dict((f, set()) for f in self.fields)
        self.fields = dict((f, set()) for f in self.fields)
        self.related_fields = []

    def validate(self):
        """
        Perform options validation.
        """
        # TODO: at the moment only required_languages is validated.
        # Maybe check other options as well?
        if self.required_languages:
            if isinstance(self.required_languages, (tuple, list)):
                self._check_languages(self.required_languages)
            else:
                self._check_languages(self.required_languages.keys(), extra=('default',))
                for fieldnames in self.required_languages.values():
                    if any(f not in self.fields for f in fieldnames):
                        raise ImproperlyConfigured(
                            'Fieldname in required_languages which is not in fields option.'
                        )

    def _check_languages(self, languages, extra=()):

        correct = list(mt_settings.AVAILABLE_LANGUAGES) + list(extra)