i18n_menu.admin.inc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. /**
  3. * @file
  4. * Helper functions for menu administration.
  5. */
  6. /**
  7. * Produces a menu translation form.
  8. */
  9. function i18n_menu_translation_form($form, $form_state, $translation_set = NULL, $item = NULL) {
  10. $translation_set = $translation_set ? $translation_set : i18n_translation_set_build('menu_link');
  11. $form['translation_set'] = array('#type' => 'value', '#value' => $translation_set);
  12. $translations = $translation_set->get_translations();
  13. // What to do with title? Let's make it a hidden field for now, some tests relay on it
  14. $form['title'] = array('#type' => 'hidden', '#default_value' => $translation_set->title);
  15. if ($item && ($lang = i18n_object_langcode($item))) {
  16. $translations[$lang] = $item;
  17. }
  18. $item = $item ? $item : array('mlid' => 0, 'menu_name' => '', 'plid' => 0);
  19. $item_lang = i18n_object_langcode($item);
  20. $form['translations'] = array(
  21. '#type' => 'fieldset',
  22. '#title' => t('Translations'),
  23. '#tree' => TRUE,
  24. '#description' => t('Enter items that will be considered as translations of each other.'),
  25. );
  26. foreach (i18n_language_list() as $langcode => $language_name) {
  27. if ($langcode == $item_lang) {
  28. // We've got a predefined item for this language
  29. $form['translations'][$langcode] = array('#type' => 'value', '#value' => $item['menu_name'] . ':' . $item['mlid']);
  30. $form['translations']['display'] = array(
  31. '#type' => 'item',
  32. '#title' => $language_name,
  33. '#markup' => check_plain($item['link_title']),
  34. );
  35. }
  36. else {
  37. // Generate a list of possible parents (not including this link or descendants).
  38. $options = i18n_menu_parent_options(menu_get_menus(), $item, $langcode);
  39. $default = isset($translations[$langcode]) ? $translations[$langcode]['menu_name'] . ':' . $translations[$langcode]['mlid'] : 'navigation:0';
  40. if (!isset($options[$default])) {
  41. $default = 'navigation:0';
  42. }
  43. $form['translations'][$langcode] = array(
  44. '#type' => 'select',
  45. '#title' => $language_name,
  46. '#default_value' => $default,
  47. '#options' => $options,
  48. '#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)),
  49. '#attributes' => array('class' => array('menu-title-select')),
  50. );
  51. }
  52. }
  53. $form['actions'] = array('#type' => 'actions');
  54. $form['actions']['update'] = array('#type' => 'submit', '#value' => t('Save'));
  55. if (!empty($translation_set->tsid)) {
  56. $form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
  57. }
  58. return $form;
  59. }
  60. /**
  61. * Process form validation
  62. */
  63. function i18n_menu_translation_form_validate($form, &$form_state) {
  64. if ($form_state['values']['op'] == t('Save')) {
  65. $selected = 0;
  66. // example array('en' => 'navigation:0')
  67. $mlids = array_filter($form_state['values']['translations']);
  68. foreach ($mlids as $lang => $item_name) {
  69. list($menu_name, $mlid) = explode(':', $item_name);
  70. if ($mlid && ($item = menu_link_load($mlid)) && i18n_object_langcode($item)) {
  71. $selected++;
  72. }
  73. else {
  74. unset($form_state['values']['translations'][$lang]);
  75. }
  76. }
  77. if ($selected < 1) {
  78. form_set_error('translations', t('There are no translations to save.'));
  79. }
  80. }
  81. }
  82. /**
  83. * Menu item translation form submission
  84. */
  85. function i18n_menu_translation_form_submit($form, &$form_state) {
  86. $translation_set = $form_state['values']['translation_set'];
  87. switch ($form_state['values']['op']) {
  88. case t('Save'):
  89. $mlids = array_filter($form_state['values']['translations']);
  90. $translation_set->reset_translations();
  91. foreach ($mlids as $lang => $item_name) {
  92. list($menu_name, $mlid) = explode(':', $item_name);
  93. $item = menu_link_load($mlid);
  94. $translation_set->add_item($item, $lang);
  95. }
  96. $translation_set->title = !empty($form_state['values']['title']) ? $form_state['values']['title'] : '';
  97. $translation_set->save(TRUE);
  98. drupal_set_message(t('The item translation has been saved.'));
  99. break;
  100. case t('Delete'):
  101. $translation_set->delete(TRUE);
  102. drupal_set_message(t('The item translation has been deleted.'));
  103. break;
  104. }
  105. $form_state['redirect'] = 'admin/structure/menu';
  106. }
  107. /**
  108. * Return a list of menu items that are valid possible parents for the given menu item.
  109. *
  110. * @param $menus
  111. * An array of menu names and titles, such as from menu_get_menus().
  112. * @param $item
  113. * The menu item or the node type for which to generate a list of parents.
  114. * If $item['mlid'] == 0 then the complete tree is returned.
  115. * @return
  116. * An array of menu link titles keyed on the a string containing the menu name
  117. * and mlid. The list excludes the given item and its children.
  118. *
  119. * @todo This has to be turned into a #process form element callback. The
  120. * 'menu_override_parent_selector' variable is entirely superfluous.
  121. */
  122. function i18n_menu_parent_options($menus, $item, $langcode) {
  123. // The menu_links table can be practically any size and we need a way to
  124. // allow contrib modules to provide more scalable pattern choosers.
  125. // hook_form_alter is too late in itself because all the possible parents are
  126. // retrieved here, unless menu_override_parent_selector is set to TRUE.
  127. if (variable_get('i18n_menu_override_parent_selector', FALSE)) {
  128. return array();
  129. }
  130. // If no menu item, create a dummy one
  131. $item = $item ? $item : array('mlid' => 0);
  132. // Get menus that have a language or have language for terms
  133. $available_menus = array();
  134. foreach (menu_load_all() as $name => $menu) {
  135. if ($menu['i18n_mode'] & I18N_MODE_TRANSLATE) {
  136. $available_menus[$name] = $menu;
  137. }
  138. elseif ($menu['i18n_mode'] & I18N_MODE_LANGUAGE && $menu['language'] == $langcode) {
  139. $available_menus[$name] = $menu;
  140. }
  141. }
  142. // Disable i18n selection, enable after the query.
  143. $previous = i18n_select(FALSE);
  144. $options = _i18n_menu_get_options($menus, $available_menus, $item, $langcode);
  145. i18n_select($previous);
  146. return $options;
  147. }
  148. /**
  149. * Helper function to get the items of the given menu.
  150. */
  151. function _i18n_menu_get_options($menus, $available_menus, $item, $langcode) {
  152. // If the item has children, there is an added limit to the depth of valid parents.
  153. if (isset($item['parent_depth_limit'])) {
  154. $limit = $item['parent_depth_limit'];
  155. }
  156. else {
  157. $limit = _menu_parent_depth_limit($item);
  158. }
  159. $options = array();
  160. foreach ($menus as $menu_name => $title) {
  161. if (isset($available_menus[$menu_name])) {
  162. if ($tree = i18n_menu_tree_all_data($menu_name, $langcode, NULL)) {
  163. $options[$menu_name . ':0'] = '<' . $title . '>';
  164. _menu_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit);
  165. }
  166. }
  167. }
  168. return $options;
  169. }
  170. /**
  171. * Filter out menu items that have a different language
  172. */
  173. function i18n_menu_tree_all_data($menu_name, $langcode, $link = NULL, $max_depth = NULL) {
  174. $tree = menu_tree_all_data($menu_name, $link, $max_depth);
  175. return _i18n_menu_tree_filter_items($tree, $langcode);
  176. }
  177. /**
  178. * Filter out menu items that have a different language
  179. */
  180. function _i18n_menu_tree_filter_items($tree, $langcode) {
  181. $result = array();
  182. foreach ($tree as $key => $item) {
  183. $lang = i18n_object_langcode($item['link']);
  184. if (!empty($item['below'])) {
  185. $item['below'] = _i18n_menu_tree_filter_items($item['below'], $langcode);
  186. }
  187. if (!empty($item['link']['customized']) && $lang == $langcode) {
  188. $result[$key] = $item;
  189. }
  190. elseif (!empty($item['below'])) {
  191. // Keep for the tree but mark as unselectable.
  192. $item['link']['title'] = '(' . $item['link']['title'] . ')';
  193. $result[$key] = $item;
  194. }
  195. }
  196. return $result;
  197. }
  198. /**
  199. * Callback for menu translation tab.
  200. */
  201. function i18n_menu_translation_item_overview($item, $translation_set = NULL) {
  202. if ($item['i18n_tsid']) {
  203. // Already part of a set, grab that set.
  204. $translation_set = i18n_translation_set_load($item['i18n_tsid']);
  205. $translations = $translation_set->get_translations();
  206. }
  207. else {
  208. // We have no translation source mlid, this could be a new set, emulate that.
  209. $translations = array($item['language'] => $item);
  210. }
  211. $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
  212. $header = array(t('Language'), t('Title'), t('Operations'));
  213. $rows = array();
  214. foreach (i18n_language_list() as $langcode => $language_name) {
  215. $options = array();
  216. if (isset($translations[$langcode])) {
  217. // Existing translation in the translation set: display status.
  218. $translation_item = menu_link_load($translations[$langcode]['mlid']);
  219. $title = l($translation_item['link_title'], $translation_item['link_path']);
  220. $path = 'admin/structure/menu/item/' . $translation_item['mlid'];
  221. $options[] = l(t('edit'), $path);
  222. if ($translation_item['mlid'] == $item['mlid']) {
  223. $language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
  224. }
  225. }
  226. else {
  227. // No such translation in the set yet: help user to create it.
  228. $title = t('n/a');
  229. $options[] = l(t('add translation'), 'admin/structure/menu/manage/' . $item['menu_name'] . '/add', array('query' => array('translation' => $item['mlid'], 'target' => $langcode) + drupal_get_destination()));
  230. }
  231. $rows[$langcode] = array(
  232. 'language' => $language_name,
  233. 'title' => $title,
  234. 'operations' => implode(" | ", $options)
  235. );
  236. }
  237. drupal_set_title(t('Translations of menu item %title', array('%title' => $item['link_title'])), PASS_THROUGH);
  238. $build['translation_overview'] = array(
  239. '#theme' => 'table',
  240. '#header' => $header,
  241. '#rows' => $rows,
  242. );
  243. return $build;
  244. }