You are here

i18n_book_navigation.module in Book translation 6.2

Same filename and directory in other branches
  1. 6 i18n_book_navigation.module
  2. 7.2 i18n_book_navigation.module

Defines the i18n book navigation module. Contains all necessary data and hooks

File

i18n_book_navigation.module
View source
<?php

/**
 * @file
 * Defines the i18n book navigation module. Contains all necessary data and
 * hooks
 */

/**
 * Implementation of hook_theme()
 *
 * The i18n_book_navigation uses the book-navigation.tpl.php file for theming
 * the "footer" book navigation in book pages. It will use it to display
 * this navigation on translated nodes, even if they're not part of a book
 * outline. We must implement our own theme however, because the default
 * book_navigation will call menu_tree_all_data() before i18n_book_navigation,
 * which will store an empty tree statically, preventing us from using it and
 * translating the links.
 */
function i18n_book_navigation_theme($existing, $type, $theme, $path) {
  return array(
    'i18n_book_navigation' => array(
      'arguments' => array(
        'book_link' => NULL,
      ),
      'path' => drupal_get_path('module', 'book'),
      'template' => 'book-navigation',
    ),
  );
}

/**
 * Sets the breadcrumb.
 * This is a port from menu_get_active_breadcrumb(). It will set the breadcrumb
 * based on the current, translated tree.
 * @see menu_get_active_breadcrumb()
 *
 * @param object $node
 *        The node currently viewed (as in menu_get_item())
 * @param array $tree
 *        The translated tree
 */
function i18n_book_navigation_set_breadcrumb($node, $tree) {
  $trail = array();
  $breadcrumb = array(
    l(t("Home"), '<front>'),
  );
  $href = 'node/' . $node->nid;
  list($key, $curr) = each($tree);
  while ($curr) {

    // Terminate the loop when we find the current path in the active trail.
    if ($curr['link']['href'] == $href) {
      $trail[] = $curr['link'];
      $curr = FALSE;
    }
    else {

      // Add the link if it's in the active trail, then move to the link below.
      if ($curr['link']['in_active_trail']) {
        $trail[] = $curr['link'];
        $tree = $curr['below'] ? $curr['below'] : array();
      }
      list($key, $curr) = each($tree);
    }
  }
  foreach ($trail as $element) {
    $breadcrumb[] = l($element['title'], $element['href'], $element['localized_options']);
  }

  // Remove the last element
  array_pop($breadcrumb);
  drupal_set_breadcrumb($breadcrumb);
}

/**
 * Implementation of hook_nodeapi()
 */
function i18n_book_navigation_nodeapi(&$node, $op, $teaser, $page) {
  switch ($op) {
    case 'view':

      // Check that we're not dealing with the original node itself or with a
      // non-translated node
      if ($node->nid != $node->tnid && $node->tnid != 0 && !$teaser) {

        // Get the original node book information
        $tnode = (object) array(
          'nid' => $node->tnid,
        );
        $book_info = book_nodeapi($tnode, 'load', $teaser, $page);

        // If the original node is part of a book outline
        if (!empty($book_info['book']['bid'])) {
          $node->content['book_navigation'] = array(
            '#value' => theme('i18n_book_navigation', $book_info['book']),
            '#weight' => 100,
          );
        }
      }
      break;
  }
}

/**
 * Implementation of hook_block()
 */
function i18n_book_navigation_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'view':
      return _i18n_book_navigation_block(menu_get_object());
    case 'list':
      $block = array(
        array(
          'info' => t('i18n Book Navigation'),
          'cache' => BLOCK_CACHE_PER_PAGE | BLOCK_CACHE_PER_ROLE,
        ),
      );
      return $block;

    // Configure and save is identical to book_block()
    case 'configure':
    case 'save':
      return book_block($op, $delta, $edit);
  }
}

/**
 * Creates the block navigation.
 * Assembles the navigation for the "current" book outline and translates
 * the links into the desired language.
 *
 * @see book_block() for more information
 *
 * @param stdClass $tnode
 *        The current node object.
 *
 * @return array
 *        The block array
 */
function _i18n_book_navigation_block($tnode) {
  $block = array();

  // Get the node in the original language
  $node = i18n_book_navigation_get_original_node($tnode);

  // If it's the same as the current language, use the default block to save time
  if ($node->language == i18n_get_lang()) {
    $block = book_block('view');
    return $block;
  }
  if (!empty($node->book)) {
    $current_bid = $node->book['bid'];
  }
  else {
    $current_bid = 0;
  }
  if (variable_get('book_block_mode', 'all pages') == 'all pages') {
    $book_menus = array();
    foreach (i18n_book_navigation_get_books() as $bid => $book) {
      $tree = array();
      if ($bid == $current_bid) {
        $tree = i18n_book_navigation($node);
      }
      else {
        $book['in_active_trail'] = FALSE;
        $tree[0]['link'] = $book;
        $tree[0]['below'] = FALSE;
      }
      if ($bid == $current_bid) {

        // Set the breadcrumb
        i18n_book_navigation_set_breadcrumb($tnode, $tree);
      }

      // Render
      $book_menus[$bid] = menu_tree_output($tree);
    }
    $block['subject'] = t("i18n Book navigation");
    $block['content'] = theme('book_all_books_block', $book_menus);
  }
  elseif ($current_bid) {

    // Only display this block when the user is browsing a book.
    $title = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), array(
      $node->book['bid'],
    )));

    // Only show the block if the user has view access for the top-level node.
    if ($title) {
      $tree = i18n_book_navigation($node);
      if (count($tree)) {

        // There should only be one element at the top level.
        $data = array_shift($tree);
        $block['subject'] = theme('book_title_link', $data['link']);
        $block['content'] = $data['below'] ? menu_tree_output($data['below']) : '';
      }
    }
  }
  return $block;
}

/**
 * Gets the translated menu tree for the original node.
 *
 * @param stdClass $node
 *        The node in the original language, that is part of the book outline
 *
 * @return array
 *        The translated menu tree, or an empty array
 */
function i18n_book_navigation($node) {
  if (!empty($node->book)) {

    // Set the i18n node selection mode in the correct language
    i18n_selection_mode('node', $node->language);
  }
  else {

    // Nothing we can do
    return array();
  }
  $tree = menu_tree_all_data($node->book['menu_name'], $node->book);

  // Translate the tree
  $tree = i18n_book_navigation_translate_tree($tree);

  // Cleanup the "empty" leaves
  $tree = i18n_book_navigation_cleanup($tree);
  if (!empty($node->book)) {

    // Revert the i18n node selection mode
    i18n_selection_mode('node', i18n_get_lang());
  }
  return $tree;
}

/**
 * Gets all the available books.
 * Port from book_get_books(). Needs to deactivate the i18n module in order to
 * retreive all books, regardless of the language settings.
 * @see book_get_books()
 */
function i18n_book_navigation_get_books() {
  module_disable(array(
    'i18n',
  ));
  $books = book_get_books();
  module_enable(array(
    'i18n',
  ));
  return $books;
}

/**
 * Translates the tree.
 * Walks down the tree and translates every item. Will respect the translation
 * settings from the i18n module.
 *
 * @param array $tree
 *        The menu tree
 * @param string $lan = NULL
 *        (optional) The language to translate the tree in. Defaults to the
 *        current language
 *
 * @return array
 *        The translated menu tree
 */
function i18n_book_navigation_translate_tree($tree, $lan = NULL) {
  foreach ($tree as $key => &$item) {
    if ($node = i18n_book_navigation_get_translated_node($item['link']['link_path'], $lan)) {
      $item['link']['title'] = $item['link']['link_title'] = $node->title;
      $item['link']['href'] = $item['link']['link_path'] = 'node/' . $node->nid;
    }
    else {
      $item = array();
    }
    if ($item['below']) {
      $item['below'] = i18n_book_navigation_translate_tree($item['below'], $lan);
    }
  }
  return $tree;
}

/**
 * Cleans up the tree.
 * Depending on the translation mode, some leaves my be displayed as "empty".
 * Walks down the tree and unsets all "empty" items.
 *
 * @param array $tree
 *        The menu tree
 *
 * @return array
 *        The cleaned up menu tree
 */
function i18n_book_navigation_cleanup($tree) {
  $new_tree = array();
  foreach ($tree as $item) {
    $temp = array();
    if (isset($item['link'])) {
      $temp['link'] = $item['link'];
      if ($item['below']) {
        $temp['below'] = i18n_book_navigation_cleanup($item['below']);
      }
      $new_tree[] = $temp;
    }
  }
  return $new_tree;
}

/**
 * Preprocesses the i18n_book_navigation.
 * Very similar to the book_navigation, the i18n_book_navigation uses the same
 * template file and template variables. These variables will be translated and
 * the urls adapted.
 * @see template_preprocess_book_navigation()
 *
 * @param array &$variables
 *        The template variables
 */
function template_preprocess_i18n_book_navigation(&$variables) {

  // Get the current node
  $tnode = menu_get_object();

  // Get the translation
  $node = i18n_book_navigation_get_original_node($tnode);

  // Set the i18n node selection mode in the correct language
  i18n_selection_mode('node', $node->language);

  // We MUST call the menu_tree_all_data() function BEFORE the book module does.
  // This is ok for performance, as the result is stored in a static cache, so
  // the tree will not get build all over again later on
  menu_tree_all_data($node->book['menu_name'], $node->book);

  // Revert the i18n node selection mode
  i18n_selection_mode('node', i18n_get_lang());

  // Provide the original book link
  $variables['book_link'] = $node->book;

  // Call the book module preprocess function
  template_preprocess_book_navigation($variables);

  // Translate title and book url
  $data = db_fetch_array(db_query("SELECT v.title, n.nid FROM {node_revisions} v\n                                    LEFT JOIN {node} n ON n.nid = v.nid AND n.vid = v.vid\n                                  WHERE n.tnid = %d AND n.language = '%s' LIMIT 1", array(
    $variables['book__id'],
    i18n_get_lang(),
  )));
  $variables['book_title'] = check_plain($data['title']);
  $variables['book_url'] = 'node/' . $data['nid'];

  // Translate the sub tree
  if (strlen($variables['tree'])) {
    $variables['tree'] = i18n_book_navigation_children($node->book);
  }

  // Translate the book links
  if ($variables['has_links']) {

    // Translate the "prev" link
    if ($variables['prev_url']) {
      if ($link = i18n_book_navigation_prev($variables['book_link'])) {
        $href = url($link['href']);

        // This *should* override the default link, as it comes afterwards
        drupal_add_link(array(
          'rel' => 'prev',
          'href' => $href,
        ));
        $variables['prev_url'] = $href;
        $variables['prev_title'] = check_plain($link['title']);
      }
      else {

        // Unset the variables
        unset($variables['prev_url'], $variables['prev_title']);
      }
    }

    // Translate the "up" link
    if ($variables['parent_url']) {
      if ($link = i18n_book_navigation_link_load($variables['book_link']['plid'])) {
        $href = url($link['href']);

        // This *should* override the default link, as it comes afterwards
        drupal_add_link(array(
          'rel' => 'up',
          'href' => $href,
        ));
        $variables['parent_url'] = $href;
        $variables['parent_title'] = check_plain($link['title']);
      }
      else {
        unset($variables['parent_url'], $variables['parent_title']);
      }
    }

    // Translate the "next" link
    if ($variables['next_url']) {
      if ($link = i18n_book_navigation_next($variables['book_link'])) {
        $href = url($link['href']);

        // This *should* override the default link, as it comes afterwards
        drupal_add_link(array(
          'rel' => 'next',
          'href' => $href,
        ));
        $variables['next_url'] = $href;
        $variables['next_title'] = check_plain($link['title']);
      }
      else {
        unset($variables['next_url'], $variables['next_title']);
      }
    }

    // Reset the "has_links" flag if needed
    $links = array(
      'prev_url',
      'prev_title',
      'parent_url',
      'parent_title',
      'next_url',
      'next_title',
    );
    foreach ($links as $link) {
      if (isset($variables[$link])) {
        $variables['has_links'] = TRUE;
      }
      else {
        $variables[$link] = '';
      }
    }
  }
}

/**
 * Loads the direct child elements.
 * Port from book_children(). Will perform a similar task, but will also translate
 * the links.
 * @see book_children()
 *
 * @param array $book_link
 *        The link data
 *
 * @return string
 *        The child elements as HTML. If no child elements were found, the string
 *        will be empty
 */
function i18n_book_navigation_children($book_link) {
  $flat = book_get_flat_menu($book_link);
  $children = array();
  if ($book_link['has_children']) {

    // Walk through the array until we find the current page.
    do {
      $link = array_shift($flat);
    } while ($link && $link['mlid'] != $book_link['mlid']);

    // Continue though the array and collect the links whose parent is this page.
    while (($link = array_shift($flat)) && $link['plid'] == $book_link['mlid']) {
      $data['link'] = $link;
      $data['below'] = '';
      $children[] = $data;
    }
  }

  // Translate the tree
  $children = i18n_book_navigation_translate_tree($children);

  // Clean it up
  $children = i18n_book_navigation_cleanup($children);

  // Render it
  return $children ? menu_tree_output($children) : '';
}

/**
 * Loads the previous link in the book.
 * Port from book_prev(). Will translate the link after loading it.
 * @see book_prev()
 *
 * @param array $book_link
 *        The link data
 *
 * @return array|false
 *        The loaded link or false if no link was found
 */
function i18n_book_navigation_prev($book_link) {
  $tree = array(
    array(
      'link' => book_prev($book_link),
      'below' => FALSE,
    ),
  );
  $tree = i18n_book_navigation_translate_tree($tree);
  return isset($tree[0]['link']) ? $tree[0]['link'] : FALSE;
}

/**
 * Loads the next link in the book.
 * Port from book_next(). Will translate the link after loading it.
 * @see book_nex()
 *
 * @param array $book_link
 *        The link data
 *
 * @return array|false
 *        The loaded link or false if no link was found
 */
function i18n_book_navigation_next($book_link) {
  $tree = array(
    array(
      'link' => book_next($book_link),
      'below' => FALSE,
    ),
  );
  $tree = i18n_book_navigation_translate_tree($tree);
  return isset($tree[0]['link']) ? $tree[0]['link'] : FALSE;
}

/**
 * Loads a link.
 * Port from book_link_load(). Will translate the link after loading it.
 * @see book_link_load()
 *
 * @param int $mlid
 *        The menu link id
 *
 * @return array|false
 *        The loaded link or false if no link was found
 */
function i18n_book_navigation_link_load($mlid) {
  $tree = array(
    array(
      'link' => book_link_load($mlid),
      'below' => FALSE,
    ),
  );
  $tree = i18n_book_navigation_translate_tree($tree);
  return isset($tree[0]['link']) ? $tree[0]['link'] : FALSE;
}

/**
 * Gets the translated node based on the link path.
 * The returned value depends on the availability of a translation and the i18n
 * settings.
 *
 * @param string $link_path
 *        The link path of the original node
 * @param string $lan = NULL
 *        (optional) The desired language. Defaults to the current language
 *
 * @return object|false
 *        The tranlsated node, or the default node, or false
 */
function i18n_book_navigation_get_translated_node($link_path, $lan = NULL) {
  if (!$lan) {
    $lan = i18n_get_lang();
  }
  $i18n_setting = variable_get('i18n_selection_mode', 'simple');
  $tnid = (int) substr($link_path, strlen('node/'));
  $tlanguage = db_result(db_query("SELECT language FROM {node} WHERE nid = %d", array(
    $tnid,
  )));
  $nid = db_result(db_query("SELECT nid FROM {node} WHERE tnid = %d AND language = '%s'", array(
    $tnid,
    $lan,
  )));
  if ($nid) {
    if ($i18n_setting == 'simple' || $i18n_setting == 'mixed' || $i18n_setting == 'strict') {

      // Current language and language neutral
      //  OR
      // Mixed current language (if available) or default language (if not) and language neutral
      //  OR
      // Only current language
      $data = db_fetch_object(db_query("SELECT nid, title FROM {node} WHERE nid = %d", array(
        $nid,
      )));
    }
    elseif ($i18n_setting == 'default' || $i18n_setting == 'off') {

      // Only default language and language neutral
      //  OR
      // All content. No language conditions apply
      $data = db_fetch_object(db_query("SELECT nid, title FROM {node} WHERE nid = %d", array(
        $tnid,
      )));
    }
    else {
      $data = FALSE;
    }
  }
  else {
    if ($i18n_setting == 'simple') {

      // Current language and language neutral
      if ($tlanguage == i18n_get_lang()) {
        $data = db_fetch_object(db_query("SELECT nid, title FROM {node} WHERE nid = %d", array(
          $tnid,
        )));
      }
      else {
        $data = db_fetch_object(db_query("SELECT nid, title FROM {node} WHERE nid = %d AND (language = '' OR language IS NULL)", array(
          $tnid,
        )));
      }
    }
    elseif ($i18n_setting == 'mixed' || $i18n_setting == 'default' || $i18n_setting == 'off') {

      // Mixed current language (if available) or default language (if not) and language neutral
      //  OR
      // Only default language and language neutral
      //  OR
      // All content. No language conditions apply
      $data = db_fetch_object(db_query("SELECT nid, title FROM {node} WHERE nid = %d", array(
        $tnid,
      )));
    }
    elseif ($i18n_setting == 'strict') {

      // Only current language
      if ($tlanguage == $lan) {
        $data = db_fetch_object(db_query("SELECT nid, title FROM {node} WHERE nid = %d", array(
          $tnid,
        )));
      }
      else {
        $data = FALSE;
      }
    }
    else {
      $data = FALSE;
    }
  }
  return $data;
}

/**
 * Gets the original node based on the current, translated version.
 *
 * @param object $node
 *        The translated node
 *
 * @return object
 *        The original node, or an empty object if no translation was found
 */
function i18n_book_navigation_get_original_node($node) {
  if ($node->nid) {
    if ($node->tnid == $node->nid || $node->tnid == 0) {
      return $node;
    }
    else {
      return node_load($node->tnid);
    }
  }
  else {
    return new stdClass();
  }
}

/**
 * Implementation of hook_token_list()
 * 
 * Provide tokens similar to the bookpath ones, except these will also be aplliable
 * to translated nodes, returning the translated book path.
 * However, depending on the i18n settings, this could have unexpected results
 * and should be used wisely (when translating the book, always start from the top,
 * as to not have "empty" positions in the book path).
 */
function i18n_book_navigation_token_list($type = 'all') {
  $list = array();
  if ($type == 'node' || $type == 'all') {
    $list['book']['i18n-book'] = t("The title of the node's book parent, translated.");
    $list['book']['i18n-book-raw'] = t("The unfiltered title of the node's book parent, translated.");
    $list['book']['i18n-bookpath'] = t("The titles of all parents in the node's book hierarchy, translated.");
    $list['book']['i18n-bookpath-raw'] = t("The unfiltered titles of all parents in the node's book hierarchy, translated.");
  }
  return $list;
}

/**
 * Implementation of hook_token_values()
 *
 * Port of book_token_values() from the token module. Will translate all the tokens.
 * @see book_token_values().
 */
function i18n_book_navigation_token_values($type, $object = NULL, $options = array()) {
  $tokens = array();
  if ($type == 'node') {
    $tokens['i18n-bookpath'] = '';
    $tokens['i18n-bookpath-raw'] = '';

    // Get the translation
    $node = i18n_book_navigation_get_original_node($object);
    if (!empty($node->book['menu_name'])) {

      // Set the i18n node selection mode in the correct language
      i18n_selection_mode('node', $node->language);
      $trail_raw = i18n_book_navigation_menu_titles($node->book, $node->nid, $object->language);

      // Revert the i18n node selection mode
      i18n_selection_mode('node', i18n_get_lang());
      $book_raw = $trail_raw[0];
      $book = check_plain($book_raw);

      // For book paths, we don't include the current node's title in the trail
      array_pop($trail_raw);
      $trail = array();
      foreach ($trail_raw as $title) {
        $trail[] = check_plain($title);
      }
      $tokens['i18n-book'] = $book;
      $tokens['i18n-book-raw'] = $book_raw;
      $tokens['i18n-bookpath'] = !empty($options['pathauto']) ? $trail : implode('/', $trail);
      $tokens['i18n-bookpath-raw'] = !empty($options['pathauto']) ? $trail_raw : implode('/', $trail_raw);
    }
  }
  return $tokens;
}

/**
 * Gets the menu titles for the book path.
 * Port of _menu_titles of the token module. Will translate the tree before fetching
 * the titles.
 * @see _menu_title()
 *
 * @param array $menu_link
 *        The current menu link data
 * @param int $nid
 *        The node nid
 * @param string $language
 *        The language of the current node
 *
 * @return array
 *        The titles from the book path
 */
function i18n_book_navigation_menu_titles($menu_link, $nid, $language) {
  $tree = menu_tree_all_data($menu_link['menu_name'], $menu_link);

  // Translate the tree
  $tree = i18n_book_navigation_translate_tree($tree, $language);

  // Clean it up
  $tree = i18n_book_navigation_cleanup($tree);

  // Get mlid of all nodes in path - top-most parent to leaf node.
  $parents = array();
  for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
    if ($menu_link["p{$i}"]) {
      $parents[] = $menu_link["p{$i}"];
    }
  }

  // Build the titles in this hierarchy.
  $titles = array();
  $current = array_shift($tree);
  while ($current) {
    if (in_array($current['link']['mlid'], $parents)) {
      $titles[] = $current['link']['title'];
      if ($current['link']['href'] == "node/" . $nid) {
        break;
      }

      // Go deeper in tree hierarchy.
      $tree = $current['below'];
    }

    // Go to next sibling at same level in tree hierarchy.
    $current = $tree ? array_shift($tree) : NULL;
  }
  return $titles;
}

/**
 * Implementation of hook_presave_translation() from the Translation Management module.
 * New translated nodes should not be saved with book information as it inteferes with
 * this module.
 *
 * Patch by chaps2
 */
function i18n_book_navigation_presave_translation(&$node, $nid, $vid, $code) {

  // Check that node is a new node cloned from a source node.
  if (!isset($node->nid) && isset($node->tnid) && isset($node->book)) {
    unset($node->book);
    variable_set('icl_content_books_to_update', array());
  }
}

/**
 * Implementation of hook_menu_block_tree_alter() from the Menu Block module.
 * A menu block configured for book navigations can now also be translated.
 */
function i18n_book_navigation_menu_block_tree_alter(&$tree, &$config) {
  $tnode = menu_get_object();

  // Get the node in the original language
  $node = i18n_book_navigation_get_original_node($tnode);
  if ($node->language != i18n_get_lang() && !empty($node->book) && $config['menu_name'] == $node->book['menu_name']) {
    $tree = i18n_book_navigation($node);
    i18n_book_navigation_set_breadcrumb($tnode, $tree);
  }
}

Functions

Namesort descending Description
i18n_book_navigation Gets the translated menu tree for the original node.
i18n_book_navigation_block Implementation of hook_block()
i18n_book_navigation_children Loads the direct child elements. Port from book_children(). Will perform a similar task, but will also translate the links.
i18n_book_navigation_cleanup Cleans up the tree. Depending on the translation mode, some leaves my be displayed as "empty". Walks down the tree and unsets all "empty" items.
i18n_book_navigation_get_books Gets all the available books. Port from book_get_books(). Needs to deactivate the i18n module in order to retreive all books, regardless of the language settings.
i18n_book_navigation_get_original_node Gets the original node based on the current, translated version.
i18n_book_navigation_get_translated_node Gets the translated node based on the link path. The returned value depends on the availability of a translation and the i18n settings.
i18n_book_navigation_link_load Loads a link. Port from book_link_load(). Will translate the link after loading it.
i18n_book_navigation_menu_block_tree_alter Implementation of hook_menu_block_tree_alter() from the Menu Block module. A menu block configured for book navigations can now also be translated.
i18n_book_navigation_menu_titles Gets the menu titles for the book path. Port of _menu_titles of the token module. Will translate the tree before fetching the titles.
i18n_book_navigation_next Loads the next link in the book. Port from book_next(). Will translate the link after loading it.
i18n_book_navigation_nodeapi Implementation of hook_nodeapi()
i18n_book_navigation_presave_translation Implementation of hook_presave_translation() from the Translation Management module. New translated nodes should not be saved with book information as it inteferes with this module.
i18n_book_navigation_prev Loads the previous link in the book. Port from book_prev(). Will translate the link after loading it.
i18n_book_navigation_set_breadcrumb Sets the breadcrumb. This is a port from menu_get_active_breadcrumb(). It will set the breadcrumb based on the current, translated tree.
i18n_book_navigation_theme Implementation of hook_theme()
i18n_book_navigation_token_list Implementation of hook_token_list()
i18n_book_navigation_token_values Implementation of hook_token_values()
i18n_book_navigation_translate_tree Translates the tree. Walks down the tree and translates every item. Will respect the translation settings from the i18n module.
template_preprocess_i18n_book_navigation Preprocesses the i18n_book_navigation. Very similar to the book_navigation, the i18n_book_navigation uses the same template file and template variables. These variables will be translated and the urls adapted.
_i18n_book_navigation_block Creates the block navigation. Assembles the navigation for the "current" book outline and translates the links into the desired language.