first import
This commit is contained in:
259
sites/all/modules/i18n/i18n_menu/i18n_menu.admin.inc
Normal file
259
sites/all/modules/i18n/i18n_menu/i18n_menu.admin.inc
Normal file
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper functions for menu administration.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Produces a menu translation form.
|
||||
*/
|
||||
function i18n_menu_translation_form($form, $form_state, $translation_set = NULL, $item = NULL) {
|
||||
$translation_set = $translation_set ? $translation_set : i18n_translation_set_create('menu_link');
|
||||
$form['translation_set'] = array('#type' => 'value', '#value' => $translation_set);
|
||||
$translations = $translation_set->get_translations();
|
||||
// What to do with title? Let's make it a hidden field for now, some tests relay on it
|
||||
$form['title'] = array('#type' => 'hidden', '#default_value' => $translation_set->title);
|
||||
if ($item && ($lang = i18n_object_langcode($item))) {
|
||||
$translations[$lang] = $item;
|
||||
}
|
||||
$item = $item ? $item : array('mlid' => 0, 'menu_name' => '', 'plid' => 0);
|
||||
$item_lang = i18n_object_langcode($item);
|
||||
$form['translations'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Translations'),
|
||||
'#tree' => TRUE,
|
||||
'#description' => t('Enter items that will be considered as translations of each other.'),
|
||||
);
|
||||
foreach (i18n_language_list() as $langcode => $language_name) {
|
||||
if ($langcode == $item_lang) {
|
||||
// We've got a predefined item for this language
|
||||
$form['translations'][$langcode] = array('#type' => 'value', '#value' => $item['menu_name'] . ':' . $item['mlid']);
|
||||
$form['translations']['display'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => $language_name,
|
||||
'#markup' => check_plain($item['link_title']),
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Generate a list of possible parents (not including this link or descendants).
|
||||
$options = i18n_menu_parent_options(menu_get_menus(), $item, $langcode);
|
||||
$default = isset($translations[$langcode]) ? $translations[$langcode]['menu_name'] . ':' . $translations[$langcode]['mlid'] : 'navigation:0';
|
||||
if (!isset($options[$default])) {
|
||||
$default = 'navigation:0';
|
||||
}
|
||||
$form['translations'][$langcode] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $language_name,
|
||||
'#default_value' => $default,
|
||||
'#options' => $options,
|
||||
'#description' => t('The maximum depth for a link and all its children is fixed at !maxdepth. Some menu links may not be available as parents if selecting them would exceed this limit.', array('!maxdepth' => MENU_MAX_DEPTH)),
|
||||
'#attributes' => array('class' => array('menu-title-select')),
|
||||
);
|
||||
}
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['update'] = array('#type' => 'submit', '#value' => t('Save'));
|
||||
if ($translation_set) {
|
||||
$form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process form validation
|
||||
*/
|
||||
function i18n_menu_translation_form_validate($form, &$form_state) {
|
||||
if ($form_state['values']['op'] == t('Save')) {
|
||||
$selected = 0;
|
||||
// example array('en' => 'navigation:0')
|
||||
$mlids = array_filter($form_state['values']['translations']);
|
||||
foreach ($mlids as $lang => $item_name) {
|
||||
list($menu_name, $mlid) = explode(':', $item_name);
|
||||
if ($mlid && ($item = menu_link_load($mlid)) && i18n_object_langcode($item)) {
|
||||
$selected++;
|
||||
}
|
||||
else {
|
||||
unset($form_state['values']['translations'][$lang]);
|
||||
}
|
||||
}
|
||||
if ($selected < 1) {
|
||||
form_set_error('translations', t('There are no translations to save.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu item translation form submission
|
||||
*/
|
||||
function i18n_menu_translation_form_submit($form, &$form_state) {
|
||||
$translation_set = $form_state['values']['translation_set'];
|
||||
|
||||
switch ($form_state['values']['op']) {
|
||||
case t('Save'):
|
||||
$mlids = array_filter($form_state['values']['translations']);
|
||||
$translation_set->reset_translations();
|
||||
foreach ($mlids as $lang => $item_name) {
|
||||
list($menu_name, $mlid) = explode(':', $item_name);
|
||||
$item = menu_link_load($mlid);
|
||||
$translation_set->add_item($item, $lang);
|
||||
}
|
||||
$translation_set->title = !empty($form_state['values']['title']) ? $form_state['values']['title'] : '';
|
||||
$translation_set->save(TRUE);
|
||||
drupal_set_message(t('The item translation has been saved.'));
|
||||
break;
|
||||
case t('Delete'):
|
||||
$translation_set->delete(TRUE);
|
||||
drupal_set_message(t('The item translation has been deleted.'));
|
||||
break;
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'admin/structure/menu';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of menu items that are valid possible parents for the given menu item.
|
||||
*
|
||||
* @param $menus
|
||||
* An array of menu names and titles, such as from menu_get_menus().
|
||||
* @param $item
|
||||
* The menu item or the node type for which to generate a list of parents.
|
||||
* If $item['mlid'] == 0 then the complete tree is returned.
|
||||
* @return
|
||||
* An array of menu link titles keyed on the a string containing the menu name
|
||||
* and mlid. The list excludes the given item and its children.
|
||||
*
|
||||
* @todo This has to be turned into a #process form element callback. The
|
||||
* 'menu_override_parent_selector' variable is entirely superfluous.
|
||||
*/
|
||||
function i18n_menu_parent_options($menus, $item, $langcode) {
|
||||
// The menu_links table can be practically any size and we need a way to
|
||||
// allow contrib modules to provide more scalable pattern choosers.
|
||||
// hook_form_alter is too late in itself because all the possible parents are
|
||||
// retrieved here, unless menu_override_parent_selector is set to TRUE.
|
||||
if (variable_get('i18n_menu_override_parent_selector', FALSE)) {
|
||||
return array();
|
||||
}
|
||||
// If no menu item, create a dummy one
|
||||
$item = $item ? $item : array('mlid' => 0);
|
||||
// Get menus that have a language or have language for terms
|
||||
$available_menus = array();
|
||||
foreach (menu_load_all() as $name => $menu) {
|
||||
if ($menu['i18n_mode'] & I18N_MODE_TRANSLATE) {
|
||||
$available_menus[$name] = $menu;
|
||||
}
|
||||
elseif ($menu['i18n_mode'] & I18N_MODE_LANGUAGE && $menu['language'] == $langcode) {
|
||||
$available_menus[$name] = $menu;
|
||||
}
|
||||
}
|
||||
// Disable i18n selection, enable after the query.
|
||||
$previous = i18n_select(FALSE);
|
||||
$options = _i18n_menu_get_options($menus, $available_menus, $item, $langcode);
|
||||
i18n_select($previous);
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the items of the given menu.
|
||||
*/
|
||||
function _i18n_menu_get_options($menus, $available_menus, $item, $langcode) {
|
||||
// If the item has children, there is an added limit to the depth of valid parents.
|
||||
if (isset($item['parent_depth_limit'])) {
|
||||
$limit = $item['parent_depth_limit'];
|
||||
}
|
||||
else {
|
||||
$limit = _menu_parent_depth_limit($item);
|
||||
}
|
||||
|
||||
$options = array();
|
||||
foreach ($menus as $menu_name => $title) {
|
||||
if (isset($available_menus[$menu_name])) {
|
||||
if ($tree = i18n_menu_tree_all_data($menu_name, $langcode, NULL)) {
|
||||
$options[$menu_name . ':0'] = '<' . $title . '>';
|
||||
_menu_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out menu items that have a different language
|
||||
*/
|
||||
function i18n_menu_tree_all_data($menu_name, $langcode, $link = NULL, $max_depth = NULL) {
|
||||
$tree = menu_tree_all_data($menu_name, $link, $max_depth);
|
||||
return _i18n_menu_tree_filter_items($tree, $langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out menu items that have a different language
|
||||
*/
|
||||
function _i18n_menu_tree_filter_items($tree, $langcode) {
|
||||
$result = array();
|
||||
foreach ($tree as $key => $item) {
|
||||
$lang = i18n_object_langcode($item['link']);
|
||||
if (!empty($item['below'])) {
|
||||
$item['below'] = _i18n_menu_tree_filter_items($item['below'], $langcode);
|
||||
}
|
||||
if (!empty($item['link']['customized']) && $lang == $langcode) {
|
||||
$result[$key] = $item;
|
||||
}
|
||||
elseif (!empty($item['below'])) {
|
||||
// Keep for the tree but mark as unselectable.
|
||||
$item['link']['title'] = '(' . $item['link']['title'] . ')';
|
||||
$result[$key] = $item;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for menu translation tab.
|
||||
*/
|
||||
function i18n_menu_translation_item_overview($item, $translation_set = NULL) {
|
||||
if ($item['i18n_tsid']) {
|
||||
// Already part of a set, grab that set.
|
||||
$translation_set = i18n_translation_set_load($item['i18n_tsid']);
|
||||
$translations = $translation_set->get_translations();
|
||||
}
|
||||
else {
|
||||
// We have no translation source mlid, this could be a new set, emulate that.
|
||||
$translations = array($item['language'] => $item);
|
||||
}
|
||||
|
||||
$type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
|
||||
$header = array(t('Language'), t('Title'), t('Operations'));
|
||||
$rows = array();
|
||||
|
||||
foreach (i18n_language_list() as $langcode => $language_name) {
|
||||
$options = array();
|
||||
if (isset($translations[$langcode])) {
|
||||
// Existing translation in the translation set: display status.
|
||||
$translation_item = menu_link_load($translations[$langcode]['mlid']);
|
||||
$title = l($translation_item['link_title'], $translation_item['link_path']);
|
||||
$path = 'admin/structure/menu/item/' . $translation_item['mlid'];
|
||||
$options[] = l(t('edit'), $path);
|
||||
|
||||
if ($translation_item['mlid'] == $item['mlid']) {
|
||||
$language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No such translation in the set yet: help user to create it.
|
||||
$title = t('n/a');
|
||||
$options[] = l(t('add translation'), 'admin/structure/menu/manage/' . $item['menu_name'] . '/add', array('query' => array('translation' => $item['mlid'], 'target' => $langcode) + drupal_get_destination()));
|
||||
}
|
||||
$rows[] = array($language_name, $title, implode(" | ", $options));
|
||||
}
|
||||
|
||||
drupal_set_title(t('Translations of menu item %title', array('%title' => $item['link_title'])), PASS_THROUGH);
|
||||
|
||||
$build['translation_item_overview'] = array(
|
||||
'#theme' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
);
|
||||
|
||||
return $build;
|
||||
}
|
130
sites/all/modules/i18n/i18n_menu/i18n_menu.i18n.inc
Normal file
130
sites/all/modules/i18n/i18n_menu/i18n_menu.i18n.inc
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Internationalization (i18n) hooks
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_object_info().
|
||||
*/
|
||||
function i18n_menu_i18n_object_info() {
|
||||
$info['menu'] = array(
|
||||
'title' => t('Menu'),
|
||||
'key' => 'menu_name',
|
||||
'load callback' => 'menu_load',
|
||||
'base path' => 'admin/structure/menu/manage',
|
||||
'placeholders' => array(
|
||||
'%menu' => 'menu_name',
|
||||
),
|
||||
'edit path' => 'admin/structure/menu/manage/%menu/edit',
|
||||
// Auto-generate translate tab.
|
||||
'translate tab' => 'admin/structure/menu/manage/%menu/translate',
|
||||
// We can easily list all these objects
|
||||
'list callback' => 'menu_load_all',
|
||||
// Metadata for string translation
|
||||
'string translation' => array(
|
||||
'textgroup' => 'menu',
|
||||
'type' => 'menu',
|
||||
'properties' => array(
|
||||
'title' => t('Title'),
|
||||
'description' => t('Description'),
|
||||
),
|
||||
),
|
||||
'translation container' => array(
|
||||
'name' => t('menu'),
|
||||
'item type' => 'menu_link',
|
||||
'item name' => t('menu items'),
|
||||
'options' => array(I18N_MODE_NONE, I18N_MODE_MULTIPLE, I18N_MODE_LANGUAGE),
|
||||
),
|
||||
);
|
||||
$info['menu_link'] = array(
|
||||
'title' => t('Menu link'),
|
||||
'class' => 'i18n_menu_link',
|
||||
'key' => 'mlid',
|
||||
'load callback' => 'menu_link_load',
|
||||
'base path' => 'admin/structure/menu/item',
|
||||
'edit path' => 'admin/structure/menu/item/%menu_link/edit',
|
||||
// Auto-generate translate tab
|
||||
'translate tab' => 'admin/structure/menu/item/%menu_link/translate',
|
||||
'placeholders' => array(
|
||||
'%menu_link' => 'mlid',
|
||||
'%menu' => 'menu_name',
|
||||
),
|
||||
'string translation' => array(
|
||||
'textgroup' => 'menu',
|
||||
'type' => 'item',
|
||||
'properties' => array(
|
||||
'title' => array(
|
||||
'title' => t('Title'),
|
||||
'field' => 'link_title',
|
||||
),
|
||||
'description' => array(
|
||||
'title' => t('Description'),
|
||||
'field' => 'options.attributes.title',
|
||||
),
|
||||
),
|
||||
),
|
||||
'translation set' => TRUE,
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_translation_set_info()
|
||||
*/
|
||||
function i18n_menu_i18n_translation_set_info() {
|
||||
$info['menu_link'] = array(
|
||||
'title' => t('Menu link'),
|
||||
'class' => 'i18n_menu_link_translation_set',
|
||||
'table' => 'menu_links',
|
||||
'field' => 'i18n_tsid',
|
||||
'parent' => 'menu',
|
||||
'placeholder' => '%i18n_menu_translation',
|
||||
'list path' => 'admin/structure/menu/manage/translation',
|
||||
'edit path' => 'admin/structure/menu/manage/translation/edit/%i18n_menu_translation',
|
||||
'delete path' => 'admin/structure/menu/manage/translation/delete/%i18n_menu_translation',
|
||||
'page callback' => 'i18n_menu_item_translation_page',
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_string_info()
|
||||
*/
|
||||
function i18n_menu_i18n_string_info() {
|
||||
$groups['menu'] = array(
|
||||
'title' => t('Menu'),
|
||||
'description' => t('Translatable menu items: title and description.'),
|
||||
'format' => FALSE, // This group doesn't have strings with format
|
||||
'list' => TRUE, // This group can list all strings
|
||||
);
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_string_objects()
|
||||
*/
|
||||
function i18n_menu_i18n_string_objects($type) {
|
||||
if ($type == 'menu_link') {
|
||||
// All menu items that have no language and are customized.
|
||||
return db_select('menu_links', 'm')
|
||||
->fields('m')
|
||||
->condition('language', LANGUAGE_NONE)
|
||||
->condition('customized', 1)
|
||||
->execute()
|
||||
->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for menu item translation tab.
|
||||
*/
|
||||
function i18n_menu_item_translation_page($type, $item) {
|
||||
module_load_include('admin.inc', 'i18n_menu');
|
||||
// If the item has a language code, we can only support translation sets.
|
||||
$translation_set = !empty($item['i18n_tsid']) ? i18n_translation_set_load($item['i18n_tsid']) : NULL;
|
||||
$build['overview'] = i18n_menu_translation_item_overview($item, $translation_set);
|
||||
$build['translation_form'] = drupal_get_form('i18n_menu_translation_form', $translation_set, $item);
|
||||
return $build;
|
||||
}
|
||||
|
98
sites/all/modules/i18n/i18n_menu/i18n_menu.inc
Normal file
98
sites/all/modules/i18n/i18n_menu/i18n_menu.inc
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Internationalization (i18n) module - Translation set
|
||||
*/
|
||||
class i18n_menu_link_translation_set extends i18n_translation_set {
|
||||
/**
|
||||
* Load all path translations
|
||||
*/
|
||||
public function load_translations() {
|
||||
$translations = array();
|
||||
$query = db_select('menu_links', 'ml');
|
||||
$query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
|
||||
$query->fields('ml');
|
||||
// Weight should be taken from {menu_links}, not {menu_router}.
|
||||
$query->addField('ml', 'weight', 'link_weight');
|
||||
$query->fields('m');
|
||||
$query->condition('ml.i18n_tsid', $this->tsid);
|
||||
foreach ($query->execute()->fetchAll(PDO::FETCH_ASSOC) as $item) {
|
||||
$item['weight'] = $item['link_weight'];
|
||||
_menu_link_translate($item);
|
||||
$translations[$item['language']] = $item;
|
||||
}
|
||||
return $translations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu link object
|
||||
*/
|
||||
class i18n_menu_link extends i18n_string_object_wrapper {
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct($type, $key, $object) {
|
||||
// Unserialize options if not done
|
||||
if (isset($object['options']) && !is_array($object['options'])) {
|
||||
$object['options'] = unserialize($object['options']);
|
||||
}
|
||||
parent::__construct($type, $key, $object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path for item
|
||||
*/
|
||||
public function get_path() {
|
||||
return $this->object['link_path'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title from item
|
||||
*/
|
||||
public function get_title() {
|
||||
return $this->object['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation mode for object
|
||||
*/
|
||||
public function get_translate_mode() {
|
||||
$mode = i18n_menu_mode($this->object['menu_name']);
|
||||
if ($this->get_langcode()) {
|
||||
return $mode & I18N_MODE_TRANSLATE;
|
||||
}
|
||||
elseif (!empty($this->object['customized'])) {
|
||||
return $mode & I18N_MODE_LOCALIZE;
|
||||
}
|
||||
else {
|
||||
return I18N_MODE_NONE;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Access to object translation. This should check object properties and permissions
|
||||
*/
|
||||
protected function translate_access() {
|
||||
return user_access('administer menu') && user_access('translate interface');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translatable properties.
|
||||
*
|
||||
* Check whether title or description are to be translated by default menu
|
||||
* system.
|
||||
*/
|
||||
protected function build_properties() {
|
||||
$properties = parent::build_properties();
|
||||
if ($properties) {
|
||||
$strings = &$properties['menu']['item'][$this->get_key()];
|
||||
$localizable = _i18n_menu_link_localizable_properties($this->object);
|
||||
foreach ($strings as $key => $data) {
|
||||
if (!in_array($key, $localizable)) {
|
||||
unset($strings[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $properties;
|
||||
}
|
||||
}
|
18
sites/all/modules/i18n/i18n_menu/i18n_menu.info
Normal file
18
sites/all/modules/i18n/i18n_menu/i18n_menu.info
Normal file
@@ -0,0 +1,18 @@
|
||||
name = Menu translation
|
||||
description = Supports translatable custom menu items.
|
||||
dependencies[] = i18n
|
||||
dependencies[] = menu
|
||||
dependencies[] = i18n_string
|
||||
dependencies[] = i18n_translation
|
||||
package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
|
||||
files[] = i18n_menu.inc
|
||||
files[] = i18n_menu.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-01-13
|
||||
version = "7.x-1.8"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1358075001"
|
||||
|
71
sites/all/modules/i18n/i18n_menu/i18n_menu.install
Normal file
71
sites/all/modules/i18n/i18n_menu/i18n_menu.install
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Installation file for i18nmenu module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function i18n_menu_install() {
|
||||
// Set module weight for it to run after core modules, but before views.
|
||||
db_query("UPDATE {system} SET weight = 5 WHERE name = 'i18n_menu' AND type = 'module'");
|
||||
module_load_install('i18n');
|
||||
i18n_install_create_fields('menu_links', array('language', 'i18n_tsid'));
|
||||
i18n_install_create_fields('menu_custom', array('language', 'i18n_mode'));
|
||||
// If updating from D6, module changed name
|
||||
if (variable_get('i18n_drupal6_update')) {
|
||||
i18n_menu_update_7000();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function i18n_menu_uninstall() {
|
||||
db_drop_field('menu_links', 'language');
|
||||
db_drop_field('menu_links', 'i18n_tsid');
|
||||
db_drop_field('menu_custom', 'language');
|
||||
db_drop_field('menu_custom', 'i18n_mode');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema_alter().
|
||||
*/
|
||||
function i18n_menu_schema_alter(&$schema) {
|
||||
$schema['menu_links']['fields']['language'] = array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => LANGUAGE_NONE);
|
||||
$schema['menu_links']['fields']['i18n_tsid'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0);
|
||||
$schema['menu_custom']['fields']['language'] = array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => LANGUAGE_NONE);
|
||||
$schema['menu_custom']['fields']['i18n_mode'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update menu items language field from Drupal 6
|
||||
*/
|
||||
function i18n_menu_update_7000() {
|
||||
// @todo
|
||||
}
|
||||
|
||||
/**
|
||||
* Set alter property for menu items with language.
|
||||
*/
|
||||
function i18n_menu_update_7001() {
|
||||
// Compile a list of menus with i18n options.
|
||||
$i18n_menus = array_filter(menu_get_names(), 'i18n_menu_mode');
|
||||
if ($i18n_menus) {
|
||||
$query = db_select('menu_links', 'm')
|
||||
->fields('m')
|
||||
->condition('menu_name', $i18n_menus);
|
||||
foreach ($query->execute()->fetchAllAssoc('mlid', PDO::FETCH_ASSOC) as $mlid => $item) {
|
||||
$options = unserialize($item['options']);
|
||||
if (_i18n_menu_link_check_alter($item) && empty($options['alter'])) {
|
||||
$options['alter'] = TRUE;
|
||||
db_update('menu_links')
|
||||
->condition('mlid', $mlid)
|
||||
->fields(array('options' => serialize($options)))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
952
sites/all/modules/i18n/i18n_menu/i18n_menu.module
Normal file
952
sites/all/modules/i18n/i18n_menu/i18n_menu.module
Normal file
@@ -0,0 +1,952 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Internationalization (i18n) submodule: Menu translation.
|
||||
*
|
||||
* @author Jose A. Reyero, 2005
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu()
|
||||
*/
|
||||
function i18n_menu_menu() {
|
||||
$items['admin/structure/menu/manage/translation'] = array(
|
||||
'title' => 'Translation sets',
|
||||
'page callback' => 'i18n_translation_set_list_manage',
|
||||
'page arguments' => array('menu_link'),
|
||||
'access arguments' => array('administer menu'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 10,
|
||||
);
|
||||
$items['admin/structure/menu/manage/translation/add'] = array(
|
||||
'title' => 'Add translation',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('i18n_menu_translation_form'),
|
||||
'access arguments' => array('administer menu'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
'file' => 'i18n_menu.admin.inc',
|
||||
);
|
||||
$items['admin/structure/menu/manage/translation/edit/%i18n_menu_translation'] = array(
|
||||
'title' => 'Edit translation',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('i18n_menu_translation_form', 6),
|
||||
'access arguments' => array('administer menu'),
|
||||
'type' => MENU_CALLBACK,
|
||||
'file' => 'i18n_menu.admin.inc',
|
||||
);
|
||||
$items['admin/structure/menu/manage/translation/delete/%i18n_menu_translation'] = array(
|
||||
'title' => 'Delete translation',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('i18n_translation_set_delete_confirm', 6),
|
||||
'access arguments' => array('administer menu'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_alter()
|
||||
*/
|
||||
function i18n_menu_menu_alter(&$items) {
|
||||
$items['admin/structure/menu/item/%menu_link'] = $items['admin/structure/menu/item/%menu_link/edit'];
|
||||
$items['admin/structure/menu/item/%menu_link']['type'] = MENU_CALLBACK;
|
||||
$items['admin/structure/menu/item/%menu_link/edit']['type'] = MENU_DEFAULT_LOCAL_TASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view().
|
||||
*/
|
||||
function i18n_menu_block_view_alter(&$data, $block) {
|
||||
if (($block->module == 'menu' || $block->module == 'system') && (i18n_menu_mode($block->delta) & I18N_MODE_MULTIPLE)) {
|
||||
$menus = menu_get_menus();
|
||||
if (isset($menus[$block->delta])) {
|
||||
if (empty($block->title)) {
|
||||
$data['subject'] = i18n_string_plain(
|
||||
array('menu', 'menu', $block->delta, 'title'),
|
||||
$menus[$block->delta]
|
||||
);
|
||||
}
|
||||
// Add contextual links for this block.
|
||||
if (!empty($data['content'])) {
|
||||
$data['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($block->delta));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_translate_path()
|
||||
*/
|
||||
function i18n_menu_i18n_translate_path($path) {
|
||||
$item = i18n_menu_link_load($path, i18n_langcode());
|
||||
if ($item && ($set = i18n_translation_object('menu_link', $item))) {
|
||||
$links = array();
|
||||
foreach ($set->get_translations() as $lang => $link) {
|
||||
$links[$lang] = array(
|
||||
'href' => $link['link_path'],
|
||||
'title' => $link['link_title'],
|
||||
'i18n_type' => 'menu_link',
|
||||
'i18n_object' => $link,
|
||||
);
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_insert()
|
||||
*/
|
||||
function i18n_menu_menu_insert($menu) {
|
||||
i18n_menu_menu_update($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_update()
|
||||
*/
|
||||
function i18n_menu_menu_update($menu) {
|
||||
// Stores the fields of menu links which need an update.
|
||||
$update = array();
|
||||
|
||||
if (!isset($menu['i18n_mode'])) {
|
||||
$menu['i18n_mode'] = I18N_MODE_NONE;
|
||||
}
|
||||
if (!($menu['i18n_mode'] & I18N_MODE_LANGUAGE)) {
|
||||
$menu['language'] = LANGUAGE_NONE;
|
||||
}
|
||||
db_update('menu_custom')
|
||||
->fields(array('language' => $menu['language'], 'i18n_mode' => $menu['i18n_mode']))
|
||||
->condition('menu_name', $menu['menu_name'])
|
||||
->execute();
|
||||
if (!$menu['i18n_mode']) {
|
||||
$update['language'] = LANGUAGE_NONE;
|
||||
}
|
||||
elseif ($menu['i18n_mode'] & I18N_MODE_LANGUAGE) {
|
||||
$update['language'] = $menu['language'];
|
||||
}
|
||||
|
||||
// Non translatable menu.
|
||||
if (!($menu['i18n_mode'] & I18N_MODE_TRANSLATE)) {
|
||||
$tsids = db_select('menu_links')
|
||||
->fields('menu_links', array('i18n_tsid'))
|
||||
->groupBy('i18n_tsid')
|
||||
->condition('menu_name', $menu['menu_name'])
|
||||
->condition('customized', 1)
|
||||
->condition('i18n_tsid', 0, '<>')
|
||||
->execute()
|
||||
->fetchCol(0);
|
||||
if (!empty($tsids)) {
|
||||
foreach ($tsids as $tsid) {
|
||||
if ($translation_set = i18n_translation_set_load($tsid)) {
|
||||
$translation_set->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
$update['i18n_tsid'] = 0;
|
||||
}
|
||||
|
||||
if (!empty($update)) {
|
||||
db_update('menu_links')
|
||||
->fields($update)
|
||||
->condition('menu_name', $menu['menu_name'])
|
||||
->condition('customized', 1)
|
||||
->execute();
|
||||
}
|
||||
|
||||
// Update strings, always add translation if no language
|
||||
if (!i18n_object_langcode($menu)) {
|
||||
i18n_string_object_update('menu', $menu);
|
||||
}
|
||||
|
||||
// Clear all menu caches.
|
||||
menu_cache_clear_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_delete()
|
||||
*/
|
||||
function i18n_menu_menu_delete($menu) {
|
||||
i18n_string_object_remove('menu', $menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_link_alter().
|
||||
*
|
||||
* This function is invoked from menu_link_save() before default
|
||||
* menu link options (menu_name, module, etc.. have been set)
|
||||
*/
|
||||
function i18n_menu_menu_link_alter(&$item) {
|
||||
// We just make sure every link has a valid language property.
|
||||
if (!i18n_object_langcode($item)) {
|
||||
$item['language'] = LANGUAGE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_link_insert()
|
||||
*/
|
||||
function i18n_menu_menu_link_insert($link) {
|
||||
i18n_menu_menu_link_update($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_link_update().
|
||||
*/
|
||||
function i18n_menu_menu_link_update($link) {
|
||||
// Stores the fields to update.
|
||||
$fields = array();
|
||||
$menu_mode = i18n_menu_mode($link['menu_name']);
|
||||
|
||||
if ($menu_mode & I18N_MODE_TRANSLATE && isset($link['language'])) {
|
||||
// Multilingual menu links, translatable, it may be part of a
|
||||
// translation set.
|
||||
if (i18n_object_langcode($link)) {
|
||||
if (!empty($link['translation_set'])) {
|
||||
// Translation set comes as parameter, we may be creating a translation,
|
||||
// add link to the set.
|
||||
$translation_set = $link['translation_set'];
|
||||
$translation_set
|
||||
->add_item($link)
|
||||
->save(TRUE);
|
||||
}
|
||||
}
|
||||
elseif ($link['language'] === LANGUAGE_NONE && !empty($link['original_item']['i18n_tsid'])) {
|
||||
if ($translation_set = i18n_translation_set_load($link['original_item']['i18n_tsid'])) {
|
||||
$translation_set->remove_language($link['original_item']['language']);
|
||||
// If there are no links left in this translation set, delete the set.
|
||||
// Otherwise update the set.
|
||||
$translation_set->update_delete();
|
||||
}
|
||||
$fields['i18n_tsid'] = 0;
|
||||
}
|
||||
}
|
||||
// For multilingual menu items, always set a language and mark them for
|
||||
// 'alter' so they can be processed later by
|
||||
// hook_translated_link_menu_alter().
|
||||
if ($menu_mode) {
|
||||
if (!isset($link['language'])) {
|
||||
$link['language'] = LANGUAGE_NONE;
|
||||
}
|
||||
if (_i18n_menu_link_check_alter($link) && empty($link['options']['alter'])) {
|
||||
$fields['options'] = $link['options'];
|
||||
$fields['options']['alter'] = TRUE;
|
||||
}
|
||||
// We cannot unmark links for altering because we don't know what other
|
||||
// modules use it for.
|
||||
}
|
||||
// Update language field if the link has a language value.
|
||||
if (isset($link['language'])) {
|
||||
$fields['language'] = $link['language'];
|
||||
}
|
||||
|
||||
if (!empty($fields)) {
|
||||
// If link options are to be updated, they need to be serialized.
|
||||
if (isset($fields['options'])) {
|
||||
$fields['options'] = serialize($fields['options']);
|
||||
}
|
||||
db_update('menu_links')
|
||||
->fields($fields)
|
||||
->condition('mlid', $link['mlid'])
|
||||
->execute();
|
||||
}
|
||||
// Update translatable strings if any for customized links that belong to a
|
||||
// localizable menu.
|
||||
if (_i18n_menu_link_is_localizable($link)) {
|
||||
i18n_string_object_update('menu_link', $link);
|
||||
}
|
||||
else {
|
||||
i18n_string_object_remove('menu_link', $link);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_delete()
|
||||
*/
|
||||
function i18n_menu_menu_link_delete($link) {
|
||||
// If a translation set exists for this link, remove this link from the set.
|
||||
if (!empty($link['i18n_tsid'])) {
|
||||
if ($translation_set = i18n_translation_set_load($link['i18n_tsid'])) {
|
||||
$translation_set->get_translations();
|
||||
|
||||
$translation_set->remove_language($link['language']);
|
||||
|
||||
// If there are no links left in this translation set, delete the set.
|
||||
// Otherwise update the set.
|
||||
$translation_set->update_delete();
|
||||
}
|
||||
}
|
||||
|
||||
i18n_string_object_remove('menu_link', $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get menu mode or compare with given one
|
||||
*/
|
||||
function i18n_menu_mode($name, $mode = NULL) {
|
||||
$menu = menu_load($name);
|
||||
if (!$menu || !isset($menu['i18n_mode'])) {
|
||||
return isset($mode) ? FALSE : I18N_MODE_NONE;
|
||||
}
|
||||
else {
|
||||
return isset($mode) ? $menu['i18n_mode'] & $mode : $menu['i18n_mode'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_translated_menu_link_alter().
|
||||
*
|
||||
* Translate localizable menu links on the fly.
|
||||
* Filter out items that have a different language from current interface.
|
||||
*
|
||||
* @see i18n_menu_menu_link_alter()
|
||||
*/
|
||||
function i18n_menu_translated_menu_link_alter(&$item) {
|
||||
// Only process links to be displayed not processed before by i18n_menu.
|
||||
if (_i18n_menu_link_process($item)) {
|
||||
if (!_i18n_menu_link_is_visible($item)) {
|
||||
$item['hidden'] = TRUE;
|
||||
}
|
||||
elseif (_i18n_menu_link_is_localizable($item)) {
|
||||
// Item has undefined language, it is a candidate for localization.
|
||||
_i18n_menu_link_localize($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function i18n_menu_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#i18n_menu' :
|
||||
$output = '<p>' . t('This module adds support for multilingual menus. You can setup multilingual options for each menu:') . '</p>';
|
||||
$output .= '<ul>';
|
||||
$output .= '<li>' . t('Menus can be fully multilingual with translatable (or localized) menu items.') . '</li>';
|
||||
$output .= '<li>' . t('Menus can be configured to have a fixed language. All menu items share this language setting and the menu will be visible in that language only.') . '</li>';
|
||||
$output .= '<li>' . t('Menus can also be configured to have no translations.') . '</li>';
|
||||
$output .= '</ul>';
|
||||
$output .= '<p>' . t('The multilingual options of a menu must be configured before individual menu items can be translated. Go to the <a href="@menu-admin">Menus administration page</a> and follow the "edit menu" link to the menu in question.', array('@menu-admin' => url('admin/structure/menu') ) ) . '</p>';
|
||||
$output .= '<p>' . t('To search and translate strings, use the <a href="@translate-interface">translation interface</a> pages.', array('@translate-interface' => url('admin/config/regional/translate'))) . '</p>';
|
||||
return $output;
|
||||
|
||||
case 'admin/config/regional/i18n':
|
||||
$output = '<p>' . t('Menus and menu items can be translated on the <a href="@configure_menus">Menu administration page</a>.', array('@configure_menus' => url('admin/structure/menu'))) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_variable_info_alter()
|
||||
*/
|
||||
function i18n_menu_variable_info_alter(&$variables, $options) {
|
||||
// Make menu variables translatable
|
||||
$variables['menu_main_links_source']['localize'] = TRUE;
|
||||
$variables['menu_secondary_links_source']['localize'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localized menu tree.
|
||||
*
|
||||
* @param string $menu_name
|
||||
* The menu the translated tree has to be fetched from.
|
||||
* @param string $langcode
|
||||
* Optional language code to get the menu in, defaults to request language.
|
||||
* @param bool $reset
|
||||
* Whether to reset the internal i18n_menu_translated_tree cache.
|
||||
*/
|
||||
function i18n_menu_translated_tree($menu_name, $langcode = NULL, $reset = FALSE) {
|
||||
$menu_output = &drupal_static(__FUNCTION__);
|
||||
$langcode = $langcode ? $langcode : i18n_language_interface()->language;
|
||||
if (!isset($menu_output[$langcode][$menu_name]) || $reset) {
|
||||
$tree = menu_tree_page_data($menu_name);
|
||||
$tree = i18n_menu_localize_tree($tree, $langcode);
|
||||
$menu_output[$langcode][$menu_name] = menu_tree_output($tree);
|
||||
}
|
||||
return $menu_output[$langcode][$menu_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize menu tree.
|
||||
*/
|
||||
function i18n_menu_localize_tree($tree, $langcode = NULL) {
|
||||
$langcode = $langcode ? $langcode : i18n_language_interface()->language;
|
||||
foreach ($tree as $index => &$item) {
|
||||
$link = $item['link'];
|
||||
// We only process links that are visible and not processed before.
|
||||
if (_i18n_menu_link_process($item['link'])) {
|
||||
if (!_i18n_menu_link_is_visible($item['link'], $langcode)) {
|
||||
// Remove links for other languages than current.
|
||||
// Links with language wont be localized.
|
||||
unset($tree[$index]);
|
||||
// @todo Research whether the above has any advantage over:
|
||||
// $item['hidden'] = TRUE;
|
||||
}
|
||||
else {
|
||||
if (_i18n_menu_link_is_localizable($item['link'])) {
|
||||
// Item has undefined language, it is a candidate for localization.
|
||||
_i18n_menu_link_localize($item['link'], $langcode);
|
||||
}
|
||||
// Localize subtree.
|
||||
if (!empty($item['below'])) {
|
||||
$item['below'] = i18n_menu_localize_tree($item['below'], $langcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize menu renderable array
|
||||
*/
|
||||
function i18n_menu_localize_elements(&$elements) {
|
||||
foreach (element_children($elements) as $mlid) {
|
||||
$elements[$mlid]['#title'] = i18n_string(array('menu', 'item', $mlid, 'title'), $elements[$mlid]['#title']);
|
||||
if (!empty($tree[$mlid]['#localized_options']['attributes']['title'])) {
|
||||
$elements[$mlid]['#localized_options']['attributes']['title'] = i18n_string(array('menu', 'item', $mlid, 'description'), $tree[$mlid]['#localized_options']['attributes']['title']);
|
||||
}
|
||||
i18n_menu_localize_elements($elements[$mlid]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of localized links for a navigation menu.
|
||||
*
|
||||
* Localized version of menu_navigation_links()
|
||||
*/
|
||||
function i18n_menu_navigation_links($menu_name, $level = 0) {
|
||||
// Don't even bother querying the menu table if no menu is specified.
|
||||
if (empty($menu_name)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Get the menu hierarchy for the current page.
|
||||
$tree = menu_tree_page_data($menu_name, $level + 1);
|
||||
$tree = i18n_menu_localize_tree($tree);
|
||||
|
||||
// Go down the active trail until the right level is reached.
|
||||
while ($level-- > 0 && $tree) {
|
||||
// Loop through the current level's items until we find one that is in trail.
|
||||
while ($item = array_shift($tree)) {
|
||||
if ($item['link']['in_active_trail']) {
|
||||
// If the item is in the active trail, we continue in the subtree.
|
||||
$tree = empty($item['below']) ? array() : $item['below'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a single level of links.
|
||||
$router_item = menu_get_item();
|
||||
$links = array();
|
||||
foreach ($tree as $item) {
|
||||
if (!$item['link']['hidden']) {
|
||||
$class = '';
|
||||
$l = $item['link']['localized_options'];
|
||||
$l['href'] = $item['link']['href'];
|
||||
$l['title'] = $item['link']['title'];
|
||||
if ($item['link']['in_active_trail']) {
|
||||
$class = ' active-trail';
|
||||
$l['attributes']['class'][] = 'active-trail';
|
||||
}
|
||||
// Normally, l() compares the href of every link with $_GET['q'] and sets
|
||||
// the active class accordingly. But local tasks do not appear in menu
|
||||
// trees, so if the current path is a local task, and this link is its
|
||||
// tab root, then we have to set the class manually.
|
||||
if ($item['link']['href'] == $router_item['tab_root_href'] && $item['link']['href'] != $_GET['q']) {
|
||||
$l['attributes']['class'][] = 'active';
|
||||
}
|
||||
// Keyed with the unique mlid to generate classes in theme_links().
|
||||
$links['menu-' . $item['link']['mlid'] . $class] = $l;
|
||||
}
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localized menu title
|
||||
*/
|
||||
function _i18n_menu_link_title($link, $langcode = NULL) {
|
||||
return i18n_string_translate(array('menu', 'item', $link['mlid'], 'title'), $link['link_title'], array('langcode' => $langcode, 'sanitize' => FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize menu item title and description.
|
||||
*
|
||||
* This will be invoked always after _menu_item_localize()
|
||||
*
|
||||
* Link properties to manage:
|
||||
* - title, menu router title
|
||||
* - link_title, menu link title
|
||||
* - options.attributes.title, menu link description.
|
||||
* - localized_options.attributes.title,
|
||||
*
|
||||
* @see _menu_item_localize()
|
||||
* @see _menu_link_translate()
|
||||
*/
|
||||
function _i18n_menu_link_localize(&$link, $langcode = NULL) {
|
||||
// Only translate title if it has no special callback.
|
||||
if (empty($link['title callback']) || $link['title callback'] === 't') {
|
||||
$link['title'] = _i18n_menu_link_title($link, $langcode);
|
||||
}
|
||||
if ($description = _i18n_menu_link_description($link, $langcode)) {
|
||||
$link['localized_options']['attributes']['title'] = $description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localized menu description
|
||||
*/
|
||||
function _i18n_menu_link_description($link, $langcode = NULL) {
|
||||
if (!empty($link['options']['attributes']['title'])) {
|
||||
return i18n_string_translate(array('menu', 'item', $link['mlid'], 'description'), $link['options']['attributes']['title'], array('langcode' => $langcode));
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this link is to be processed by i18n_menu and start processing.
|
||||
*/
|
||||
function _i18n_menu_link_process(&$link) {
|
||||
// Only visible links that have a language property and haven't been processed
|
||||
// before. We also check that they belong to a menu with language options.
|
||||
if (empty($link['i18n_menu']) && !empty($link['language']) && !empty($link['access']) && empty($link['hidden']) && i18n_menu_mode($link['menu_name'])) {
|
||||
// Mark so it won't be processed twice.
|
||||
$link['i18n_menu'] = TRUE;
|
||||
// Skip if administering this menu or this menu item.
|
||||
if (arg(0) == 'admin' && arg(1) == 'structure' && arg(2) == 'menu') {
|
||||
if (arg(3) == 'manage' && $link['menu_name'] == arg(4)) {
|
||||
return FALSE;
|
||||
}
|
||||
elseif (arg(3) == 'item' && arg(4) == $link['mlid']) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this menu item should be marked for altering.
|
||||
*
|
||||
* Menu items that have a language or that have any localizable strings
|
||||
* will be marked to be run through hook_translated_menu_link_alter().
|
||||
*
|
||||
* @see i18n_menu_translated_menu_link_alter()
|
||||
*/
|
||||
function _i18n_menu_link_check_alter($link) {
|
||||
return i18n_menu_mode($link['menu_name']) && (i18n_object_langcode($link) || _i18n_menu_link_is_localizable($link, TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this link should be localized by i18n_menu.
|
||||
*
|
||||
* @param array $link
|
||||
* Menu link array.
|
||||
* @param bool $check_strings
|
||||
* Whether to check if the link has actually localizable strings. Since this
|
||||
* is a more expensive operation, it will be just checked when editing menu
|
||||
* items.
|
||||
*
|
||||
* @return boolean
|
||||
* Returns TRUE if link is localizable.
|
||||
*/
|
||||
function _i18n_menu_link_is_localizable($link, $check_strings = FALSE) {
|
||||
return !empty($link['customized']) && !i18n_object_langcode($link) && i18n_menu_mode($link['menu_name'], I18N_MODE_LOCALIZE) &&
|
||||
(!$check_strings || _i18n_menu_link_localizable_properties($link));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this menu link is visible for current/given language.
|
||||
*/
|
||||
function _i18n_menu_link_is_visible($link, $langcode = NULL) {
|
||||
$langcode = $langcode ? $langcode : i18n_language_interface()->language;
|
||||
return $link['language'] == LANGUAGE_NONE || $link['language'] == $langcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localizable properties for menu link checking agains the router item.
|
||||
*/
|
||||
function _i18n_menu_link_localizable_properties($link) {
|
||||
$props = array();
|
||||
$router = !empty($link['router_path']) ? _i18n_menu_get_router($link['router_path']) : NULL;
|
||||
if (!empty($link['link_title'])) {
|
||||
// If the title callback is 't' and the link title matches the router title
|
||||
// it will be localized by core, not by i18n_menu.
|
||||
if (!$router ||
|
||||
(empty($router['title_callback']) || $router['title_callback'] != 't') ||
|
||||
(empty($router['title']) || $router['title'] != $link['link_title'])
|
||||
) {
|
||||
$props[] = 'title';
|
||||
}
|
||||
}
|
||||
if (!empty($link['options']['attributes']['title'])) {
|
||||
// If the description matches the router description, it will be localized
|
||||
// by core.
|
||||
if (!$router || empty($router['description']) || $router['description'] != $link['options']['attributes']['title']) {
|
||||
$props[] = 'description';
|
||||
}
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the menu router for this router path.
|
||||
*
|
||||
* We need the untranslated title to compare, and this will be fast.
|
||||
* There's no api function to do this?
|
||||
*
|
||||
* @param string $path
|
||||
* The path to fetch from the router.
|
||||
*/
|
||||
function _i18n_menu_get_router($path) {
|
||||
$cache = &drupal_static(__FUNCTION__, array());
|
||||
if (!array_key_exists($path, $cache)) {
|
||||
$cache[$path] = db_select('menu_router', 'mr')
|
||||
->fields('mr', array('title', 'title_callback', 'description'))
|
||||
->condition('path', $path)
|
||||
->execute()
|
||||
->fetchAssoc();
|
||||
}
|
||||
return $cache[$path];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
function i18n_menu_form_menu_edit_menu_alter(&$form, &$form_state) {
|
||||
$menu = menu_load($form['old_name']['#value']);
|
||||
$i18n_mode = $menu && isset($menu['i18n_mode']) ? $menu['i18n_mode'] : I18N_MODE_NONE;
|
||||
$langcode = $menu && isset($menu['language']) ? $menu['language'] : LANGUAGE_NONE;
|
||||
|
||||
$form += i18n_translation_mode_element('menu', $i18n_mode, $langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*
|
||||
* Add a language selector to the menu_edit_item form and register a submit
|
||||
* callback to process items.
|
||||
*/
|
||||
function i18n_menu_form_menu_edit_item_alter(&$form, &$form_state) {
|
||||
$item = &$form['original_item']['#value'];
|
||||
$item['language'] = i18n_menu_item_get_language($item);
|
||||
// Check whether this item belongs to a node object and it is a supported type.
|
||||
$node_item = ($node = i18n_menu_item_get_node($item)) && i18n_menu_node_supported_type($node->type);
|
||||
if (!$node_item && i18n_menu_mode($item['menu_name'], I18N_MODE_TRANSLATE)) {
|
||||
//$form['i18n'] = array('#type' => 'fieldset');
|
||||
$form['i18n']['language'] = array(
|
||||
'#description' => t('This item belongs to a multilingual menu. You can set a language for it.'),
|
||||
) + i18n_element_language_select($item);
|
||||
|
||||
// If the term to be added will be a translation of a source term,
|
||||
// set the default value of the option list to the target language and
|
||||
// create a form element for storing the translation set of the source term.
|
||||
if (isset($_GET['translation']) && isset($_GET['target']) && ($source_item = menu_link_load($_GET['translation']))) {
|
||||
if (!empty($source_item['i18n_tsid'])) {
|
||||
$translation_set = i18n_translation_set_load($source_item['i18n_tsid']);
|
||||
}
|
||||
else {
|
||||
// Create object and stick the source information in the translation set.
|
||||
$translation_set = i18n_translation_set_build('menu_link')
|
||||
->add_item($source_item);
|
||||
}
|
||||
$form['link_path']['#default_value'] = $source_item['link_path'];
|
||||
|
||||
// Maybe we should disable the 'link_path' and 'parent' form elements?
|
||||
// $form['link_path']['#disabled'] = TRUE;
|
||||
// $form['parent']['#disabled'] = TRUE;
|
||||
|
||||
$form['i18n']['language']['#default_value'] = $_GET['target'];
|
||||
$form['i18n']['language']['#disabled'] = TRUE;
|
||||
|
||||
drupal_set_title(t('%language translation of menu item %title', array('%language' => locale_language_name($_GET['target']), '%title' => $source_item['link_title'])), PASS_THROUGH);
|
||||
}
|
||||
elseif (!empty($item['i18n_tsid'])) {
|
||||
$translation_set = i18n_translation_set_load($item['i18n_tsid']);
|
||||
}
|
||||
|
||||
// Add the translation set to the form so we know the new menu item
|
||||
// needs to be added to that set.
|
||||
if (!empty($translation_set)) {
|
||||
$form['translation_set'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $translation_set,
|
||||
);
|
||||
|
||||
// If the current term is part of a translation set,
|
||||
// remove all other languages of the option list.
|
||||
if ($translations = $translation_set->get_translations()) {
|
||||
unset($form['i18n']['language']['#options'][LANGUAGE_NONE]);
|
||||
foreach ($translations as $langcode => $translation) {
|
||||
if ($translation['mlid'] !== $item['mlid']) {
|
||||
unset($form['i18n']['language']['#options'][$langcode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form['language'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $item['language'],
|
||||
);
|
||||
}
|
||||
if ($node_item && i18n_langcode($item['language'])) {
|
||||
$form['i18n']['message'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Language'),
|
||||
'#markup' => i18n_language_name($item['language']),
|
||||
'#description' => t('This menu item belongs to a node, so it will have the same language as the node and cannot be localized.'),
|
||||
);
|
||||
}
|
||||
array_unshift($form['#validate'], 'i18n_menu_menu_item_prepare_normal_path');
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal path should be checked with menu item's language to avoid
|
||||
* troubles when a node and it's translation has the same url alias.
|
||||
*/
|
||||
function i18n_menu_menu_item_prepare_normal_path($form, &$form_state) {
|
||||
$item = &$form_state['values'];
|
||||
$item['link_path'] = i18n_prepare_normal_path($item['link_path'], $item['language']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language for menu item
|
||||
*/
|
||||
function i18n_menu_item_get_language($item) {
|
||||
if (isset($item['language'])) {
|
||||
return $item['language'];
|
||||
}
|
||||
else {
|
||||
$menu = menu_load($item['menu_name']);
|
||||
switch ($menu['i18n_mode']) {
|
||||
case I18N_MODE_LANGUAGE:
|
||||
return $menu['language'];
|
||||
case I18N_MODE_NONE:
|
||||
case I18N_MODE_LOCALIZE:
|
||||
return LANGUAGE_NONE;
|
||||
default:
|
||||
if (!empty($item['mlid'])) {
|
||||
return db_select('menu_links', 'm')
|
||||
->fields('m', array('language'))
|
||||
->condition('mlid', $item['mlid'])
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
else {
|
||||
return LANGUAGE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_node_form_alter().
|
||||
*
|
||||
* Add language to menu settings of the node form, as well as setting defaults
|
||||
* to match the translated item's menu settings.
|
||||
*/
|
||||
function i18n_menu_form_node_form_alter(&$form, &$form_state, $form_id) {
|
||||
if (isset($form['menu'])) {
|
||||
$node = $form['#node'];
|
||||
$link = $node->menu;
|
||||
if (!empty($link['mlid'])) {
|
||||
// Preserve the menu item language whatever it is.
|
||||
$form['menu']['link']['language'] = array('#type' => 'value', '#value' => $link['language']);
|
||||
}
|
||||
elseif (i18n_menu_node_supported_type($node->type)) {
|
||||
// Set menu language to node language but only if it is a supported node type.
|
||||
$form['menu']['link']['language'] = array('#type' => 'value', '#value' => $node->language);
|
||||
}
|
||||
else {
|
||||
$form['menu']['link']['language'] = array('#type' => 'value', '#value' => LANGUAGE_NONE);
|
||||
}
|
||||
// Customized must be set to 1 to save language.
|
||||
$form['menu']['link']['customized'] = array('#type' => 'value', '#value' => 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a node type has multilingual support (but not entity translation).
|
||||
*/
|
||||
function i18n_menu_node_supported_type($type) {
|
||||
$supported = &drupal_static(__FUNCTION__);
|
||||
if (!isset($supported[$type])) {
|
||||
$mode = variable_get('language_content_type_' . $type, 0);
|
||||
$supported[$type] = $mode == 1 || $mode == 2; // 2 == TRANSLATION_ENABLED
|
||||
}
|
||||
return $supported[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the node object for a menu item.
|
||||
*/
|
||||
function i18n_menu_item_get_node($item) {
|
||||
return isset($item['router_path']) && $item['router_path'] == 'node/%' ? node_load(arg(1, $item['link_path'])) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_presave()
|
||||
*
|
||||
* Set menu link language to node language
|
||||
*/
|
||||
function i18n_menu_node_presave($node) {
|
||||
if (!empty($node->menu) && isset($node->language) && i18n_menu_node_supported_type($node->type)) {
|
||||
$node->menu['language'] = i18n_object_langcode($node, LANGUAGE_NONE);
|
||||
// Store node type with menu item so we can quickly access it later.
|
||||
$node->menu['options']['node_type'] = $node->type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_prepare_translation().
|
||||
*/
|
||||
function i18n_menu_node_prepare_translation($node) {
|
||||
if (empty($node->menu['mlid']) && !empty($node->translation_source)) {
|
||||
$tnode = $node->translation_source;
|
||||
// Prepare the tnode so the menu item will be available.
|
||||
node_object_prepare($tnode);
|
||||
$node->menu['link_title'] = $tnode->menu['link_title'];
|
||||
$node->menu['weight'] = $tnode->menu['weight'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process menu and menu item add/edit form submissions.
|
||||
*
|
||||
* @todo See where this fits
|
||||
*/
|
||||
/*
|
||||
function i18n_menu_edit_item_form_submit($form, &$form_state) {
|
||||
$mid = menu_edit_item_save($form_state['values']);
|
||||
db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", array($form_state['values']['language'], $mid));
|
||||
return 'admin/build/menu';
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load translation set. Menu loading callback.
|
||||
*/
|
||||
function i18n_menu_translation_load($tsid) {
|
||||
return i18n_translation_set_load($tsid, 'menu_link');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load menu item by path, language
|
||||
*/
|
||||
function i18n_menu_link_load($path, $langcode) {
|
||||
$query = db_select('menu_links', 'ml');
|
||||
$query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
|
||||
$query->fields('ml');
|
||||
// Weight should be taken from {menu_links}, not {menu_router}.
|
||||
$query->addField('ml', 'weight', 'link_weight');
|
||||
$query->fields('m');
|
||||
$query->condition('ml.link_path', $path);
|
||||
$query->condition('ml.language', $langcode);
|
||||
if ($item = $query->execute()->fetchAssoc()) {
|
||||
$item['weight'] = $item['link_weight'];
|
||||
_menu_link_translate($item);
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_init().
|
||||
*/
|
||||
function i18n_menu_init() {
|
||||
|
||||
// The only way to override the default preferred menu link for a path is to
|
||||
// inject it into the static cache of the function menu_link_get_preferred().
|
||||
|
||||
// The problem with the default implementation is that it does not take the
|
||||
// language of a menu link into account. Whe having different menu trees for
|
||||
// different menus, this means that the active trail will not work for all but
|
||||
// one language.
|
||||
|
||||
// The code below is identical to the mentioned function except the added
|
||||
// language condition on the query.
|
||||
|
||||
// TODO: Adding an alter tag to the query would allow to do this with a simple
|
||||
// hook_query_alter() implementation.
|
||||
|
||||
$preferred_links = &drupal_static('menu_link_get_preferred');
|
||||
|
||||
$path = $_GET['q'];
|
||||
|
||||
// Look for the correct menu link by building a list of candidate paths,
|
||||
// which are ordered by priority (translated hrefs are preferred over
|
||||
// untranslated paths). Afterwards, the most relevant path is picked from
|
||||
// the menus, ordered by menu preference.
|
||||
$item = menu_get_item($path);
|
||||
$path_candidates = array();
|
||||
// 1. The current item href.
|
||||
$path_candidates[$item['href']] = $item['href'];
|
||||
// 2. The tab root href of the current item (if any).
|
||||
if ($item['tab_parent'] && ($tab_root = menu_get_item($item['tab_root_href']))) {
|
||||
$path_candidates[$tab_root['href']] = $tab_root['href'];
|
||||
}
|
||||
// 3. The current item path (with wildcards).
|
||||
$path_candidates[$item['path']] = $item['path'];
|
||||
// 4. The tab root path of the current item (if any).
|
||||
if (!empty($tab_root)) {
|
||||
$path_candidates[$tab_root['path']] = $tab_root['path'];
|
||||
}
|
||||
// Retrieve a list of menu names, ordered by preference.
|
||||
$menu_names = menu_get_active_menu_names();
|
||||
// Use an illegal menu name as the key for the preferred menu link.
|
||||
$selected_menu = MENU_PREFERRED_LINK;
|
||||
// Put the selected menu at the front of the list.
|
||||
array_unshift($menu_names, $selected_menu);
|
||||
|
||||
$query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
|
||||
$query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
|
||||
$query->fields('ml');
|
||||
// Weight must be taken from {menu_links}, not {menu_router}.
|
||||
$query->addField('ml', 'weight', 'link_weight');
|
||||
$query->fields('m');
|
||||
$query->condition('ml.link_path', $path_candidates, 'IN');
|
||||
|
||||
// Only look menu links with none or the current language.
|
||||
$query->condition('ml.language', array(LANGUAGE_NONE, i18n_language_interface()->language), 'IN');
|
||||
|
||||
// Sort candidates by link path and menu name.
|
||||
$candidates = array();
|
||||
foreach ($query->execute() as $candidate) {
|
||||
$candidate['weight'] = $candidate['link_weight'];
|
||||
$candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
|
||||
// Add any menus not already in the menu name search list.
|
||||
if (!in_array($candidate['menu_name'], $menu_names)) {
|
||||
$menu_names[] = $candidate['menu_name'];
|
||||
}
|
||||
}
|
||||
|
||||
// Store the most specific link for each menu. Also save the most specific
|
||||
// link of the most preferred menu in $preferred_link.
|
||||
foreach ($path_candidates as $link_path) {
|
||||
if (isset($candidates[$link_path])) {
|
||||
foreach ($menu_names as $menu_name) {
|
||||
if (empty($preferred_links[$path][$menu_name]) && isset($candidates[$link_path][$menu_name])) {
|
||||
$candidate_item = $candidates[$link_path][$menu_name];
|
||||
$map = explode('/', $path);
|
||||
_menu_translate($candidate_item, $map);
|
||||
if ($candidate_item['access']) {
|
||||
$preferred_links[$path][$menu_name] = $candidate_item;
|
||||
if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) {
|
||||
// Store the most specific link.
|
||||
$preferred_links[$path][MENU_PREFERRED_LINK] = $candidate_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
292
sites/all/modules/i18n/i18n_menu/i18n_menu.test
Normal file
292
sites/all/modules/i18n/i18n_menu/i18n_menu.test
Normal file
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test case for multilingual menus.
|
||||
*/
|
||||
class i18nMenuTestCase extends Drupali18nTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Menu translation',
|
||||
'group' => 'Internationalization',
|
||||
'description' => 'Menu translation functions',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('i18n_menu', 'translation'));
|
||||
parent::setUpLanguages(array('administer menu'));
|
||||
$this->translator = $this->drupalCreateUser(array('translate interface', 'translate user-defined strings'));
|
||||
}
|
||||
|
||||
function testMenuTranslateLocalize() {
|
||||
// Test filtering for menu blocks.
|
||||
$menu = $this->createMenu(array('i18n_mode' => I18N_MODE_MULTIPLE));
|
||||
|
||||
$neutral_item = $this->createMenuLink(array('menu_name' => $menu['menu_name']));
|
||||
$default_item = $this->createMenuLink(array('menu_name' => $menu['menu_name'], 'language' => $this->default_language));
|
||||
$secondary_item = $this->createMenuLink(array('menu_name' => $menu['menu_name'], 'language' => $this->secondary_language));
|
||||
|
||||
$block['title'] = $menu['title'];
|
||||
$block['module'] = 'menu';
|
||||
$block['delta'] = $menu['menu_name'];
|
||||
$this->moveBlockToRegion($block, 'sidebar_first');
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText($neutral_item['link_title']);
|
||||
$this->assertText($default_item['link_title']);
|
||||
$this->assertNoText($secondary_item['link_title']);
|
||||
|
||||
$this->i18nGet($this->secondary_language, '<front>');
|
||||
$this->assertText($neutral_item['link_title']);
|
||||
$this->assertNoText($default_item['link_title']);
|
||||
$this->assertText($secondary_item['link_title']);
|
||||
|
||||
// Test filtering for built-in menus.
|
||||
$edit = array(
|
||||
'i18n_mode' => I18N_MODE_MULTIPLE,
|
||||
);
|
||||
$this->drupalPost('admin/structure/menu/manage/main-menu/edit', $edit, t('Save'));
|
||||
|
||||
$neutral_item = $this->createMenuLink(array('menu_name' => 'main-menu'));
|
||||
$default_item = $this->createMenuLink(array('menu_name' => 'main-menu', 'language' => $this->default_language));
|
||||
$secondary_item = $this->createMenuLink(array('menu_name' => 'main-menu', 'language' => $this->secondary_language));
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText($neutral_item['link_title']);
|
||||
$this->assertText($default_item['link_title']);
|
||||
$this->assertNoText($secondary_item['link_title']);
|
||||
|
||||
$this->i18nGet($this->secondary_language, '<front>');
|
||||
$this->assertText($neutral_item['link_title']);
|
||||
$this->assertNoText($default_item['link_title']);
|
||||
$this->assertText($secondary_item['link_title']);
|
||||
|
||||
// Test the same thing with a system menu used as a block.
|
||||
$block['title'] = $menu['title'];
|
||||
$block['module'] = 'system';
|
||||
$block['delta'] = 'main-menu';
|
||||
$this->moveBlockToRegion($block, 'sidebar_first');
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText($neutral_item['link_title']);
|
||||
$this->assertText($default_item['link_title']);
|
||||
$this->assertNoText($secondary_item['link_title']);
|
||||
|
||||
$this->i18nGet($this->secondary_language, '<front>');
|
||||
$this->assertText($neutral_item['link_title']);
|
||||
$this->assertNoText($default_item['link_title']);
|
||||
$this->assertText($secondary_item['link_title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test menu items for nodes.
|
||||
*/
|
||||
function testNodeMenuItems() {
|
||||
// Create menu and display it in a block.
|
||||
$menu = $this->createMenu(array(
|
||||
'i18n_mode' => I18N_MODE_MULTIPLE,
|
||||
'language' => LANGUAGE_NONE,
|
||||
'menu_name' => 'test',
|
||||
));
|
||||
|
||||
$neutral_item = $this->createMenuLink(array('menu_name' => $menu['menu_name']));
|
||||
$block['title'] = $menu['title'];
|
||||
$block['module'] = 'menu';
|
||||
$block['delta'] = $menu['menu_name'];
|
||||
$this->moveBlockToRegion($block, 'sidebar_first');
|
||||
$menu_parent = $menu['menu_name'] . ':0';
|
||||
// Create content type 'page', translation enabled, login as translator
|
||||
parent::setUpContentTranslation();
|
||||
$settings = array(
|
||||
'menu_options[' . $menu['menu_name'] . ']' => TRUE,
|
||||
'menu_parent' => $menu_parent,
|
||||
'node_options[promote]' => FALSE,
|
||||
);
|
||||
$this->drupalPost('admin/structure/types/manage/page/edit', $settings, t('Save content type'));
|
||||
|
||||
// Create nodes with language and menu item: es, en, und
|
||||
$edit = array(
|
||||
'menu[enabled]' => TRUE,
|
||||
'menu[parent]' => $menu_parent,
|
||||
'promote' => FALSE,
|
||||
);
|
||||
// English Page => English menu item
|
||||
$en_title = $this->randomName(10);
|
||||
$en_body = $this->randomString(50);
|
||||
$nodes[] = $en_node = $this->createNode('page', $en_title, $en_body, 'en', $edit + array('menu[link_title]' => $en_title));
|
||||
// Spanish page => Spanish menu item
|
||||
$es_title = $this->randomName(10);
|
||||
$es_body = $this->randomString(50);
|
||||
$nodes[] = $es_node = $this->createNode('page', $es_title, $es_body, 'es', $edit + array('menu[link_title]' => $es_title));
|
||||
// Language neutral page, localicable menu item
|
||||
$und_title = $this->randomName(10);
|
||||
$und_body = $this->randomString(50);
|
||||
$nodes[] = $und_node = $this->createNode('page', $und_title, $und_body, LANGUAGE_NONE, $edit + array('menu[link_title]' => $und_title));
|
||||
// Check menu items have right language and we cannot edit them.
|
||||
foreach ($nodes as $node) {
|
||||
menu_node_prepare($node);
|
||||
$this->assertEqual($node->menu['language'], $node->language, 'Menu item has the same language that the node it belongs to.');
|
||||
$this->drupalGet('admin/structure/menu/item/' . $node->menu['mlid'] . '/edit');
|
||||
$this->assertText(t('This menu item belongs to a node, so it will have the same language as the node and cannot be localized.'));
|
||||
$this->assertNoField('language', 'We cannot edit language for menu items that belong to nodes.');
|
||||
}
|
||||
// Check menu items show up for the right language.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText($en_title);
|
||||
$this->assertNoText($es_title);
|
||||
$this->assertText($und_title);
|
||||
$this->i18nGet('es', '<front>');
|
||||
$this->assertText($es_title);
|
||||
$this->assertNoText($en_title);
|
||||
$this->assertText($und_title);
|
||||
// Create string translation for neutral menu item and check it shows up
|
||||
$translation = $this->randomName(10);
|
||||
$this->createStringTranslation('menu', $und_title, array('es' => $translation));
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText($und_title);
|
||||
$this->i18nGet('es', '<front>');
|
||||
$this->assertText($translation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the translation set management works.
|
||||
*/
|
||||
function testMenuTranslationSets() {
|
||||
$menu = $this->createMenu(array('i18n_mode' => I18N_MODE_MULTIPLE));
|
||||
|
||||
$neutral_item = $this->createMenuLink(array('menu_name' => $menu['menu_name']));
|
||||
$default_item = $this->createMenuLink(array('menu_name' => $menu['menu_name'], 'language' => $this->default_language));
|
||||
$secondary_item = $this->createMenuLink(array('menu_name' => $menu['menu_name'], 'language' => $this->secondary_language));
|
||||
|
||||
$translationset_edit = array(
|
||||
'translations[' . $this->default_language . ']' => $default_item['menu_name'] . ':' . $default_item['mlid'],
|
||||
'translations[' . $this->secondary_language . ']' => $secondary_item['menu_name'] . ':' . $secondary_item['mlid'],
|
||||
);
|
||||
$translation_set = $this->createMenuLinkTranslationSet($translationset_edit);
|
||||
|
||||
// Check if the overview works
|
||||
$this->drupalGet('admin/structure/menu/manage/translation');
|
||||
$link = $this->xpath('//*/a[contains(@href,"admin/structure/menu/manage/translation/edit/' . $translation_set->tsid . '")]');
|
||||
$this->assertTrue(!empty($link), 'Created translation-set found.');
|
||||
|
||||
// Check if the edit mode works
|
||||
$this->drupalGet('admin/structure/menu/manage/translation/edit/' . $translation_set->tsid);
|
||||
$this->assertFieldByXPath(
|
||||
"//*[@id='edit-translations-" . $this->default_language . "']/option[@selected]/@value",
|
||||
$menu['menu_name'] . ':' . $default_item['mlid'],
|
||||
'Expected option selection for language ' . $this->default_language . ' found.'
|
||||
);
|
||||
$this->assertFieldByXPath(
|
||||
"//*[@id='edit-translations-" . $this->secondary_language . "']/option[@selected]/@value",
|
||||
$menu['menu_name'] . ':' . $secondary_item['mlid'],
|
||||
'Expected option selection for language ' . $this->secondary_language . ' found.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if on a switch from translatable to non translatable the translation
|
||||
* sets and links are cleaned up.
|
||||
*/
|
||||
function testMenuTranslateLocalizeSwitchToNonTranslatable() {
|
||||
// Test filtering for menu blocks.
|
||||
$menu = $this->createMenu(array('i18n_mode' => I18N_MODE_MULTIPLE));
|
||||
|
||||
// Check current menu mode
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $menu['menu_name'] . '/edit');
|
||||
$this->assertFieldByName('i18n_mode', I18N_MODE_MULTIPLE, 'Menu i18n mode set to I18N_MODE_MULTIPLE');
|
||||
|
||||
// Setup menu links for testing.
|
||||
$neutral_item = $this->createMenuLink(array('menu_name' => $menu['menu_name']));
|
||||
$default_item = $this->createMenuLink(array('menu_name' => $menu['menu_name'], 'language' => $this->default_language));
|
||||
$secondary_item = $this->createMenuLink(array('menu_name' => $menu['menu_name'], 'language' => $this->secondary_language));
|
||||
|
||||
$translationset_edit = array(
|
||||
'translations[' . $this->default_language . ']' => $default_item['menu_name'] . ':' . $default_item['mlid'],
|
||||
'translations[' . $this->secondary_language . ']' => $secondary_item['menu_name'] . ':' . $secondary_item['mlid'],
|
||||
);
|
||||
$translation_set = $this->createMenuLinkTranslationSet($translationset_edit);
|
||||
$tsid = $translation_set->tsid;
|
||||
|
||||
// Test language mode switch
|
||||
$edit = array(
|
||||
'i18n_mode' => I18N_MODE_LANGUAGE,
|
||||
'language' => $this->secondary_language,
|
||||
);
|
||||
$this->drupalPost('admin/structure/menu/manage/' . $menu['menu_name'] . '/edit', $edit, t('Save'));
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $menu['menu_name'] . '/edit');
|
||||
$this->assertFieldByName('i18n_mode', I18N_MODE_LANGUAGE, 'Menu i18n mode changed to I18N_MODE_LANGUAGE');
|
||||
|
||||
$this->assertTrue(!empty(i18n_translation_set_load($tsid)->tsid), 'Translation set kept.');
|
||||
|
||||
$menu_link_languages = db_select('menu_links')
|
||||
->fields('menu_links', array('language'))
|
||||
->condition('menu_name', $menu['menu_name'])
|
||||
->groupBy('language')
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$this->assertTrue((count($menu_link_languages) == 1 && reset($menu_link_languages) === $this->secondary_language), 'Menu link language changed to menu language.');
|
||||
|
||||
// Test cleanup.
|
||||
$edit = array(
|
||||
'i18n_mode' => I18N_MODE_NONE,
|
||||
);
|
||||
$this->drupalPost('admin/structure/menu/manage/' . $menu['menu_name'] . '/edit', $edit, t('Save'));
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $menu['menu_name'] . '/edit');
|
||||
$this->assertFieldByName('i18n_mode', I18N_MODE_NONE, 'Menu i18n mode changed to I18N_MODE_NONE');
|
||||
$translation_sets = entity_load('i18n_translation', FALSE, array('tsid' => $tsid), TRUE);
|
||||
$this->assertTrue(empty($translation_sets), 'Translation set deleted.');
|
||||
|
||||
$menu_link_languages = db_select('menu_links')
|
||||
->fields('menu_links', array('language'))
|
||||
->condition('menu_name', $menu['menu_name'])
|
||||
->groupBy('language')
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$this->assertTrue(((count($menu_link_languages) == 1) && reset($menu_link_languages) === LANGUAGE_NONE), 'Menu link language switched to LANGUAGE_NONE.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a menu.
|
||||
*/
|
||||
function createMenu($edit = array()) {
|
||||
$edit += array(
|
||||
'title' => $this->randomName(),
|
||||
'menu_name' => substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI),
|
||||
'language' => $this->secondary_language,
|
||||
);
|
||||
$this->drupalPost('admin/structure/menu/add', $edit, t('Save'));
|
||||
return menu_load('menu-' . $edit['menu_name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a menu link.
|
||||
*/
|
||||
function createMenuLink($item = array()) {
|
||||
$item += array(
|
||||
'link_title' => $this->randomName(),
|
||||
'link_path' => '<front>',
|
||||
'customized' => TRUE,
|
||||
);
|
||||
|
||||
return menu_link_load(menu_link_save($item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a translation set.
|
||||
*/
|
||||
function createMenuLinkTranslationSet($edit = array()) {
|
||||
$edit += array(
|
||||
'title' => $this->randomName(16),
|
||||
);
|
||||
$this->drupalPost('admin/structure/menu/manage/translation/add', $edit, t('Save'));
|
||||
|
||||
// Load translation set entity.
|
||||
$entity = entity_load('i18n_translation', FALSE, array('title' => $edit['title']), TRUE);
|
||||
if (empty($entity)) {
|
||||
$this->fail('Could not create a translation set.', 'i18n_translation');
|
||||
return FALSE;
|
||||
}
|
||||
return reset($entity);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user