5

I'm trying to change the link of a menu item dynamically based on the language that is selected in the language switcher.

Let's say I have the following links in my main-menu:
-Home
-About
-Products

If the language selected is English, I want the About item to link to node/73. If the language selected is Dutch, I want the About item to link to node/74.

Is this possible and how would I best go about this?

Any help is very much appreciated.

EDIT: Some extra information. I have the Internationalization, Content Translation and Entity Translation modules installed. Because of the hierarchy of the menu and a mix between content translated nodes and entity translated nodes, I don't want to add two seperate links to the menu but have one link and change the path dynamically in code.

11

You want to implement hook_translated_menu_link_alter().

This hook is not called for all menu items. According to the API documentation:

It is only invoked if $item['options']['alter'] has been set to a non-empty value (e.g., TRUE). This flag should be set using hook_menu_link_alter().

Here's an example:

function MODULE_menu_link_alter(&$link) {
  if ($link['link_title'] == 'foo') {
    $link['options']['alter'] = TRUE;
  }
}

function MODULE_translated_menu_link_alter(&$link) {
  if ($link['link_title'] == 'foo') {
    $link['href'] = 'node/5';
  }
}

Some notes:

  • you may want to filter additionally by $link['menu_name']
  • MODULE_menu_link_alter() is invoked on cache clear for all menus items declared via hook_menu().
  • For menu items created via web it is only invoked on save, that is, for this code to take effect you need to edit-and-save menu links you want to alter.

For reference, this technique is implemented by core in user.module (see user_menu_link_alter and user_translated_menu_link_alter) and by menu_token module.

  • It would probably be better to filter on mlid, since a title could change, but the ID will not. – mbomb007 May 1 at 21:46
  • Agree but mlid may change across environments. For such an approach you should enforce the mlids somehow, or use UUIDs with entity_menu_links (or perhaps another module I don't know). – jonhattan May 6 at 7:48
5

If you install the Internationalization module, you will have language selection on your menu configuration page, for example, admin/structure/menu/manage/main-menu/add. Select the language and set the respective path for the language.

If you have two languages, you would need to create two menu items for each language. Then, if you select a language, the menu items with the respective language will be displayed.

  • First off, thanks for your response, I appreciate it. I have the Internationalization, Content Translation and Entity Translation module installed. The reason why I want to change the link dynamically in code is because it should link to a content translated node. So actually two seperate nodes. But because of the hierarchy of the menu I can't just add two links in the menu, one for each language. Because there's a child link in the menu to an entity translated node. – Smos Jan 30 '13 at 10:56
  • So I don't know what to do with the child/parent relationship when there's a mix between content translated and entity translated nodes. Is it possible to just change the link in code? – Smos Jan 30 '13 at 10:56
0

After days of breaking my head over this I finally figured out how to solve my problem!!!

So, a little recap: I have three nodes that are translations of each other (with content translation).
Node 157 = English
Node 158 = Dutch
Node 159 = French

I needed a menu item that would dynamically show the correct node based on the interface language. But I couldn't create three seperate menu items, because this menu item has some child links to nodes that are translated with entity translation. Then I had some issues with showing the menu for the translions because these weren't in the menu. To make a long story short, here's the code I used:

mymodule.module

function mymodule_node_view($node, $view_mode, $langcode) {
    if($node->nid == 157) {
        if($langcode == 'nl') {
            drupal_goto('node/158');
        }elseif($langcode == 'fr') {
            drupal_goto('node/159');
        }
    } elseif($node->nid == 158 || $node->nid == 159) {
        menu_tree_set_path('main-menu', 'node/157');
    }
}

template.php

function mytheme_preprocess_page(&$variables) {
    if(!empty($variables['node'])){
        switch ($variables['node']->nid) {
            case 158:
                $variables['node']->title = '';
                menu_set_active_item('node/157');
                break;
            case 159:
                $variables['node']->title = '';
                menu_set_active_item('node/157');
                break;
        }
    }
}

If you can't make any sense out of this, feel free to ask me, I can hardly make any sense of it myself but it does the trick!

  • I'm fine you've fixed your problem by your own means but IMO It is not about fixing your problem but answering to a question «How can I change a menu link dynamically? (D7)». I did an effort to explain this in my answer. Please accept the answer. – jonhattan Jan 31 '13 at 16:31
  • Also, I think you can update the OP instead of adding answers to continue the reasoning. This is not a forum ;) – jonhattan Jan 31 '13 at 16:34
  • 1
    About the solution you've reached: loading a complete node and check for language to redirect to another one seems a very bad pattern. Instead, you could define a menu item (hook_menu) and load the correct node in the callback. Other solution I think of is to create a ctools page with a variant per language. – jonhattan Jan 31 '13 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.