From ca26f5b4d536f33458435e46f95128a661127826 Mon Sep 17 00:00:00 2001 From: Rui Martins Date: Fri, 30 Oct 2015 12:03:52 +0000 Subject: [PATCH] Added support for snippets --- wagtail_modeltranslation/models.py | 266 ++++++++++++++++++++++++++++- 1 file changed, 265 insertions(+), 1 deletion(-) diff --git a/wagtail_modeltranslation/models.py b/wagtail_modeltranslation/models.py index 7cec23e..f18c38c 100755 --- a/wagtail_modeltranslation/models.py +++ b/wagtail_modeltranslation/models.py @@ -474,4 +474,268 @@ class TranslationMixin(object): for (id, root_path, root_url) in root_paths: if self.url_path.startswith(root_path): - return ('' if len(root_paths) == 1 else root_url) + reverse('wagtail_serve', args=(self.url_path[len(root_path):],)) + return ('' if len(root_paths) == 1 else root_url) + reverse( + 'wagtail_serve', args=(self.url_path[len(root_path):],)) + + +# WAGTAIL MODELTRANSLATION MIXIN FOR SNIPPETS +#################################### +class SnippetsTranslationMixin(object): + _translation_options = None + _wgform_class = None + _translated = False + _required_fields = [] + + def __init__(self, *args, **kwargs): + super(SnippetsTranslationMixin, self).__init__(*args, **kwargs) + + SnippetsTranslationMixin._translation_options = translator.\ + get_options_for_model( + self.__class__) + + if self.__class__._translated: + return + + edit_handler_class = get_snippet_edit_handler(self.__class__) + SnippetsTranslationMixin._wgform_class =\ + edit_handler_class.get_form_class(self.__class__) + + defined_tabs =\ + SnippetsTranslationMixin._fetch_defined_tabs(self.__class__) + + for tab_name, tab in defined_tabs: + patched_tab = [] + + for panel in tab: + trtab = SnippetsTranslationMixin._patch_panel(self, panel) + + if trtab: + for x in trtab: + patched_tab.append(x) + + setattr(self.__class__, tab_name, patched_tab) + + # DELETE TEMPORARY EDIT HANDLER IN ORDER TO LET WAGTAIL RECONSTRUCT + # NEW EDIT HANDLER BASED ON NEW TRANSLATION PANELS + if self.__class__ in SNIPPET_EDIT_HANDLERS: + del SNIPPET_EDIT_HANDLERS[self.__class__] + edit_handler_class = get_snippet_edit_handler(self.__class__) + + form = edit_handler_class.get_form_class(self.__class__) + for fname, f in form.base_fields.items(): + # set field required on formset level if original field is required + # as well + if fname in self._required_fields: + f.required = True + + if fname in SnippetsTranslationMixin._translation_options.fields\ + and SnippetsTranslationMixin._is_orig_required(fname): + f.required = False + + self.__class__._translated = True + + @staticmethod + def _fetch_defined_tabs(defined_class): + """ + Fetch tabs defined by user in models.py + """ + tabs = () + + # If user has defined panels dict on models.py + if hasattr(defined_class, 'panels'): + # TEST !!! + tabs += (('panels', + copy.deepcopy(defined_class.panels)),) + # Check for common tabs + else: + if hasattr(defined_class, 'content_panels'): + tabs += (('content_panels', + copy.deepcopy(defined_class.content_panels)),) + if hasattr(defined_class, 'promote_panels'): + tabs += (('promote_panels', + copy.deepcopy(defined_class.promote_panels)),) + if hasattr(defined_class, 'settings_panels'): + tabs += (('settings_panels', + copy.deepcopy(defined_class.settings_panels)),) + + return tabs + + @staticmethod + def _patch_panel(instance, panel, inline_tr_options=None): + """ + Generic panel patching function + """ + trpanels = None + + if panel.__class__.__name__ == 'FieldPanel': + trpanels = SnippetsTranslationMixin._patch_fieldpanel( + panel, inline_tr_options) + elif panel.__class__.__name__ == 'MultiFieldPanel': + trpanels = [SnippetsTranslationMixin._patch_multifieldpanel( + panel, inline_tr_options)] + elif panel.__class__.__name__ == 'InlinePanel': + SnippetsTranslationMixin._patch_inlinepanel(instance, panel) + trpanels = [panel] + elif panel.__class__.__name__ == 'StreamFieldPanel': + trpanels = SnippetsTranslationMixin._patch_streamfieldpanel(panel) + else: + trpanels = [panel] + + return trpanels + + @classmethod + def _is_orig_required(cls, field_name, formset=None): + """ + check if original field is required + TODO: + if formset is given, example for inline models. + """ + required = False + + if not formset: + for fname, f in cls._wgform_class.base_fields.items(): + if fname == field_name: + if f.required: + required = True + break + + return required + + # FieldPanel + #################################### + @classmethod + def _patch_fieldpanel(cls, fieldpanel, inline_tr_options=None): + """ + Patch FieldPanels and return one per available language + """ + tr_fields = [] + if inline_tr_options: + tr_fields = inline_tr_options + else: + tr_fields = cls._translation_options.fields + + translated_fieldpanels = [] + if fieldpanel.field_name in tr_fields: + for lang in settings.LANGUAGES: + classes = fieldpanel.classname + + if cls._is_orig_required(fieldpanel.field_name) and\ + (lang[0] == settings.LANGUAGE_CODE): + if ("%s_%s" % (fieldpanel.field_name, lang[0]) + not in cls._required_fields): + cls._required_fields.append("%s_%s" % ( + fieldpanel.field_name, lang[0])) + + translated_field_name = "%s_%s" % ( + fieldpanel.field_name, lang[0]) + translated_fieldpanels.append( + FieldPanel( + translated_field_name, + classname=classes)) + + # delete original field from form + if fieldpanel.field_name in cls._wgform_class._meta.fields: + cls._wgform_class._meta.fields.remove(fieldpanel.field_name) + else: + return [fieldpanel] + + return translated_fieldpanels + + # StreamFieldPanel + #################################### + @classmethod + def _patch_streamfieldpanel(cls, fieldpanel, inline_tr_options=None): + """ + Patch StreamFieldPanels and return one per available language + """ + tr_fields = [] + if inline_tr_options: + tr_fields = inline_tr_options + else: + tr_fields = cls._translation_options.fields + + translated_fieldpanels = [] + if fieldpanel.field_name in tr_fields: + for lang in settings.LANGUAGES: + if cls._is_orig_required(fieldpanel.field_name) and\ + (lang[0] == settings.LANGUAGE_CODE): + if ("%s_%s" % (fieldpanel.field_name, lang[0]) + not in cls._required_fields): + cls._required_fields.append("%s_%s" % ( + fieldpanel.field_name, lang[0])) + + translated_field_name = "%s_%s" % ( + fieldpanel.field_name, lang[0]) + translated_fieldpanels.append( + StreamFieldPanel( + translated_field_name)) + + # delete original field from form + if fieldpanel.field_name in cls._wgform_class._meta.fields: + cls._wgform_class._meta.fields.remove(fieldpanel.field_name) + else: + return [fieldpanel] + + return translated_fieldpanels + + @classmethod + def _patch_multifieldpanel(cls, mfpanel, inline_tr_options=None): + """ + Patch MultiFieldPanel + """ + patched_fields = [] + + for panel in mfpanel.children: + if panel.__class__.__name__ == 'FieldPanel': + for item in cls._patch_fieldpanel(panel, inline_tr_options): + patched_fields.append(item) + elif panel.__class__.__name__ == 'FieldRowPanel': + patched_fields.append( + cls._patch_fieldrowpanel(panel, inline_tr_options)) + else: + patched_fields.append(panel) + + return MultiFieldPanel( + patched_fields, + classname=mfpanel.classname, + heading=mfpanel.heading) + + @classmethod + def _patch_fieldrowpanel(cls, frpanel, inline_tr_options=None): + """ + Patch FieldRowPanel + """ + patched_fields = [] + + for panel in frpanel.children: + if panel.__class__.__name__ == 'FieldPanel': + for item in cls._patch_fieldpanel(panel, inline_tr_options): + patched_fields.append(item) + else: + patched_fields.append(panel) + + return FieldRowPanel( + patched_fields, + classname=frpanel.classname) + + @classmethod + def _patch_inlinepanel(cls, instance, panel): + inline_panels = getattr( + instance.__class__, panel.relation_name).related.model.panels + try: + inline_model_tr_fields = translator.get_options_for_model( + getattr( + instance.__class__, + panel.relation_name).related.model).fields + except NotRegistered: + return None + + translated_inline = [] + for inlinepanel in inline_panels: + for item in cls._patch_fieldpanel( + inlinepanel, inline_model_tr_fields): + translated_inline.append(item) + + getattr( + instance.__class__, panel.relation_name).related.model.panels =\ + translated_inline