Translating Menus in Drupal 6

menu translation administration screenFor well over a year Drupal core has supported much more advanced multilingual capabilities compared to previous versions. When Drupal 6 landed all the hard work that Gábor Hojtsy and the internationalization team did was released to the world and people rejoiced (in 60+ languages).

This is a very broad simplification of what was done, but the focus of those efforts was to make it easier for administrators to translate content (nodes) on a site. If you have a news story published in English you can create a French version of that news story that is 'tied' to the English story and it will be easy for your site visitors to switch between the English and French (or Spanish or Dutch etc.) version of your story.

As I said, this is a very broad simplification. There was much more work being done, but not all of it managed to make it into core. Some translations features were left in the contributed i18n (internationalization) module. Others features were 'roughed in' to core to allow for future improvements.

One such feature that didn't quite get finished was menu translations.

Menus can be translated, but its not entirely obvious how to do it. And even after you've read the documentation, it may not necessarily work the way you expect it to. (See example: Menu items disappear when you change language in the Drupal handbook.)

There are two basic ways of translating menus. One is with the i18n module. The other is without. A third might be a combination of both. Since the first method offers the most flexibility I'll start with that.

Menu Translation with i18n

With the first method will need to install the i18n module and enable the "Menu Translation" sub module. By doing this you will be provided with a 'Language' dropdown option whenever you create a new menu item via /admin/build/menu-customize/your-menu-name/add. This language option allows you to select the language the menu item is intended for.

If you select "All Languages", the displayed text of the link in the menu will be translatable via the Drupal "Translation Interface".

This works well if all the links in your menu will go to the same location regardless of which language the user is viewing your site. For example a "home" link that takes a person to the front page of your site.

But what about when the link in the menu will go to a different destination depending on the language? It is no longer sufficient to translate the 'text' of the link, you will also have to change the destination of the link in the menu.

In these cases, when you create a menu item you provide the path to (say) the English content you intend to link to AND select 'English' from the 'language' dropdown. By doing this, the link in the menu will only be displayed if the user is viewing the site in English. You will then have to create a second menu item that links to (say) the French content that matches English content you linked to in the first menu item. For this second link you would select 'French' from the 'language' dropdown so that the menu item will only be displayed when viewing the site in French.

(For more detailed step by step menu translation steps see: http://drupal.org/node/275705 - also linked at the end of this article)

Menu Translation without i18n

The other noteworthy menu translation option that only works for the "Primary Links" and "Secondary Links" menus allows you to use entirely different menus (vs. different menu items) for each language. This method will switch the menu displayed depending on which language the site is being viewed in.

The downside of this method is that it is entirely unintuitive to set up especially for people that may be new to Drupal. And even when set up, the interface to specify which menus to use isn't immediately obvious.

In Drupal 6 a number of system variables are available that could technically have a value for each language your site is configured to use. For example, items like "Site Slogan" (found at admin/settings/site-information) could be configured to display one thing in English and another displayed in French. The same is true for Primary Links and Secondary Links (which is what we are interested in here)

However, none of these translatable system variables are translatable by default. In order to turn on the ability to translate them you must modify the settings.php file for your site to include a special configuration variable.

In the case of the primary and secondary links you would add the following to settings.php:

$conf['i18n_variables'] = array(
  'menu_primary_links_source',
  'menu_secondary_links_source',
);

When you do this a very subtle change occurs on the Menu Settings page (found at admin/build/menus/settings) illustrated in this image. But, this change does not at all make it clear what you have to do to display a different 'Primary Links' menu for each language.

The trick is that you will have to switch the site to display the administrative interface in the language you want to configure the menu for. So if you wanted to tell the site to display a different menu for Primary Links in say French, you would switch to display the interface in French and then pick a menu from the dropdown list under 'Source for Primary Links.'

The 'source' must obviously be an existing menu. Therefore, before you could tell the system to use a different menu you would have had to create a menu and added menu items to it in order for it to appear in that dropdown list. By default all languages will have 'source for primary links' set to the menu called 'Primary Links', but it can be changed to any existing menu you have created.

Once you have selected the source for Primary Links for each of your site's languages, whenever a site visitor switches from one language to another, the menu displayed will be the one you configured for that language.

Conclusions and Links

In short, menu translations aren't the most intuitive feature of Drupal 6. But, with a bit of patience it can be done. I hope this article has helped you in some way better understand how to do it.

If you have any questions, corrections or additional links you want to share please feel free to leave a comment.

April 14th 2009 11PM
By: andre

 

Comments

Perfect example of when Drupal sucks

Thank you for your post it is definitely helpful.

This menu issue is absurd. In a multi-lingual setting the menu is as important as content. i defy anybody to get this right the first time or even the 10th time.

without i18nmenu

Menu Translation without i18nmenu module works for every menu, not only with the primary, secondary menu.

method 1:
create myenglishmenu, mygermanmenu (do not create any variables in settings.php). Display the English (German) menu block only when the active language is English (German). The visibility settings can be done with the block visibility (using simple php code) or with the i18nblocks module..

I prefer this method as all menu items are separated into different menus by language, but

method 2:
you do not need two menus. You can put menu items into the same menu, if your nodes have language set (not language neutral), and i18n module is enabled, and using the default Content selection mode "Current language and language neutral." Then any menu item which links to a node in different language should not be displayed, so you will see menu items for the active language only.

The big problem with Drupal that it has too many options, and users first find the options which do not work..

php language selection

Thanks for the additional method

Re: Pasqualle's method 1:
Yes indeed you can add some block display logic to switch between two menu blocks. This will require a little bit of code as mentioned.

If you are comfortable with writing code you could also write a lightweight module that handles switching menu blocks on and off depending on the language.

Re: Pasqualle's method 2:
This is the method I describe in the post. This makes use of i18n and requires you to specify the language of each menu item. Those menu items will then only display for the language they were configured to use.