def add_select_related(self, fields):
        """
        Sets up the select_related data structure so that we only select
        certain related models (as opposed to all models, when
        self.select_related=True).
        """
        new_fields = []
        opts = self.model._meta

        # There is not actually any useful code, all this is to handle deprecated arguments.
        for field_name in fields:
            if field_name.startswith('translations'):
                new_name = None

                if field_name == 'translations':
                    new_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(get_active()))
                elif '_' in field_name:
                    dummy, language_code = field_name.rsplit('_', 1)
                    if language_code in get_all():
                        new_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(language_code))

                if new_name:
                    msg = "Using '%s' in select_related is deprecated, use '%s' or '%s' instead."
                    warnings.warn(msg % (field_name, TRANSLATION_FIELD_NAME, new_name), DeprecationWarning)
                    new_fields.append(TRANSLATION_FIELD_NAME)
                    new_fields.append(new_name)
                    continue

            # In all other cases use the old name
            new_fields.append(field_name)

        new_fields = set(new_fields)
        return super(MultilingualQuery, self).add_select_related(new_fields)
    def __get__(self, instance, instance_type=None):
        """
        Returns field translation or None
        """
        if instance is None:
            return self

        translation_model = self.model._meta.translation_model

        # Find language codes to be tried
        lang_codes = [self.language_code]
        if self._fallback:
            lang_codes += get_fallbacks(self.language_code)

        for lang_code in lang_codes:
            # Find translation
            translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(lang_code))
            try:
                # Translation is nullable, so it may return None
                translation = getattr(instance, translation_name)
            except translation_model.DoesNotExist:
                translation = None

            if translation is None:
                # Translation does not exist, try another language
                continue

            # Once we have the translation object we return what's there
            return getattr(translation, self._field_name)

        return None
    def __init__(self, field_name, language_code=None, fallback=False):
        self._field_name = field_name
        self._language_code = language_code
        self._fallback = fallback

        name = field_name
        if language_code is not None:
            name = '%s_%s' % (name, sanitize_language_code(language_code))
        if fallback:
            name = '%s_%s' % (name, FALLBACK_FIELD_SUFFIX)
        self.name = name

        super(TranslationProxyField, self).__init__()
def expand_lookup(opts, field_name):
    """
    Utility that expands simple multilingual lookup to lookup which can be handled by DJango ORM.
    """
    # Check if field is a translation
    field = _get_proxy_or_none(opts, field_name)
    if field is None:
        # Not a multilingual lookup, return
        return field_name

    # Multilingual field, add 'TranslationRelation' to lookup
    translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(field.language_code))
    return LOOKUP_SEP.join((translation_name, field.field_name))
    def __init__(self, to, base_name, language_code=None, **kwargs):
        self._base_name = base_name
        self._language_code = language_code

        # Create the field name
        if language_code:
            name = '%s_%s' % (base_name, sanitize_language_code(language_code))
        else:
            name = base_name
        kwargs['name'] = name
        # Disable any modifications of this field
        kwargs['editable'] = False
        kwargs['serialize'] = False
        # Define 'rel' object
        kwargs['rel'] = TranslationRel(self, to)
        # Let queries to fill master object into translation cache, e.g. in select_related.
        kwargs['unique'] = True
        kwargs['null'] = True

        to_fields = ['master']
        super(TranslationRelation, self).__init__(to, [], to_fields, **kwargs)
    def __set__(self, instance, value):
        """
        Sets field translation
        """
        translation_model = self.model._meta.translation_model

        # Find translation
        translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(self.language_code))

        try:
            # Translation is nullable, so it may return None
            translation = getattr(instance, translation_name)
        except translation_model.DoesNotExist:
            translation = None

        if translation is None:
            # Translation does not exist, create one
            translation = translation_model(master=instance, language_code=self.language_code)
            setattr(instance, translation_name, translation)

        # Set the field translation
        setattr(translation, self._field_name, value)
 def get_cache_name(self):
     # The field for active language needs to use the cache for that language
     return '_%s_%s_cache' % (self._base_name, sanitize_language_code(self.language_code))
 def test_sanitize_language_code(self):
     self.assertEqual(sanitize_language_code('cs'), 'cs')
     self.assertEqual(sanitize_language_code('en'), 'en')
     self.assertEqual(sanitize_language_code('en-us'), 'en_us')