Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[solved]Multi-language support for snippets #566

Closed
redwired opened this issue Apr 4, 2023 · 5 comments
Closed

[solved]Multi-language support for snippets #566

redwired opened this issue Apr 4, 2023 · 5 comments
Labels
Type: Enhancement New feature or functionality change

Comments

@redwired
Copy link

redwired commented Apr 4, 2023

Hi,

I'm trying to use WagtailCRX for a multi-languages website (french, japanese and english).

I started implementing i18n with wagtail-localize and it seems to be working as intended for pages content.

However, I cant make it work with CRX snippets.

I'm trying to follow the wagtail official documentation:

https://docs.wagtail.org/en/stable/advanced_topics/i18n.html#translatable-snippets

At first, I tried to customize footer and navbar snippets in my website/models.py by unregistering the default ones and redefine my own classes by adding the TranslatableMixin behavior and inherit the default snippets classes.

For example, to redefine Footer, I tried some dirty hack like this one :

# removing previously registered coderedcms snippets to replace them with
# a custom child class implementing TranslatableMixin
DEFERRED_REGISTRATIONS.remove((coderedcms.models.snippet_models.Footer, None))

@register_snippet
class Footer(TranslatableMixin, coderedcms.models.snippet_models.Footer):
    class Meta(TranslatableMixin.Meta):
        verbose_name = _("Footer")

After I made all the needed migrations with BootstrapTranslatableMixin as explained in the wagtail's documentation, I managed to get translatable snippets on the admin.

However, if I select my Footer on the CRX Settings menu, its will stick to one selected language and doesn't translate at all.

I understood that in the database I have the 2 models (base and inherited), but only my redefined model has the language support.

It looks like CRX takes the base class (coderedcms.models.snippet_models.Footer) to render the snippet.

I tried to redefine a footer without inherit your base class, but then I had no footer choice at all.

I'm wondering if what I want to do is even possible without modifying the WagtailCRX library ? Or perhaps I just make it wrong (im a seasoned developer, but still a beginner with python/django/wagtail) ?

If not possible, do you plan to implement multiple language support at some point ?

I sincerely think multiple-language support would be a real added value for WagtailCRX. But on the other hand I also understand it can be a difficult upgrade, as it could need some deep rework and consequent (and risky) DB migration for your clients.

On my side, I can try to make it works by modifying coderedcms itself. But I dont want to work on something you already planned. And I don't like the idea to fork (and maintain) another version of your repo either.

So, what do you think/suggest I do to get it works as I intended ?

Thanks in advance.

@redwired redwired added the Type: Enhancement New feature or functionality change label Apr 4, 2023
@vsalvino
Copy link
Contributor

vsalvino commented Apr 4, 2023

Thanks for providing all the details. It is probably not possible to translate our built-in Navbar and Footer models, because they are concrete in coderedcms, and therefore cannot be altered. This was a design mistake that was made early on. The long-term plan is to eventually make all models abstract, so that the client can define them in local code and make customizations as necessary. See issue #56

However, in the short-term, my recommendation is to use a custom Navbar and Footer. Simply ignore the built-in ones from coderedcms.

First, define a custom snippet as normal. You can copy the implementation of the built-in ones here: https://github.com/coderedcorp/coderedcms/blob/dev/coderedcms/models/snippet_models.py

Second, override the HTML templates (specifically navbar.html and footer.html from here https://github.com/coderedcorp/coderedcms/tree/dev/coderedcms/templates/coderedcms/snippets) to render your own models instead. You may need to create a templatetag to query them.

@redwired
Copy link
Author

redwired commented Apr 4, 2023

Thanks for you advice. I was also thinking about rewriting a whole new snippet, but wanted to be sure about it.

I can close this issue now.

@redwired redwired closed this as completed Apr 4, 2023
@redwired
Copy link
Author

I'm reopening this comment as I eventually succeeded to make this work !

After trying several ways, I came back to my first intuition to inherit from the base, non translatable, snippet.

In the website/models.py, I took advantage of the deferred registration to unregister the coderedcms predefined snippets models.

Then I defined and registered new custom models inheriting from the former ones.

Then, I used a trick and monkey patched the coderedcms original model classes with my new one.

I made this for Navbar and Footer as they are those two which are mostly annoying in my case.

Here's the code I added to models.py


import coderedcms.models.snippet_models

from wagtail.models import TranslatableMixin
from wagtail.snippets.models import DEFERRED_REGISTRATIONS, register_snippet

from django.utils.translation import gettext_lazy as _

# hack to remove previously registered coderedcms snippets as they are being replaced
# with custom snippets implementing TranslatableMixin (in models/snippet_models.py)
DEFERRED_REGISTRATIONS.remove((coderedcms.models.snippet_models.Navbar, None))
DEFERRED_REGISTRATIONS.remove((coderedcms.models.snippet_models.Footer, None))


@register_snippet
class Navbar(TranslatableMixin, coderedcms.models.snippet_models.Navbar):
    class Meta(TranslatableMixin.Meta):
        verbose_name = _("Navigation Bar")


@register_snippet
class Footer(TranslatableMixin, coderedcms.models.snippet_models.Footer):
    class Meta(TranslatableMixin.Meta):
        verbose_name = _("Footer")


# dirty "Monkey Patching" to change default CRX snippets behavior
# to inherit of TranslatableMixin
coderedcms.models.snippet_models.Navbar = Navbar
coderedcms.models.snippet_models.Footer = Footer

Also dont forget to build migrations with After I made all the needed migrations with BootstrapTranslatableMixin as explained in the wagtail's documentation: https://docs.wagtail.org/en/stable/advanced_topics/i18n.html#translatable-snippets )

Finally, I had to slightly modify my customized navbar.html and footer.html templates to use the "localized" property provided by TranslatableMixin.

https://docs.wagtail.org/en/stable/reference/pages/model_reference.html#wagtail.models.TranslatableMixin.localized

(see https://docs.coderedcorp.com/wagtail-crx/how_to/headers_and_footers.html for customization tutorial)

here is my footer.html :


{% load wagtailcore_tags coderedcms_tags i18n %}

{% if settings.coderedcms.LayoutSettings.site_footer %}
<footer>
  {% get_footers as footers %}
  {% for footer in footers %}
  <div {% if footer.custom_id %}id="{{footer.custom_id}}"{% endif %} {% if footer.custom_css_class %}class="{{footer.custom_css_class}}"{% endif %}>
    {% for item in footer.localized.content %}
    {% include_block item with settings=settings %}
    {% endfor %}
  </div>
  {% endfor %}
</footer>
{% endif %}

I guess there must be better ways to solve the problem. For instance, I'm not sure the "localized" property uses wagtail cache. But it works and most important: it still based on the coderedcms concrete classes definitions via inheritance, and doesn't requires any built-in source code modifications.

@redwired redwired reopened this Apr 12, 2023
@redwired redwired changed the title Multi-language support for snippets ? [solved]Multi-language support for snippets Apr 12, 2023
@vsalvino
Copy link
Contributor

vsalvino commented Apr 13, 2023

That is quite a clever hack/workaround. Glad you got it working! Our goal is to eventually make all models abstract (#56) so that this won't be an issue, but that is still a long way out.

Everything and anything will work with wagtail-cache. It works by looking at the final rendered page, then storing that in the cache based on HTTP headers and URL. So the English version and French version would be cached separately for example, as long as they use separate URLs or separate HTTP lang headers.

@vsalvino
Copy link
Contributor

Closing this due to inactivity. Feel free to re-open if you are still experiencing the issue or have any new information. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement New feature or functionality change
Projects
None yet
Development

No branches or pull requests

2 participants