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

Wagtailmenu Internationalisation #74

Closed
begonaalvarezd opened this issue Nov 16, 2016 · 21 comments
Closed

Wagtailmenu Internationalisation #74

begonaalvarezd opened this issue Nov 16, 2016 · 21 comments

Comments

@begonaalvarezd
Copy link

Hello! First of all thank you for this package :)

I am adapting my website to be multi-language flowing the oficial Internationalisation tutorial from Wagtail using TranslatedField class because, sadly, I cannot use wagtail-modeltranslation since it not compatible with Django 1.10. I am trying to include, therefore, also an international menu based on the selected language. I have seen that to render the menu titles you do:

for item in menu_items:
        try:
            """
            `menu_items` is a list of `MenuItem` objects, that either links
            to Page instances, or custom URLs
            """
            page = item.link_page
            menuitem = item
            if page and use_specific:
                page = page.specific
            setattr(item, 'text', item.menu_text)
        except AttributeError:
            """
            `menu_items` is a list of `Page` objects, not `MenuItem` objects
            """
            page = item
            menuitem = None
            setattr(item, 'text', page.title)

Is there a possibility to define a simple internationalized title? I have tried and tried but I really dont manage to get it working.

Any help would be appreciated, thanks!

@ababic
Copy link
Collaborator

ababic commented Nov 16, 2016

Hi @begonaalvarezd.

Thanks for the kind words. I'm glad you're finding it useful. Do you have a separate site set up for each language, or are you introducing the different languages in a more integrated way? If you were creating an actual 'Site' for each language, I guess the simplest answer would be to create a separate menu for each site, and they should be picked up automatically.

The text attribute that is added to each menu item is just a convenience thing to help templates remain consistent. If you're writing custom menu templates, you should be able to sub out {{ item.text }} for something else.

In order to access those translated strings on pages, you'll need to use the use_specfic=True option on your menu tag, so that you're dealing with specific objects (that will know about your custom fields) and not vanilla Page objects (that only have the basic Page fields). You could just do {{ item.link_page.specific }} or {{ item.specific }} in your templates, but using the use_specific=True on the tag will get the specific pages with the minimum number of queries possible.

With that in place, it should be possible to swap out {{ item.text}} in templates for {{ item.link_page.translated_title }} (if menu_items is a list of MenuItem objects) or {{ item.translated_title }} (if menu_items is a list of Page objects).

I think you'll still be stuck for MenuItem objects that don't link to pages, though :( With those fields fixed on the MenuItem model, I don't think there's any way to easily define/access translated menu text for those. I can only think of hacky ways involving additional template tags and models.

@begonaalvarezd
Copy link
Author

begonaalvarezd commented Nov 16, 2016

Woooow! That solved the issue! I am serving both translations under the same site so the doubled menu was not an option for me, but your answer is! I have been using your package for couple of days and didnt step into use_specific=True. This is a 1 minute Internationalization! Now it is working perfectly <3

By now I dont plan to have MenuItem objects that dont link to pages, but good to keep in mind :)

Thank you very very much for replying so fast! Great support 👍

@ababic
Copy link
Collaborator

ababic commented Nov 16, 2016

Ah, cool. Glad you managed to work it out :)

The use_specific option is relatively new, and was added for exactly cases like this. It's False by default, because titles and urls are barely ever overridden, and fetching specific pages does add queries and will effect rendering time.

Just a heads up: There are some changes planned for use_specific in the next major release version, so you may have to make some small adjustments if you want to use that. It's still not released yet, though :)

@begonaalvarezd
Copy link
Author

Hello again @ababic

I have a simple new question. I am facing a new issue with you solution for "key page links becoming just 'toggles' in multi-level drop-downs" for multi-language sites. The field repeated_item_text is defined as a CharField, therefore it is not possible for me to create a translated repeated_item_text. I am thinking on creating my own metaclass MultilanguageMenuPage that inherits from your MenuPage and adds a TranslatedField instead of a single CharField but I am afraid this will become very complex at the end. Do you have any suggestion to this issue?

Thank you very much for your time :)

@ababic
Copy link
Collaborator

ababic commented Nov 23, 2016

Hey @begonaalvarezd.

I think you should be able to solve this without resorting to overriding metaclasses :) The repeated menu items are actually added by the MenuPage instance that the menu tag is currently dealing with. I would suggest you start by taking a look at the modify_submenu_items() method on MenuPage. It should be possible to override what's there, and just use different (multilingual) fields to put the repeated menu item together :)

@ababic
Copy link
Collaborator

ababic commented Nov 23, 2016

If you think about how wagtail provides the title field for pages, but you add the additional TranslatedField fields to cater for the multilingual versions... I think you kinda just need to do the same for repeated_item_text, and treat the original as version for your default language. I think you might need to look at overriding the panels on the page too, but shouldn't think it would be much more complicated than that.

I think using an abstract MultilanguageMenuPage model with all that stuff on would probably be a good way to go.

@begonaalvarezd
Copy link
Author

Great! This worked beautifully :) I am very very new to both python and Django and I still over-complicate my solutions hehe.

Thank you so much again for your great support. Solved and closed issue!

@ababic
Copy link
Collaborator

ababic commented Nov 23, 2016

No worries. Multilingual wagtail sites are very common, so my hope is that this conversation will be useful to others trying to solve the same problem. I should probably think about putting a page in the documentation about it, too (when I get around to creating documentation!)

@agelinas
Copy link

Hi,

I have been strugling with switching languages and multilingual menus for the websites I have been working on, for the last two years. I appreciate greatly wagtailmenus. I've got wagtailmodeltranslation working, so I have extra fields for the fields I want to translate (ex. title_en, title_fr, url_path_en, url_path_fr, etc,) and it is working well for me, but when it comes to figuring out how create multilingual menus, it is beyond me.

I like your idea of having some guidelines in the docs on how to create multilingual menus, it would be greatly appreciated. In the meantime, I will get better acquainted with wagtailmenus and try to understand the previous posts on the subject.

Thank you,

Alain

@ababic
Copy link
Collaborator

ababic commented Oct 25, 2017

Hey @agelinas!

The first step is to ensure the use_specific field value for all of your main and flat menu instances is set to 3 (Always). This will ensure the menus are dealing with instances of the page types you've defined in your project (along with all of the translated field values) instead of vanilla Page objects (that only have access to the basic fields from wagtail's Pagemodel).

And, if you're using section_menu or children_menu tags anywhere, you can make those work by using the use_specific template tag argument, or by changing the default value used by each tag by adding the following to your project settings:

WAGTAILMENUS_DEFAULT_CHILDREN_MENU_USE_SPECIFIC = 3
WAGTAILMENUS_DEFAULT_SECTION_MENU_USE_SPECIFIC = 3

For wagtail-modeltranslation, this might be enough, but let me know if not.

EDIT:

You might also want to look at the WAGTAILMENUS_PAGE_FIELD_FOR_MENU_ITEM_TEXT setting too :)

@agelinas
Copy link

Hi @ababic,
Thank you for the guidelines you provided over a year ago! It did work for me using wagtailmodeltranslation and I'm still using the website I implemented wagtailmenus on. I am now upgrading to Django and Wagtail 2 and decided to drop wagtailmodeltranslation because of its dependency on django-modeltranslation and my not being able to get it to work anymore.

So I decided to use the recommended content internalisation in the Wagtail documentation :

class BlogPage(Page):
title_fr = models.CharField(max_length=255)

body_en = StreamField(...)
body_fr = StreamField(...)

.....
class TranslatedField:
def init(self, en_field, fr_field):
self.en_field = en_field
self.fr_field = fr_field

def __get__(self, instance, owner):
    if translation.get_language() == 'fr':
        return getattr(instance, self.fr_field)
    else:
        return getattr(instance, self.en_field)

`
Etc.

I was thinking that if I simply added (duplicated) the fields that need translations for each language : ex. link, link_fr, link_en, and copy the content of the active language into the original field (link in this example) at runtime, would this work ? I think that is how django-modeltranslation works. If so and if you have the time, could you please provide a few guidelines or hints on how to go about it.

Thank you, I much appreciate what you're doing.

@ababic
Copy link
Collaborator

ababic commented Nov 23, 2018

Hi @agelinas,

If you were looking at taking this approach for menus, then you may find this example in the docs useful:

https://wagtailmenus.readthedocs.io/en/latest/advanced_topics/custom_menu_classes.html#replacing-both-the-flatmenu-and-flatmenuitem-models

If most of your menu items are links to pages, and you're wanting to derive menu item text from a similar field on your page models, there's a setting you can use to achieve that:

https://wagtailmenus.readthedocs.io/en/latest/settings_reference.html#wagtailmenus-page-field-for-menu-item-text

EDIT: Removed note on 'using specific pages for menu generation', as wagtailmenus has since been updated to always use specific pages.

Hope this helps! :)

@agelinas
Copy link

agelinas commented Nov 23, 2018

Thanks @ababic

I did find examples in your docs for managing multiple languages by duplicating fields and what is involved (The link you sent me: I should have checked your documentation for updates since I last read it, sorry!) The documentation is very helpful and I already have managed to do the flatmenu adaptations and will soon work on main menu as per your guidelines.

Thank you, much appreciated!

@MrCordeiro
Copy link
Contributor

Hi everyone!

@ababic's links don't work anymore and I was still searching for references on how to internationalize my main menu. I'm currently using wagtail-localize which is the package the Wagtail team is set to be used in order to integrate i18n at the Wagtail core.

From this discussion, I now get I should be creating a custom menu item, but without the documentation references, it's all still very hazy to me.

@ababic
Copy link
Collaborator

ababic commented Dec 6, 2021

Hi @MrCordeiro.

Only the last link there is broken. That's because wagtailmenus has since been simplified so that you don't have to do anything special to get specific pages... it will get them automatically.

@MrCordeiro
Copy link
Contributor

Ah, I see!

So maybe I'm searching for references in the wrong place. Just saw @perepicornell's commend on issue #242... would that be the way to go?

@ababic
Copy link
Collaborator

ababic commented Dec 7, 2021

@MrCordeiro That all depends on how you're doing internationalisation in your project really. The solution on #242 might be the way to go if you're using https://github.com/wagtail/wagtail-localize (with language-specific trees being automatically synced). That's certainly easiest from an editor perspective, as you define the menu once, and that automatically works for all locales.

@MrCordeiro
Copy link
Contributor

@ababic it worked great!

I'm not yet familiarized with all translation options for Wagtail, but that looked like a good solution. Is there a reason (other than the lack of time, of course) why we can't integrate that into the package?

In case there's an impediment, that snippet could perhaps be added as a recipe on the docs instead - which would be something I feel I could tackle with a PR. What do you think? (I could also make the Django 4.0 adaptations while at it too)

@ababic
Copy link
Collaborator

ababic commented Dec 8, 2021

@MrCordeiro I must admit, I've let this app fall off my radar, as it's not something I use any longer (plus, I haven't worked at rkhleics for years). So, any help would be appreciated.

@MrCordeiro
Copy link
Contributor

Fair enough. I didn't even know rkhleics was a company... If they forgot about it, maybe this package should be maintained by jazzband then.

I'll open an issue so I can refer to it and start working on the PR.

@Redjam
Copy link

Redjam commented Feb 24, 2022

Hi there, I use Wagtail-Localize and Wagtailmenus together. I found a solution to make the menu localized but it's so easy that I'm pretty sure I have forgotten something 😅.

I have created a Main Menu and the following template:

{% load i18n menu_tags %}

<ul class="font-title text-black text-2xl tracking-wider space-y-8">
    {% for item in menu_items %}
        <li class="relative px-4">
            <a class="before:w-12 before:h-0.5 before:bg-black before:absolute before:-bottom-2.5 before:left-4 before:opacity-0 before:origin-left before:scale-x-0 before:transition-transform before:duration-500 hover:before:scale-x-100 hover:before:opacity-100"
               href="{{ item.link_page.localized.url }}">{{ item.link_page.localized.title }}</a>
        </li>
    {% endfor %}
</ul>

Using link_page.localized, the url and title that are displayed depend on the location code.

I only create one menu and let the translation happen in the template.

I don't beleive this workarround to be so easy. Where did I miss something? 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants