I had several problems when I was trying to setup a multilanguage site and translate the Menu items.
The menu active item was working only for the english language, then I made some changes in menu_set_active_item and now it's working. See the code below:

/**
 * Sets the path of the active menu item.
 * Changed by wundo (03/12/2005)
 */
function menu_set_active_item($path = NULL) {
  static $stored_mid;
  $menu = menu_get_menu();

  if (is_null($stored_mid) || !empty($path)) {
    if (empty($path)) {
      /* wundo Menu Hack (03/12/2005)
      $path = $_GET['q'];
      */
      $path = _i18n_get_original_path();
      $path = substr($path,strlen(i18n_get_lang_prefix($path)));
      if($path[0] == '/')
        $path = substr($path,1);
      if(empty($path))
        $path = $_GET['q'];
    }
    else {
      $_GET['q'] = $path;
    }
    while ($path && !array_key_exists($path, $menu['path index'])) {
      $path = substr($path, 0, strrpos($path, '/'));
    }
    
    $stored_mid = array_key_exists($path, $menu['path index']) ? $menu['path index'][$path] : 0;
    $path = $_GET['q'];
    // Search for default local tasks to activate instead of this item.
    $continue = TRUE;
    while ($continue) {
      $continue = FALSE;
      if (array_key_exists('children', $menu['items'][$stored_mid])) {
        foreach ($menu['items'][$stored_mid]['children'] as $cid) {
          if ($menu['items'][$cid]['type'] & MENU_LINKS_TO_PARENT) {
            $stored_mid = $cid;
            $continue = TRUE;
          }
        }
      }
    }
  }
  
  return $stored_mid;
}
CommentFileSizeAuthor
#6 i18n_patches.zip31.96 KBAnonymous (not verified)

Comments

richardb’s picture

This didn't work for me... all pages just showed 'You are not authorised to view this page'
I noticed
$path = $_GET['q'];
returns something like node/82, while
$path = _i18n_get_original_path();
returns: en/mypage

Anonymous’s picture

I spent several ours working on this issue and came to the conclusion that the solution is not as simple as wundo proposes. The reason is, that the menu-object, dynamically generated and stored in $menu, stores (besides a lot of additional stuff) the relation between path (as you defined in the menu-administration) and menuID. During setup and theming of the page, the menu-object is queried several times, e.g. to identify visibility, activity etc. of content elements and naturally to code the html of the menu itself.
As I understood, the menu-object tries to store the menupath in the normal form 'node/XXX', i.e. drupal tries to resolve aliased pathnames. If this cannot be done, the alias-string is stored.
In the case when you define an aliased nodepath (e.g. 'en/mypath') but a different menupath (e.g. 'mypath') the alias cannot be resolved. In this case, the variable $menu contains a menu-item pointing to 'mypath'. Drupal get's into trouble identifying the relation between menu and content, which results in the menu on your page not beeing expanded or activated.
Ok, this is not too complex, but the menu-object also stores data of submenus and page task-bars (i.e. child-menues). These child-menus (they are e.g. the 'show'|'translate'|'edit' task-bars of nodes) are shown on your current page, i.e. their parent-node exists and the path can be de-aliased) are identified in $menu by 'node/XXX/something' while the related menu-item still points to 'mypath'. So drupal get's lost when starting to analyse chield-menues.
What does this mean: The solution proposed by wundo does not generally solve the issue.

I will give it some additional thoughts, but probably go along the approach proposed in http://drupal.org/node/30331#comment-48083
This is from an administration and S/W point of view not too elegant, and you may endup with different menu-trees in different languages, but for the 'enduser' it may be simpler to attach content directly 1-to-1 to a well defined menuelement (especially when he works with menu_otf). ;-)

PS: Hmmm, just a thought for future implementations of i18n and core: How about automatically store a menu-item for each language while hiding this to the user.

Anonymous’s picture

Status: Reviewed & tested by the community » Needs review

I think I found two possible solutions to this problem.

a) code a template_menu_item_link() function in your template that does all the analysis on active menu's, childs and task bars when themeing a menu-item. By this, a lot of analysis is done over and over again and you repeat what is already done in the core. Positive is that you omit drawbacks on other modules. (Hmmm, by the way I was suprised, that the activity of the menu is only identified late in the l() function!)

b) hack the menu.inc file to achieve, that the "missing links" in the menu-data-object are resolved directly after fetching the data from the DB. Doing this, no data is changed in the DB, the missing links are just resolved when the menupathes (e.g. when switching language or administering menues) need update.
After the lines
// Handle URL aliases if entered in menu administration.
$item->path = drupal_get_normal_path($item->path);
in the function _menu_build() insert the following hack:

      // i18n menu hack, bgkaempf 060213
      //   Analyses wether non-linked menu-path matches with language-prefixed
      //   path-alias. If match a is identified, the link is established.
      if (module_exist('i18n') && function_exists('i18n_get_lang')) {
        // check wether menupath-alias is resolvable:
        if (($item->path) == (drupal_get_path_alias($item->path))) {
          // It's not. So check wether alias is found at 'lang_prefix/path':
          $alias_map = drupal_get_path_map();
          if (array_key_exists(i18n_get_lang()."/".($item->path), $alias_map)) {
            //yes, so set menupath to normal path of alias (i.e. de-alias again).
            $item->path = drupal_get_normal_path(i18n_get_lang()."/".$item->path);
            $i18n_orphan_path_found = True;
          }
        }
      }
      // end i18n menu hack

I tested the patch with some modules and different types of pages. I only marginally tested it with e.g. taxonomy. Nevertheless, I hope the patch is quite robust, as it does not touch resolved menupath's or menu's that are hard linked to nodes.

Be aware, that this patch automatically links the menu with path "mypath" to the system path of the alias "current_lang_prefix/mypath" (with current_lang_prefix beeing the current language prefix, e.g. "en") when this alias exists.

Good luck.
bernhard

Anonymous’s picture

sorry ... the line $i18n_orphan_path_found = True; is not required and can be deleted. (It's just a leftover from the testing)

mirek_’s picture

hello

i'm fighting with the same problem - the menu links, that will point to the translated content. it seems, that your (bgkaempf) hack is usefull and it will work. but - in my case it doesnt work. so whats wrong? what i have to do to make it work? i've got the fresh installation of the drupal 4.6 and installed the i18n module from this link. do i have to install something more?

anyway. i am bit sad and confused, that at the project page is written, that last update was on December 2nd, 2005, but the downloadable version is dated to 4.6.0, 25/04/2005 - 02:15 and the cvs version is dated to March 6, 2005 - 20:15 (its older?). only when i look at the CVS messages for Internationalization i see something new. so - is there updated version of the i18n in one downloadable and usable package, that i can use? because - i am very interesting in this module. and i dont want to make my own hacks because of the hard way to upgrade to a newer version of drupal or just the module. probably the only way is to apply the patches from the very first beginning from the cvs. but - what about to release new running version of this module... hmm... :-/

i will apreciate any help. thanks a lot

Anonymous’s picture

StatusFileSize
new31.96 KB

mirek,
I used exactly the same i18n download. This is the latest update, as it already includes the i18n menu modul.

When installing i18n: Did you properly install i18n, especially did you patch the corefiles as required by i18n (bootstrap.inc and common.inc)?

bernhard

PS: attached you find the patched core files as required by standard i18n (these are my builds of the standard i18n patches, they are not related the menu-hack I discussed above!).

wundo’s picture

bgkaempf,

I don't have time to try you review yet, but I have my patch running in some site ok.

I used the last version (in last november) of i18n if the bootstrap.inc and etc from the i18n cvs (already patched).

The problem is that the track don't work in my patch, as soon as possible I will try your patch.

mirek_’s picture

to bgkaempf ;)

what i have done:

1. i installed the fress instalation of drupal 4.6.5
2. i downloaded the i18n module (from the module page), check the node page as translatable
3. i used patches available with the i18n module
3. added my language in localization (so i have english and slovak)
4. added language block (for easier language content switching)
5. i created simple content page to test it and created english and slovak translation
6. added the link of this content to the menu (english is node/3 and slovak is node/2 - in the menu is link to the slovak - node/2)

so - after applying your patch to the menu.inc still no change - the link is still pointing to the node/2 - doesnt matter, what language is selected. is there something more to do to make it work?

Anonymous’s picture

mirek
sorry for answering late ... I am fighting with some other nodetypes and modules currently ;-).

you write:
6. added the link of this content to the menu (english is node/3 and slovak is node/2 - in the menu is link to the slovak - node/2)

So, when I understand you correctly, you connected the menu with node/2, i.e. you 'hard-linked' the menu-item to the slovak content-item. To make my solution run you would have to:

6.a. give a meaningful alias name to your nodes, e.g. 'welcome':
alias the english node to: en/welcome
alias the slovak node to: ??/welcome (with ?? the 2-letter abbreviation for slovak)
6.b create a menu entry, name it e.g. 'welcome' and point it to the path 'welcome'

My patch then enables the menu to connect to your nodes (en/welcome and ??/welcome) depending on the active language.

Hope this helps.

Roberto Gerola’s picture

Title: Make the active menu item works in a translated version. » Make the active menu item (and every link) works in a translated version.
Assigned: wundo » Roberto Gerola
Category: feature » support
Status: Needs review » Needs work

Hello.
I think I've found a very simple and global solution to this topic.
I've changed the function l() in common.inc in this manner :

function l($text, $path, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = FALSE) {
  if ((drupal_get_normal_path($path) == $_GET['q']) || (drupal_get_normal_path(i18n_get_lang(). "/". $path) == $_GET['q'])) {
    if (isset($attributes['class'])) {
      $attributes['class'] .= ' active';
    }
    else {
      $attributes['class'] = 'active';
    }
  }
  return '<a href="'. check_url(url($path, $query, $fragment, $absolute)) .'"'. drupal_attributes($attributes) .'>'. ($html ? $text : check_plain($text)) .'</a>';
}

This patch needs some rows of code to check for the availability of the i18n module.
It shoud work for every link, I've tested both for menu and primary links.

Bye.

hugues’s picture

Version: 4.6.x-1.x-dev » 4.7.x-1.x-dev
Assigned: Roberto Gerola » hugues
Category: support » bug
Status: Needs work » Reviewed & tested by the community

After working with the code proposed by bgkaempf, I found a clean and final solution. The problem is that drupal_get_normal_path() needs the full content of the alias while the menu entries only contain the page name. Example: the menu entry points to "mypage", while the aliases to the pages are "en/mypage" or any "<language code>/mypage". Non i18n path aliases can also exist and should of course still work. Example: a page with no language assigned to it, that should display in any language: the menu entry and the alias should be the same and be just "mypage".

The code first checks whether drupal_get_normal_path() returned something different than what we had before, meaning an alias was found. If not, it passes the path through custom_url_rewrite() which adds the language code. After that, it rechecks whether drupal_get_normal_path() returned something different.

The only glitch is that when a new alias is made, the page admin/menu has to be accessed so the _menu_build() function get called and the menu is updated. The same page has of course also to be accessed after the code has been patched for it to work for the first time.

Here is the code:

// menu.inc
function _menu_build() {
...
      // Handle URL aliases if entered in menu administration.
      if (!isset($_menu['path index'][$item->path])) {
        //$item->path = drupal_get_normal_path($item->path);
        // several cases:
        // menu entry:
        //   node/21
        //   en/node/21 (not useful)
        //   myalias
        //   en/myalias (not useful)
        // alias:
        //   none
        //   myalias
        //   en/myalias
        // each of the combinations should work
        
        // final path has to be something like "node/xx"
        // drupal_get_normal_path wants the real alias
        $newpath = drupal_get_normal_path($item->path);
        if ($newpath != $item->path) {
          // this is it
          $item->path = $newpath;
        }
        else if (function_exists('custom_url_rewrite')) {
          $custompath = custom_url_rewrite('alias', $item->path, $item->path);
          $newpath = drupal_get_normal_path($custompath);
          if ($newpath != $custompath) {
            // this is it
            $item->path = $newpath;
          }
        }
      }
jose reyero’s picture

Status: Reviewed & tested by the community » Closed (won't fix)

This version is not supported anymore