Schmella
Schmella

Reputation: 91

Wagtail Custom Translatable Menu

I am new to wagtail and i am working with a custom menu. I set up a custom menu class and use a tag to display the menu-items in the templates. This works fine, however i would need to create different menus depending on what language my site is used in. (i know wagtailmenus exists, however i could not find a satisfying way to create translated menus there either)

I wanted to create a similar translation experience like wagtail-localize does with pages. Is this possible or do i have to take a different approach?

I already tried to use wagtails TranslatableMixin to simply create duplicates of my menu with different translations, however this does not seem to work, because the translate option (like it is done with pages) is missing.

Classes:

class Menu(TranslatableMixin, ClusterableModel):    
    title = models.CharField(max_length=100)
    logo = models.ForeignKey("wagtailimages.Image", blank=True, null=True, on_delete=models.SET_NULL, related_name="menu_logo")
    image = models.ForeignKey("wagtailimages.Image", blank=True, null=True, on_delete=models.SET_NULL, related_name="menu_image")
    slug = AutoSlugField(populate_from="title", editable=True)

    panels = [
        MultiFieldPanel(
            [
                FieldPanel("title"),
                FieldPanel("slug"),
                ImageChooserPanel("logo"),
                ImageChooserPanel("image"),
            ],
            heading="Menu",
        ),
        InlinePanel("menu_items", label="Menu Item"),
    ]

    def __str__(self):
        return self.title

    class Meta(TranslatableMixin.Meta):
        verbose_name = "Menu"



class MenuItem(ClusterableModel, AbstractMenuItem):
    page = ParentalKey("Menu", related_name="menu_items")

    class Meta:
        verbose_name = "Menu Item"

Templatetags:

@register.simple_tag()
def get_menu(slug, authencicated):
    menu = Menu.objects.get(slug=slug)
    all_menu_items = menu.menu_items.all()
    menu_items = []
    for item in all_menu_items:
        if item.show(authencicated):
            menu_items.append(item)
    return {"logo": menu.logo, "image": menu.image, "items": menu_items}

template:

{% get_menu "main-menu" request.user.is_authenticated as menu%}

Upvotes: 3

Views: 1087

Answers (1)

Fuchsi
Fuchsi

Reputation: 164

Here are ways to approach this "manually" without additional packages. First of all please double check your configuration.

On the one hand you could add a translated title to the page models that you are listing in these menus. Call it title_en, for example.

On the other hand you could add these field directly to your MenuItem class:

class MenuItem(ClusterableModel, AbstractMenuItem):
    page = ParentalKey("Menu", related_name="menu_items")
    title_en = models.CharField(max_length=32, verbose_name="English Title")
    title_zh = models.CharField(max_length=32, verbose_name="Chinese Title")

    class Meta:
        verbose_name = "Menu Item"

In the template you can identify the current language and choose the menu accordingly. This also works via a template tag (by passing the language code over or getting the language code within the template tag).

{% load i18n %}

{% get_current_language as current_language_code %}


# You could either pass the current_language_code to your template tag:
{% get_menu('slug', current_language_code) %}


# Or use multiple template tags:
{% if current_language_code == 'zh' %}
    {% get_chinese_menu %}
{% else %}
    {% get_english_fallback_menu %}
{% endif %}

You can also get the current language code in your templatetags.py:

from django.utils.translation import get_language

@register.simple_tag()
def get_menu(slug, ...):
    current_language_code = get_language()
    if current_language_code == 'zh':
        ...
    else:
        ... 

You could use an additional custom template tag to translate the menu items if the structure of the menu is identical:

from django.utils.translation import get_language

@register.simple_tag()
def get_translated_title(item):
    current_language_code = get_language()
    if current_language_code == 'zh':
        return item.title_zh
    return item.title_en  # fallback

Upvotes: 0

Related Questions