|  | 
| 8 | 8 | # Ensure that models are registered for translation before TranslationAdmin | 
| 9 | 9 | # runs. The import is supposed to resolve a race condition between model import | 
| 10 | 10 | # and translation registration in production (see issue #19). | 
|  | 11 | +from django.utils.safestring import mark_safe | 
| 11 | 12 | import modeltranslation.models  # NOQA | 
| 12 | 13 | from modeltranslation.settings import DEFAULT_LANGUAGE | 
| 13 | 14 | from modeltranslation.translator import translator | 
| 14 | 15 | from modeltranslation.utils import ( | 
| 15 |  | -    get_translation_fields, build_css_class, build_localized_fieldname, get_language) | 
|  | 16 | +    get_translation_fields, build_css_class, build_localized_fieldname, get_language, | 
|  | 17 | +    build_localized_verbose_name) | 
| 16 | 18 | 
 | 
| 17 | 19 | 
 | 
| 18 | 20 | class TranslationBaseModelAdmin(BaseModelAdmin): | 
| @@ -196,11 +198,52 @@ def get_translation_field_excludes(self, exclude_languages=None): | 
| 196 | 198 |                     exclude.append(tfield) | 
| 197 | 199 |         return tuple(exclude) | 
| 198 | 200 | 
 | 
|  | 201 | +    def _make_readonly_func(self, readonly_field): | 
|  | 202 | +        field = self.model._meta.get_field(readonly_field) | 
|  | 203 | + | 
|  | 204 | +        def func(self, obj): | 
|  | 205 | +            # Wrap the markup rendered by AdminReadonlyField in a hidden span | 
|  | 206 | +            # with custom modeltranslation specific css class to mimic a field. | 
|  | 207 | +            return mark_safe( | 
|  | 208 | +                '<span id="id_%s" class="mt mt-readonly mt-field-%s-%s">%s</span>' % ( | 
|  | 209 | +                    readonly_field, field.translated_field.name, field.language.replace('-', '_'), | 
|  | 210 | +                    getattr(obj, readonly_field))) | 
|  | 211 | +        # Forgive me, for i don't know what i'm doing... | 
|  | 212 | +        func.__name__ = str( | 
|  | 213 | +            unicode(build_localized_verbose_name(field.translated_field.name, field.language))) | 
|  | 214 | +        #func.__name__ = readonly_field | 
|  | 215 | +        return func | 
|  | 216 | + | 
| 199 | 217 |     def get_readonly_fields(self, request, obj=None): | 
| 200 | 218 |         """ | 
| 201 | 219 |         Hook for specifying custom readonly fields. | 
| 202 | 220 |         """ | 
| 203 |  | -        return self.replace_orig_field(self.readonly_fields) | 
|  | 221 | +        readonly_fields = self.replace_orig_field(self.readonly_fields) | 
|  | 222 | +        # Note: A field defined in ModelAdmin.readonly_fields isn't rendered as | 
|  | 223 | +        # a form field in admin. Since we rely on the custom css classes we add | 
|  | 224 | +        # to the form fields through patch_translation_field in tabbed translation | 
|  | 225 | +        # fields, readonly fields won't be tabbed. | 
|  | 226 | +        if readonly_fields: | 
|  | 227 | +            # Add a dynamic callable per translation to the admin class. This | 
|  | 228 | +            # is actually an undocumented feature in ModelAdmin and might | 
|  | 229 | +            # bite us hard, but it seems to be the only way to modify the | 
|  | 230 | +            # rendered output without monkeypatching the entire | 
|  | 231 | +            # AdminReadonlyField class. But is what we try here any better? | 
|  | 232 | +            readonly_fields_new = [] | 
|  | 233 | +            for readonly_field in readonly_fields: | 
|  | 234 | +                readonly_func = self._make_readonly_func(readonly_field) | 
|  | 235 | +                readonly_fields_new.append(readonly_func.__name__) | 
|  | 236 | +                if not hasattr(TranslationBaseModelAdmin, readonly_func.__name__): | 
|  | 237 | +                    setattr(TranslationBaseModelAdmin, readonly_func.__name__, readonly_func) | 
|  | 238 | +                # Replace the original readonly_fields with the dynamic callables | 
|  | 239 | +                readonly_fields = readonly_fields_new | 
|  | 240 | +                # And add the original readonly_fields to exclude, so they doesn't | 
|  | 241 | +                # end up in the form. FIXME: At least one admin test will fail now. | 
|  | 242 | +                if self.exclude: | 
|  | 243 | +                    self.exclude.append(readonly_field) | 
|  | 244 | +                else: | 
|  | 245 | +                    self.exclude = [readonly_field] | 
|  | 246 | +        return readonly_fields | 
| 204 | 247 | 
 | 
| 205 | 248 | 
 | 
| 206 | 249 | class TranslationAdmin(TranslationBaseModelAdmin, admin.ModelAdmin): | 
|  | 
0 commit comments