diff --git a/README.rst b/README.rst index 2c146e8..5dd37d1 100755 --- a/README.rst +++ b/README.rst @@ -58,6 +58,7 @@ Quick start ... 'wagtail_modeltranslation', 'wagtail_modeltranslation.makemigrations', + 'wagtail_modeltranslation.migrate', ) 3. Add 'django.middleware.locale.LocaleMiddleware' to ``MIDDLEWARE`` on your ``settings.py``:: diff --git a/docs/advanced settings.rst b/docs/advanced settings.rst index e7a1f43..a5d32b5 100644 --- a/docs/advanced settings.rst +++ b/docs/advanced settings.rst @@ -28,3 +28,15 @@ This setting behaves as the above but should be used for panels that are compose .. code-block:: python WAGTAILMODELTRANSLATION_CUSTOM_COMPOSED_PANELS = ['app_x.module_y.PanelZ'] + + +``WAGTAILMODELTRANSLATION_TRANSLATE_SLUGS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Default: ``True`` + +This setting makes slug and url_path localized. If True, each page will have a slug and url_path per language. + +.. code-block:: python + + WAGTAILMODELTRANSLATION_TRANSLATE_SLUGS = True diff --git a/wagtail_modeltranslation/patch_wagtailadmin.py b/wagtail_modeltranslation/patch_wagtailadmin.py index ce61762..8ba17b3 100644 --- a/wagtail_modeltranslation/patch_wagtailadmin.py +++ b/wagtail_modeltranslation/patch_wagtailadmin.py @@ -20,10 +20,12 @@ from modeltranslation.translator import translator, NotRegistered from modeltranslation.utils import build_localized_fieldname, get_language from wagtail.contrib.settings.models import BaseSetting from wagtail.contrib.settings.views import get_setting_edit_handler + try: from wagtail.contrib.routable_page.models import RoutablePageMixin from wagtail.admin.edit_handlers import FieldPanel, \ - MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel + MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel,\ + extract_panel_definitions_from_model_class, ObjectList from wagtail.core.models import Page, Site from wagtail.core.fields import StreamField, StreamValue from wagtail.core.url_routing import RouteResult @@ -35,7 +37,8 @@ try: except ImportError: from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin from wagtail.wagtailadmin.edit_handlers import FieldPanel, \ - MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel + MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel,\ + extract_panel_definitions_from_model_class, ObjectList from wagtail.wagtailcore.models import Page, Site from wagtail.wagtailcore.fields import StreamField, StreamValue from wagtail.wagtailcore.url_routing import RouteResult @@ -117,16 +120,17 @@ class WagtailTranslator(object): _patch_stream_field_meaningful_value(descriptor) # OVERRIDE PAGE METHODS - model.set_url_path = _new_set_url_path - model.route = _new_route - model._update_descendant_url_paths = _new_update_descendant_url_paths - if not hasattr(model, '_get_site_root_paths'): - model.get_url_parts = _new_get_url_parts # Wagtail<1.11 - model._get_site_root_paths = _new_get_site_root_paths - _patch_clean(model) + if TRANSLATE_SLUGS: + model.set_url_path = _new_set_url_path + model.route = _new_route + model._update_descendant_url_paths = _new_update_descendant_url_paths + if not hasattr(model, '_get_site_root_paths'): + model.get_url_parts = _new_get_url_parts # Wagtail<1.11 + model._get_site_root_paths = _new_get_site_root_paths + _patch_clean(model) - if not model.save.__name__.startswith('localized'): - setattr(model, 'save', LocalizedSaveDescriptor(model.save)) + if not model.save.__name__.startswith('localized'): + setattr(model, 'save', LocalizedSaveDescriptor(model.save)) def _patch_other_models(self, model): if hasattr(model, 'edit_handler'): @@ -135,11 +139,13 @@ class WagtailTranslator(object): tab.children = self._patch_panels(tab.children) elif hasattr(model, 'panels'): model.panels = self._patch_panels(model.panels) - - if model in get_snippet_models() and model in SNIPPET_EDIT_HANDLERS: - del SNIPPET_EDIT_HANDLERS[model] else: - get_setting_edit_handler.cache_clear() + panels = extract_panel_definitions_from_model_class(model) + translation_registered_fields = translator.get_options_for_model(model).fields + panels = filter(lambda field: field.field_name not in translation_registered_fields, panels) + edit_handler = ObjectList(panels) + + SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to_model(model) def _patch_panels(self, panels_list, related_model=None): """ diff --git a/wagtail_modeltranslation/settings.py b/wagtail_modeltranslation/settings.py index c3eadf8..d777651 100644 --- a/wagtail_modeltranslation/settings.py +++ b/wagtail_modeltranslation/settings.py @@ -10,3 +10,4 @@ CUSTOM_SIMPLE_PANELS = [import_from_string(panel_class) for panel_class in getattr(settings, 'WAGTAILMODELTRANSLATION_CUSTOM_SIMPLE_PANELS', [])] CUSTOM_COMPOSED_PANELS = [import_from_string(panel_class) for panel_class in getattr(settings, 'WAGTAILMODELTRANSLATION_CUSTOM_COMPOSED_PANELS', [])] +TRANSLATE_SLUGS = getattr(settings, 'WAGTAILMODELTRANSLATION_TRANSLATE_SLUGS', True) diff --git a/wagtail_modeltranslation/static/wagtail_modeltranslation/js/wagtail_translated_slugs.js b/wagtail_modeltranslation/static/wagtail_modeltranslation/js/wagtail_translated_slugs.js index 5b60bd1..80c8e1a 100644 --- a/wagtail_modeltranslation/static/wagtail_modeltranslation/js/wagtail_translated_slugs.js +++ b/wagtail_modeltranslation/static/wagtail_modeltranslation/js/wagtail_translated_slugs.js @@ -8,13 +8,13 @@ $(document).ready(function () { $('#id_title_' + lang_code).on('focus', function () { /* slug should only follow the title field if its value matched the title's value at the time of focus */ var currentSlug = $('#id_slug_' + lang_code).val(); - var slugifiedTitle = cleanForSlug(this.value); + var slugifiedTitle = cleanForSlug(this.value, true); slugFollowsTitle = (currentSlug == slugifiedTitle); }); $('#id_title_' + lang_code).on('keyup keydown keypress blur', function () { if (slugFollowsTitle) { - var slugifiedTitle = cleanForSlug(this.value); + var slugifiedTitle = cleanForSlug(this.value, true); $('#id_slug_' + lang_code).val(slugifiedTitle); } }); diff --git a/wagtail_modeltranslation/tests/models.py b/wagtail_modeltranslation/tests/models.py index 7a9d894..6308a73 100755 --- a/wagtail_modeltranslation/tests/models.py +++ b/wagtail_modeltranslation/tests/models.py @@ -52,9 +52,13 @@ class PatchTestPage(WagtailPage): @register_snippet -class PatchTestSnippet(models.Model): +class PatchTestSnippetNoPanels(models.Model): name = models.CharField(max_length=10) + +@register_snippet +class PatchTestSnippet(PatchTestSnippetNoPanels): + panels = [ FieldPanel('name') ] diff --git a/wagtail_modeltranslation/tests/settings.py b/wagtail_modeltranslation/tests/settings.py index 0c50767..b8d06c8 100755 --- a/wagtail_modeltranslation/tests/settings.py +++ b/wagtail_modeltranslation/tests/settings.py @@ -21,3 +21,5 @@ MODELTRANSLATION_AUTO_POPULATE = False MODELTRANSLATION_FALLBACK_LANGUAGES = {'default': (MODELTRANSLATION_DEFAULT_LANGUAGE,)} ROOT_URLCONF = 'wagtail_modeltranslation.tests.urls' + +TRANSLATE_SLUGS = True diff --git a/wagtail_modeltranslation/tests/tests.py b/wagtail_modeltranslation/tests/tests.py index 87851db..192d805 100755 --- a/wagtail_modeltranslation/tests/tests.py +++ b/wagtail_modeltranslation/tests/tests.py @@ -303,6 +303,8 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase): def test_snippet_patching(self): self.check_fieldpanel_patching(panels=models.FieldPanelSnippet.panels) + self.check_panels_patching(models.FieldPanelSnippet, ['name_de', 'name_en']) + self.check_imagechooserpanel_patching(panels=models.ImageChooserPanelSnippet.panels) self.check_fieldrowpanel_patching(panels=models.FieldRowPanelSnippet.panels) self.check_streamfieldpanel_patching(panels=models.StreamFieldPanelSnippet.panels) @@ -312,6 +314,24 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase): # which is the SnippetInlineModel self.check_inlinepanel_patching(panels=models.SnippetInlineModel.panels) + # Case we don't define panels on snippet + self.check_panels_patching(models.PatchTestSnippetNoPanels, ['name_de', 'name_en']) + + def check_panels_patching(self, model, model_fields): + patched_edit_handler = get_snippet_edit_handler(model) + + if VERSION[0] < 2: + form = patched_edit_handler.get_form_class(model) + else: + form = patched_edit_handler.get_form_class() + + try: + # python 3 + self.assertEqual(model_fields, list(form.base_fields.keys())) + except AttributeError: + # python 2.7 + self.assertItemsEqual(model_fields, form.base_fields.keys()) + def test_page_form(self): """ In this test we use the InlinePanelPage model because it has all the possible "patchable" fields @@ -353,10 +373,6 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase): In this test we use the InlinePanelSnippet model because it has all the possible "patchable" fields so if the created form has all fields the the form was correctly patched """ - try: - from wagtail.snippets.views.snippets import get_snippet_edit_handler - except ImportError: - from wagtail.wagtailsnippets.views.snippets import get_snippet_edit_handler snippet_edit_handler = get_snippet_edit_handler(models.InlinePanelSnippet) if VERSION < (2,): diff --git a/wagtail_modeltranslation/tests/translation.py b/wagtail_modeltranslation/tests/translation.py index 6eb4954..abcb4ef 100755 --- a/wagtail_modeltranslation/tests/translation.py +++ b/wagtail_modeltranslation/tests/translation.py @@ -1,12 +1,29 @@ # coding: utf-8 -from modeltranslation.translator import translator, register, TranslationOptions - -from wagtail_modeltranslation.tests.models import TestRootPage, TestSlugPage1, TestSlugPage2, PatchTestPage, \ - PatchTestSnippet, FieldPanelPage, ImageChooserPanelPage, FieldRowPanelPage, MultiFieldPanelPage, InlinePanelPage, \ - FieldPanelSnippet, ImageChooserPanelSnippet, FieldRowPanelSnippet, MultiFieldPanelSnippet, PageInlineModel, \ - BaseInlineModel, StreamFieldPanelPage, StreamFieldPanelSnippet, SnippetInlineModel, InlinePanelSnippet, \ - TestSlugPage1Subclass, RoutablePageTest +from modeltranslation.translator import (TranslationOptions, register, + translator) +from wagtail_modeltranslation.tests.models import (BaseInlineModel, + FieldPanelPage, + FieldPanelSnippet, + FieldRowPanelPage, + FieldRowPanelSnippet, + ImageChooserPanelPage, + ImageChooserPanelSnippet, + InlinePanelPage, + InlinePanelSnippet, + MultiFieldPanelPage, + MultiFieldPanelSnippet, + PageInlineModel, + PatchTestPage, + PatchTestSnippet, + PatchTestSnippetNoPanels, + RoutablePageTest, + SnippetInlineModel, + StreamFieldPanelPage, + StreamFieldPanelSnippet, + TestRootPage, TestSlugPage1, + TestSlugPage1Subclass, + TestSlugPage2) # Wagtail Models @@ -35,11 +52,14 @@ class PatchTestPageTranslationOptions(TranslationOptions): fields = ('description',) -class PatchTestSnippetTranslationOptions(TranslationOptions): +@register(PatchTestSnippetNoPanels) +class PatchTestSnippetNoPanelsTranslationOptions(TranslationOptions): fields = ('name',) -translator.register(PatchTestSnippet, PatchTestSnippetTranslationOptions) +@register(PatchTestSnippet) +class PatchTestSnippetTranslationOptions(TranslationOptions): + pass # Panel Patching Models diff --git a/wagtail_modeltranslation/translation.py b/wagtail_modeltranslation/translation.py index 8b9538a..82a1266 100644 --- a/wagtail_modeltranslation/translation.py +++ b/wagtail_modeltranslation/translation.py @@ -2,17 +2,23 @@ from modeltranslation.decorators import register from modeltranslation.translator import TranslationOptions +from wagtail_modeltranslation import settings try: from wagtail.core.models import Page except ImportError: from wagtail.wagtailcore.models import Page + + @register(Page) class PageTR(TranslationOptions): fields = ( 'title', - 'slug', 'seo_title', 'search_description', - 'url_path', ) + if settings.TRANSLATE_SLUGS: + fields += ( + 'slug', + 'url_path', + )