Index: i18nmenu_node.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/i18nmenu_node/i18nmenu_node.module,v
retrieving revision 1.15
diff -u -r1.15 i18nmenu_node.module
--- i18nmenu_node.module	14 Sep 2010 10:30:38 -0000	1.15
+++ i18nmenu_node.module	14 Sep 2010 17:09:51 -0000
@@ -12,6 +12,29 @@
  */
 
 /**
+ * Return the information used to provide the [i18n] blocks.
+ */
+function i18nmenu_node_block_info($module = NULL) {
+  static $info;
+
+  if (!isset($info)) {
+    $info = array(
+      'menu' => array(
+        'view' => 'i18nmenu_node_menu_block_view',
+      ),
+      'user' => array(
+        'delta' => array(1),
+        'view' => 'i18nmenu_node_navigation_menu_block_view',
+      ),
+      'menu_block' => array(),
+    );
+    drupal_alter('i18nmenu_node_block_info', $info);
+  }
+
+  return empty($module) ? $info : $info[$module];
+}
+
+/**
  * Implementation of hook_block().
  *
  * Provide an i18n version of each menu block.
@@ -19,30 +42,81 @@
 function i18nmenu_node_block($op = 'list', $delta = 0) {
   switch ($op) {
     case 'list':
-      $blocks = menu_block($op, $delta);
-      foreach ($blocks as $delta => $block) {
-        $blocks[$delta]['info'] = t('[i18n] !block', array('!block' => $blocks[$delta]['info']));
+      $blocks = array();
+      // Retrieve blocks form all the modules defined in the block information.
+      foreach (i18nmenu_node_block_info() as $module => $data) {
+        $module_blocks = module_invoke($module, 'block');
+        if (!empty($module_blocks)) {
+          // If a delta set is specified filter out the undesired blocks.
+          if ($data['delta']) {
+            $module_blocks = array_intersect_key($module_blocks, array_flip($data['delta']));
+          }
+          // Create an [i18n] version for each block and store the parent module
+          // as part of the delta.
+          foreach ($module_blocks as $delta => $block) {
+            $blocks["$module:$delta"]['info'] = t('[i18n] !block', array('!block' => $block['info']));
+          }
+        }
       }
       return $blocks;
 
     case 'view':
-      return i18nmenu_node_block_view($delta);
+      list($module, $delta) = explode(':', $delta, 2);
+      return i18nmenu_node_block_view($module, $delta);
   }
 }
 
 /**
- * Render the i18n version of a menu block.
+ * Render the i18n version of a block.
  *
  * Since menu tree rendering is influenced by language selection modes, we need
- * to temporary disable language selection, while rendering them. To render the
- * menu tree we use i18nmenu_translated_tree(). With this approach we avoid
- * rendering an unlocalized version and then replacing it during block
+ * to temporary disable language selection, while rendering them.
+ *
+ * @see menu_tree_check_access().
+ */
+function i18nmenu_node_block_view($module, $delta) {
+  $info = i18nmenu_node_block_info($module);
+  $default_callback = "{$module}_block";
+
+  if (!empty($info['file'])) {
+    require_once $info['file'];
+  }
+
+  // If a view callback is defined we use it, otherwise we fall back to the
+  // usual hook_block() invocation.
+  i18n_selection_mode('off');
+  $block = !empty($info['view']) && function_exists($info['view']) ? $info['view']($delta) : $default_callback('view', $delta);
+  i18n_selection_mode('reset');
+
+  return $block;
+}
+
+/**
+ * Render the navigation menu block.
+ */
+function i18nmenu_node_navigation_menu_block_view() {
+  global $user;
+  $block = i18nmenu_node_menu_block_view('navigation');
+
+  // Authenticated users have their name as title of the navigation menu.
+  if ($user->uid) {
+    $block['subject'] = check_plain($user->name);
+  }
+
+  return $block;
+}
+
+/**
+ * Render the i18n version of a menu block.
+ *
+ * To render the menu tree we use i18nmenu_translated_tree(). With this approach
+ * we avoid rendering an unlocalized version and then replacing it during block
  * preprocessing, hence we should have a performance improvement here over the
  * standard (translated) menu blocks.
  *
  * @see menu_tree_check_access().
  */
-function i18nmenu_node_block_view($menu_name) {
+function i18nmenu_node_menu_block_view($menu_name) {
   static $menus;
 
   if (!isset($menus)) {
@@ -51,9 +125,7 @@
 
   $block = array();
   $block['subject'] = check_plain($menus[$menu_name]);
-  i18n_selection_mode('off');
   $block['content'] = i18nmenu_translated_tree($menu_name);
-  i18n_selection_mode('reset');
 
   return $block;
 }
Index: i18nmenu_node.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/i18nmenu_node/i18nmenu_node.install,v
retrieving revision 1.1
diff -u -r1.1 i18nmenu_node.install
--- i18nmenu_node.install	11 Jul 2010 13:06:31 -0000	1.1
+++ i18nmenu_node.install	14 Sep 2010 17:09:50 -0000
@@ -39,3 +39,13 @@
   }
   i18nmenu_node_item_translations_refresh_all(FALSE);
 }
+
+/**
+ * Implements hook_update_N().
+ *
+ * Convert block delta to the new format <module>:<delta>.
+ */
+function i18nmenu_node_update_6100() {
+  $query = "UPDATE {blocks} SET delta = CONCAT('menu:', delta) WHERE module = 'i18nmenu_node'";
+  return array(update_sql($query));
+}
Index: i18nmenu_node.api.php
===================================================================
RCS file: i18nmenu_node.api.php
diff -N i18nmenu_node.api.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ i18nmenu_node.api.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,41 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Hooks provided by the Menu Translation (Node) module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alter the information used to provide [i18n] blocks.
+ *
+ * This hook can be implemented to add support for additional modules needing
+ * to render menu trees without incurring in language selection problems, or
+ * altering the default information.
+ *
+ * @param $info
+ *   A nested array keyed by module name. Each entry is an associative array
+ *   having the following (optional) keys:
+ *   - delta: An array of delta used to restrict the block set returned by the
+ *     module. If this is empty all the returned blocks will be used.
+ *   - view: A view callback that will be called to render the block identified
+ *     by the given delta. If empty the default hook_block('view', $delta) will
+ *     be used.
+ *   - file: A file to be included before calling the view callback.
+ */
+function hook_i18nmenu_node_block_info_alter(&$info) {
+  $info['custom_module'] = array(
+    'delta' => array('custom_delta_1', 'custom_delta_2'),
+    'view' => 'custom_module_view_callback',
+    'file' => drupal_get_path('module', 'custom_module') .'/custom_module.inc',
+  );
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
