def localize_fields(cls, localized_fields):
    """
    For each field name in localized_fields,
    for each language in settings.LANGUAGES,
    add fields to cls,
    and remove the original field, instead
    replace it with a DefaultFieldDescriptor,
    which always returns the field in the current language.
    """

    # never do this twice
    if hasattr(cls, 'localized_fields'):
        return cls

    # MSGID_LANGUAGE is the language that is used for the gettext message id's.
    # If it is not available, because the site isn't using subsites, the
    # LANGUAGE_CODE is good too. MSGID_LANGUAGE gives the opportunity to
    # specify a language not available in the site but which is still used for
    # the message id's.
    msgid_language = getattr(settings,
        'MSGID_LANGUAGE',  settings.LANGUAGE_CODE)

    # set the localized fields property
    cls.localized_fields = localized_fields

    for field in localized_fields:
        original_attr = get_field_from_model_by_name(cls, field)

        for cnt, language_code in enumerate(get_all_language_codes()):
            i18n_attr = copy.copy(original_attr)
            # add support for south introspection.
            i18n_attr._south_introspects = True
            i18n_attr.original_fieldname = field
            i18n_attr.include_in_xml = False
            lang_attr_name = get_real_fieldname(field, language_code)
            i18n_attr.name = lang_attr_name
            i18n_attr.creation_counter = i18n_attr.creation_counter + .01 * cnt
            # null must be allowed for the message id language because this
            # language might not be available at all in the backend
            if not i18n_attr.null and i18n_attr.default is NOT_PROVIDED:
                i18n_attr.null = True

            if language_code != msgid_language:
                # no validation for the fields that are language specific
                if not i18n_attr.blank:
                    i18n_attr.blank = True

            if i18n_attr.verbose_name:
                i18n_attr.verbose_name = translation.string_concat(
                    i18n_attr.verbose_name, u' (%s)' % language_code)
            cls.add_to_class(lang_attr_name, i18n_attr)

        # delete original field
        del cls._meta.local_fields[cls._meta.local_fields.index(original_attr)]

        # copy some values and functions from the original_attr
        # so the field can emulate the original_attr as good as possible
        kwargs = {
            'serialize': getattr(original_attr, 'serialize', True),
            'extra_attrs': getattr(original_attr, 'extra_attrs', None),
            'max_length': getattr(original_attr, 'max_length', None),
            'min_length': getattr(original_attr, 'min_length', None),
            'form_field': original_attr.formfield(
                **FORMFIELD_FOR_DBFIELD_DEFAULTS.get(
                    original_attr.__class__, {})),
            'get_internal_type': original_attr.get_internal_type,
            'unique': getattr(original_attr, 'unique', False),
            'to_python': original_attr.to_python,
        }

        # copy __serialize__ if it was defined on the original attr
        if hasattr(original_attr, '__serialize__'):
            kwargs['__serialize__'] = original_attr.__serialize__

        # add the DefaultFieldDescriptor where the original_attr was.
        cls.add_to_class(field, DefaultFieldDescriptor(field, **kwargs))

        # update fields cache
        try:
            cls._meta._fill_fields_cache()
        except AttributeError:
            # Django 1.8 removed _fill_fields_cache
            cls._meta._expire_cache()
            cls._meta._get_fields(reverse=False)

    # return the finished product
    return cls
def localize_fields ( cls , localized_fields ) : if hasattr ( cls , 'localized_fields' ) : return cls msgid_language = getattr ( settings , 'MSGID_LANGUAGE' , settings . LANGUAGE_CODE ) cls . localized_fields = localized_fields for field in localized_fields : original_attr = get_field_from_model_by_name ( cls , field ) for cnt , language_code in enumerate ( get_all_language_codes ( ) ) : i18n_attr = copy . copy ( original_attr ) i18n_attr . _south_introspects = True i18n_attr . original_fieldname = field i18n_attr . include_in_xml = False lang_attr_name = get_real_fieldname ( field , language_code ) i18n_attr . name = lang_attr_name i18n_attr . creation_counter = i18n_attr . creation_counter + .01 * cnt if not i18n_attr . null and i18n_attr . default is NOT_PROVIDED : i18n_attr . null = True if language_code != msgid_language : if not i18n_attr . blank : i18n_attr . blank = True if i18n_attr . verbose_name : i18n_attr . verbose_name = translation . string_concat ( i18n_attr . verbose_name , u' (%s)' % language_code ) cls . add_to_class ( lang_attr_name , i18n_attr ) del cls . _meta . local_fields [ cls . _meta . local_fields . index ( original_attr ) ] kwargs = { 'serialize' : getattr ( original_attr , 'serialize' , True ) , 'extra_attrs' : getattr ( original_attr , 'extra_attrs' , None ) , 'max_length' : getattr ( original_attr , 'max_length' , None ) , 'min_length' : getattr ( original_attr , 'min_length' , None ) , 'form_field' : original_attr . formfield ( ** FORMFIELD_FOR_DBFIELD_DEFAULTS . get ( original_attr . __class__ , { } ) ) , 'get_internal_type' : original_attr . get_internal_type , 'unique' : getattr ( original_attr , 'unique' , False ) , 'to_python' : original_attr . to_python , } if hasattr ( original_attr , '__serialize__' ) : kwargs [ '__serialize__' ] = original_attr . __serialize__ cls . add_to_class ( field , DefaultFieldDescriptor ( field , ** kwargs ) ) try : cls . _meta . _fill_fields_cache ( ) except AttributeError : cls . _meta . _expire_cache ( ) cls . _meta . _get_fields ( reverse = False ) return cls
For each field name in localized_fields,
    for each language in settings.LANGUAGES,
    add fields to cls,
    and remove the original field, instead
    replace it with a DefaultFieldDescriptor,
    which always returns the field in the current language.