Solving your multilingual navigation issues with Entity Translation in Drupal 7

UPDATE: the D7 entity module has changed, and now has support for menus. See my latest post on the topic for more up-to-date information.

This blog post has been a long time coming. I have been using Entity Translation, Drupal 7's new interface to doing translations, for the better part of this past year. It has been an exciting adventure, but with every new way of doing things there are some dragons along the path. In this post, I think I have solved one of my last great challenges with it by using some new contrib modules, so I'm documenting my experience here so you do not have to have the same troubles.

Entity Translation, for those who are not aware, is Drupal's transition to translating fields rather than translating nodes. You can read more about it on Gábor's site on Drupal7 Multilingual if you wish (you've probably already seen this page if you were searching around and landed here).

So what is wrong with Drupal's navigation menus when you use Entity Translation?

  • By default, there is only one navigation menu configuration for the node - on the source translation only.
  • The modules relating to entity translation are very new - some of them even lack a user interface!
  • Menus become a difficult problem because they are not entities like everything else
  • "Language neutral" (aka 'LANGUAGE_NONE' or 'und') nav menu entries must be translated from the default language, even if the source node is not in that language, potentially making your translation tables very messy (not to mention this is complicated to setup).

What is the best way to address these issues?

This new module solves a lot of problems by allowing us to add a field to each node that we will use in place of Drupal's standard navigation "menu_links". It then generates Drupal's standard links managed by this module, so that you can use menus in the standard way.

There is one limitation which had me scratching my head for a couple days. If you set the menu field to "translatable" you can get the menu setting on all versions of the translation. This is fabulous. What doesn't work is taking the language from the translated entity and putting that language setting into Drupal's standard "menu_links" table. Not ideal right? Well, there is a workaround.

You see, it is possible to create a navigation menu in Drupal that is language-specific. So, if you take a step back and think about this, since each language version of an entity-node has it's own menu configuration, why not just localize the menu entirely? That way we don't care if the menu_link is language neutral. With this structure, as an example, the French editor when doing the menu settings on a node must only remember to place the French translation within the context of the other French postings. That is simple enough to explain to your users.

Other dragons? Other awesome things?

There are not that many issues I have found yet since this module generates real Drupal menu_links for the navigation menu you can use any modules that support using Drupal's nav menu system, but you might have to do it twice (or more, depending on how many languages you are supporting.

Additional things you might want to think about:

What about the future?

Eventually, when we get around to adopting Drupal8, menu navigation will probably be based on entities. So we're already inching toward the future by embracing entities for everything now!

UPDATE: You may also be interested in my new Entity Translation Tabs module!

UPDATE 2: Keep in mind you don't need many i18n modules with this, and that some i18n modules cause a conflict. Only "Block languages" (i18n_block) and the core i18n modules are necessary for this configuration.

Be sure to disable i18n multilingual select, i18n field translation, i18n path translation and i18n menu translation.

For your convenience:
drush pm-disable i18n_select i18n_field i18n_path i18n_menu


i18n_taxonomy is OK. i18n_taxonomy might cause troubles too, but I have not tested this yet.

I recommend the "Localize" option on your taxonomy, which requires you to put the default language version first, and the "title" module to replace the taxonomy term name interface. You may have to hook_form_alter your Views if you output your taxonomy as an exposed filter to put the translation.

I put the following into my hook_form_alter function to make taxonomy make sense:

  if ('taxonomy_form_term' == $form_id) {
    drupal_set_message('Taxonomy terms must be set in English first.  Then click "save and translate" and you can put the French version.  You can then manage existing translations by going to the term using the translate tab.');
  if ('views_exposed_form' == $form_id) {
    global $language;
    // this uses French, but you could abstract it a bit.
    if ($language->language == 'fr') {
      $result = db_query("select * from {field_data_name_field} where language='fr'");
      foreach ($result as $row) {
          $form['field_series_code_tid']['#options'][$row->entity_id] = $row->name_field_value;