def __call__(self, cls):
        """run the filter on the class to be decorated"""
        if hasattr(cls, 'model'):
            self.model = cls.model
        elif not self.model:
            raise AttributeError(L10n.error_no_model % (cls.__name__) )

        # gather names of fields added by I18n
        added_fields = []
        for field in self.model.localized_fields:
            for language in get_all_language_codes():
                added_fields.append(get_real_fieldname(field, language))

        # determine name of the permission to edit untranslated fields
        permisson_name = "%s.can_edit_untranslated_fields_of_%s" % (
            self.model._meta.app_label, self.model.__name__.lower()
        )
        
        # make sure that fields become read_only when no permission is given.
        def get_readonly_fields(self, request, obj=None):
            if not request.user.has_perm(permisson_name):
                fields = self.fields or map(lambda x: x.name, self.model._meta.fields)
                # remove primary key because we don't show that, not even uneditable
                fields.pop(self.model._meta.pk_index())
                prohibited_fields = compute_prohibited(fields, self.exclude, self.model.localized_fields)
                
                return set(self.readonly_fields).union(prohibited_fields)
            
            return self.readonly_fields
        
        cls.get_readonly_fields = get_readonly_fields
        
        # override some views to hide fields which are not localized
        if hasattr(cls, 'change_view'):
            # BaseModelAdmin.__init__ will mess up our lazy lists if the following is
            # not allready defined
            if 'action_checkbox' not in cls.list_display and cls.actions is not None:
                cls.list_display = ['action_checkbox'] +  list(cls.list_display)
            
            if not cls.list_display_links:
                for name in cls.list_display:
                    if name != 'action_checkbox':
                        cls.list_display_links = [name]
                        break

            # Make certain properties lazy and internationalized
            cls.list_display_links = all_lazy_localized_list(cls.list_display_links, self.model.localized_fields)
            cls.list_display = all_lazy_localized_list(cls.list_display, self.model.localized_fields)
            cls.list_editable = all_lazy_localized_list(cls.list_editable, self.model.localized_fields)
            cls.search_fields = all_lazy_localized_list(cls.search_fields, self.model.localized_fields)
        
        return cls
Example #2
0
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
        cls._meta._fill_fields_cache()

    # return the finished product
    return cls
Example #3
0
 def __restoreBlank(self, cls, blankFlags):
     for field, blank in zip(self.localizedFields, blankFlags):
         for code in get_all_language_codes():
             i18n_attr = get_field_from_model_by_name(
                 cls, getLocalizedFieldName(field, code))
             i18n_attr.blank = blank
Example #4
0
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
Example #5
0
 def __restoreBlank(self, cls, blankFlags):
   for field, blank in zip(self.localizedFields, blankFlags):
     for code in get_all_language_codes():
       i18n_attr = get_field_from_model_by_name(cls, getLocalizedFieldName(field, code))
       i18n_attr.blank = blank
Example #6
0
    def __call__(self, cls):
        """run the filter on the class to be decorated"""
        if hasattr(cls, 'model'):
            self.model = cls.model
        elif not self.model:
            raise AttributeError(L10n.error_no_model % (cls.__name__))

        # gather names of fields added by I18n
        added_fields = []
        for field in self.model.localized_fields:
            for language in get_all_language_codes():
                added_fields.append(get_real_fieldname(field, language))

        # hide added fields from form and admin
        cls.exclude = added_fields
        cls.form = forms.make_localised_form(self.model,
                                             cls.form,
                                             exclude=added_fields)

        # determine name of the permission to edit untranslated fields
        permisson_name = "%s.can_edit_untranslated_fields_of_%s" % (
            self.model._meta.app_label, self.model.__name__.lower())

        # make sure that fields become read_only when no permission is given.
        def get_readonly_fields(self, request, obj=None):
            if not request.user.has_perm(permisson_name):
                fields = self.fields or map(lambda x: x.name,
                                            self.model._meta.fields)
                # remove primary key because we don't show that, not even uneditable
                fields.pop(self.model._meta.pk_index())
                prohibited_fields = compute_prohibited(
                    fields, self.exclude, self.model.localized_fields)

                return set(self.readonly_fields).union(prohibited_fields)

            return self.readonly_fields

        cls.get_readonly_fields = get_readonly_fields

        # override some views to hide fields which are not localized
        if hasattr(cls, 'change_view'):
            # BaseModelAdmin.__init__ will mess up our lazy lists if the following is
            # not allready defined
            if 'action_checkbox' not in cls.list_display and cls.actions is not None:
                cls.list_display = ['action_checkbox'] + list(cls.list_display)

            if not cls.list_display_links:
                for name in cls.list_display:
                    if name != 'action_checkbox':
                        cls.list_display_links = [name]
                        break

            # Make certain properties lazy and internationalized
            cls.list_display_links = lazy_localized_list(
                cls.list_display_links, self.model.localized_fields)
            cls.list_display = lazy_localized_list(cls.list_display,
                                                   self.model.localized_fields)
            cls.list_editable = lazy_localized_list(
                cls.list_editable, self.model.localized_fields)
            cls.search_fields = lazy_localized_list(
                cls.search_fields, self.model.localized_fields)

        else:

            def get_formset(self, request, obj=None, **kwargs):
                if self.declared_fieldsets:
                    fields = flatten_fieldsets(self.declared_fieldsets)
                else:
                    fields = None
                if self.exclude is None:
                    exclude = []
                else:
                    exclude = list(self.exclude)
                exclude.extend(self.get_readonly_fields(request, obj))
                exclude = exclude or None

                if not hasattr(self, 'ct_fk_field'):
                    return super(cls, self).get_formset(request, obj, **kwargs)
                else:
                    # TODO:
                    # this code can be deleted if django fixes GenericInlineModelAdmin it's
                    # get_formset signature so it looks like InlineModelAdmin
                    defaults = {
                        "ct_field": self.ct_field,
                        "fk_field": self.ct_fk_field,
                        "form": self.form,
                        "formfield_callback": self.formfield_for_dbfield,
                        "formset": self.formset,
                        "extra": self.extra,
                        "can_delete": self.can_delete,
                        "can_order": False,
                        "fields": fields,
                        "max_num": self.max_num,
                        "exclude": exclude
                    }

                    defaults.update(kwargs)
                    # the BaseGenericInlineFormSet does not work too well
                    # with modified models, so use LocalizableGenericInlineFormSet.
                    if self.formset is BaseGenericInlineFormSet \
                        or self.formset.__class__ is BaseGenericInlineFormSet:
                        defaults['formset'] = LocalizableGenericInlineFormSet

                    return generic_inlineformset_factory(
                        self.model, **defaults)

            cls.get_formset = get_formset

        return cls
Example #7
0
    def __call__(self, cls):
        """run the filter on the class to be decorated"""
        if hasattr(cls, 'model'):
            self.model = cls.model
        elif not self.model:
            raise AttributeError(L10n.error_no_model % (cls.__name__) )

        # gather names of fields added by I18n
        added_fields = []
        for field in self.model.localized_fields:
            for language in get_all_language_codes():
                added_fields.append("%s_%s" % (field, language))

        # hide added fields from form and admin
        cls.exclude = added_fields
        cls.form = forms.make_localised_form(self.model, cls.form, exclude=added_fields)

        # determine name of the permission to edit untranslated fields
        permisson_name = "%s.can_edit_untranslated_fields_of_%s" % (
            self.model._meta.app_label, self.model.__name__.lower()
        )
        
        # make sure that fields become read_only when no permission is given.
        def get_readonly_fields(self, request, obj=None):
            if not request.user.has_perm(permisson_name):
                fields = self.fields or map(lambda x: x.name, self.model._meta.fields)
                # remove primary key because we don't show that, not even uneditable
                fields.pop(self.model._meta.pk_index())
                prohibited_fields = compute_prohibited(fields, self.exclude, self.model.localized_fields)
                
                return set(self.readonly_fields).union(prohibited_fields)
            
            return self.readonly_fields
        
        cls.get_readonly_fields = get_readonly_fields
        
        # override some views to hide fields which are not localized
        if hasattr(cls, 'change_view'):
            # BaseModelAdmin.__init__ will mess up our lazy lists if the following is
            # not allready defined
            if 'action_checkbox' not in cls.list_display and cls.actions is not None:
                cls.list_display = ['action_checkbox'] +  list(cls.list_display)
            
            if not cls.list_display_links:
                for name in cls.list_display:
                    if name != 'action_checkbox':
                        cls.list_display_links = [name]
                        break

            # Make certain properties lazy and internationalized
            cls.list_display_links = lazy_localized_list(cls.list_display_links, self.model.localized_fields)
            cls.list_display = lazy_localized_list(cls.list_display, self.model.localized_fields)
            cls.list_editable = lazy_localized_list(cls.list_editable, self.model.localized_fields)
            cls.search_fields = lazy_localized_list(cls.search_fields, self.model.localized_fields)
            
        else:
            def get_formset(self, request, obj=None, **kwargs):
                if self.declared_fieldsets:
                    fields = flatten_fieldsets(self.declared_fieldsets)
                else:
                    fields = None
                if self.exclude is None:
                    exclude = []
                else:
                    exclude = list(self.exclude)
                exclude.extend(self.get_readonly_fields(request, obj))
                exclude = exclude or None

                if not hasattr(self, 'ct_fk_field'):
                    return super(cls, self).get_formset(request, obj, **kwargs)
                else:
                    # TODO:
                    # this code can be deleted if django fixes GenericInlineModelAdmin it's
                    # get_formset signature so it looks like InlineModelAdmin
                    defaults = {
                        "ct_field": self.ct_field,
                        "fk_field": self.ct_fk_field,
                        "form": self.form,
                        "formfield_callback": self.formfield_for_dbfield,
                        "formset": self.formset,
                        "extra": self.extra,
                        "can_delete": self.can_delete,
                        "can_order": False,
                        "fields": fields,
                        "max_num": self.max_num,
                        "exclude": exclude
                    }
                    
                    defaults.update(kwargs)
                    # the BaseGenericInlineFormSet does not work too well
                    # with modified models, so use LocalizableGenericInlineFormSet.
                    if self.formset is BaseGenericInlineFormSet \
                        or self.formset.__class__ is BaseGenericInlineFormSet:
                        defaults['formset'] = LocalizableGenericInlineFormSet
                        
                    return generic_inlineformset_factory(self.model, **defaults)
            
            cls.get_formset = get_formset
        
            
        return cls