1. Carl Meyer
  2. django-modeltranslation

Source

django-modeltranslation / modeltranslation / utils.py

# -*- coding: utf-8 -*-
from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import get_language as _get_language
from django.utils.functional import lazy


def get_language():
    """
    Return an active language code that is guaranteed to be in
    settings.LANGUAGES (Django does not seem to guarantee this for us.)

    """
    lang = _get_language()
    available_languages = [l[0] for l in settings.LANGUAGES]
    if lang not in available_languages and '-' in lang:
        lang = lang.split('-')[0]
    if lang in available_languages:
        return lang
    return available_languages[0]


def get_translation_fields(field):
    """Returns a list of localized fieldnames for a given field."""
    return [build_localized_fieldname(field, l[0]) for l in settings.LANGUAGES]


def build_localized_fieldname(field_name, lang):
    return '%s_%s' % (field_name, lang.replace('-', '_'))

def _build_localized_verbose_name(verbose_name, lang):
    return u'%s [%s]' % (verbose_name, lang)

build_localized_verbose_name = lazy(_build_localized_verbose_name, unicode)

class TranslationFieldDescriptor(object):
    """A descriptor used for the original translated field."""
    def __init__(self, name, initial_val=""):
        """
        The ``name`` is the name of the field (which is not available in the
        descriptor by default - this is Python behaviour).
        """
        self.name = name
        self.val = initial_val

    def __set__(self, instance, value):
        lang = get_language()
        loc_field_name = build_localized_fieldname(self.name, lang)
        # also update the translation field of the current language
        setattr(instance, loc_field_name, value)
        # update the original field via the __dict__ to prevent calling the
        # descriptor
        instance.__dict__[self.name] = value

    def __get__(self, instance, owner):
        if not instance:
            raise ValueError(u"Translation field '%s' can only be "
                              "accessed via an instance not via "
                              "a class." % self.name)
        lang = get_language()
        loc_field_name = build_localized_fieldname(self.name, lang)
        if hasattr(instance, loc_field_name):
            return getattr(instance, loc_field_name) or \
                   instance.__dict__[self.name]
        return instance.__dict__[self.name]


#def create_model(name, fields=None, app_label='', module='', options=None,
                 #admin_opts=None):
    #"""
    #Create specified model.
    #This is taken from http://code.djangoproject.com/wiki/DynamicModels
    #"""
    #class Meta:
        ## Using type('Meta', ...) gives a dictproxy error during model
        ## creation
        #pass

    #if app_label:
        ## app_label must be set using the Meta inner class
        #setattr(Meta, 'app_label', app_label)

    ## Update Meta with any options that were provided
    #if options is not None:
        #for key, value in options.iteritems():
            #setattr(Meta, key, value)

    ## Set up a dictionary to simulate declarations within a class
    #attrs = {'__module__': module, 'Meta': Meta}

    ## Add in any fields that were provided
    #if fields:
        #attrs.update(fields)

    ## Create the class, which automatically triggers ModelBase processing
    #model = type(name, (models.Model,), attrs)

    ## Create an Admin class if admin options were provided
    #if admin_opts is not None:
        #class Admin(admin.ModelAdmin):
            #pass
        #for key, value in admin_opts:
            #setattr(Admin, key, value)
        #admin.site.register(model, Admin)

    #return model


def copy_field(field):
    """
    Instantiate a new field, with all of the values from the old one, except
    the to and to_field in the case of related fields.

    This taken from http://www.djangosnippets.org/snippets/442/
    """
    base_kw = dict([(n, getattr(field, n, '_null')) for n in \
              models.fields.Field.__init__.im_func.func_code.co_varnames])
    if isinstance(field, models.fields.related.RelatedField):
        rel = base_kw.get('rel')
        rel_kw = dict([(n, getattr(rel, n, '_null')) for n in \
                 rel.__init__.im_func.func_code.co_varnames])
        if isinstance(field, models.fields.related.ForeignKey):
            base_kw['to_field'] = rel_kw.pop('field_name')
        base_kw.update(rel_kw)
    base_kw.pop('self')
    return field.__class__(**base_kw)