i18n_translation.module 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. /**
  3. * @file
  4. * Internationalization (i18n) module - Entity translations
  5. */
  6. // Language list with only enabled languages
  7. define('I18N_ENTITY_LANGUAGES_ENABLED', 0);
  8. // Language list with all languages
  9. define('I18N_ENTITY_LANGUAGES_EXTENDED', 1);
  10. /**
  11. * Default entity controller for notifications objects
  12. */
  13. class I18nTranslationSetController extends DrupalDefaultEntityController {
  14. /**
  15. * Builds objects of specific classes upon loading.
  16. *
  17. * @param $queried_entities
  18. * Associative array of query results, keyed on the entity ID.
  19. * @param $revision_id
  20. * ID of the revision that was loaded, or FALSE if the most current revision
  21. * was loaded.
  22. */
  23. protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
  24. foreach ($queried_entities as $id => $entity) {
  25. $queried_entities[$id] = i18n_translation_set_build($entity->type, $entity);
  26. }
  27. return parent::attachLoad($queried_entities, $revision_id);
  28. }
  29. }
  30. /**
  31. * Implements hook_entity_info().
  32. */
  33. function i18n_translation_entity_info() {
  34. $bundles = array();
  35. foreach (i18n_translation_set_info() as $type => $info) {
  36. $bundles[$type] = array(
  37. 'label' => $info['title'],
  38. );
  39. }
  40. $return = array(
  41. 'i18n_translation' => array(
  42. 'label' => t('Translation set'),
  43. 'controller class' => 'I18nTranslationSetController',
  44. 'base table' => 'i18n_translation_set',
  45. //'uri callback' => 'taxonomy_term_uri',
  46. 'fieldable' => FALSE,
  47. 'entity keys' => array(
  48. 'id' => 'tsid',
  49. 'bundle' => 'type',
  50. 'label' => 'title',
  51. ),
  52. 'bundle keys' => array(
  53. 'bundle' => 'type',
  54. ),
  55. 'bundles' => $bundles,
  56. ),
  57. );
  58. return $return;
  59. }
  60. /**
  61. * Implements hook_menu()
  62. */
  63. function i18n_translation_menu() {
  64. $items['admin/config/regional/i18n_translation'] = array(
  65. 'title' => 'Translation sets',
  66. 'description' => 'Translation sets overview.',
  67. 'page callback' => 'i18n_translation_admin_overview',
  68. //'page arguments' => array('i18n_translation_set_overview'),
  69. 'access arguments' => array('administer site configuration'),
  70. 'file' => 'i18n_translation.admin.inc',
  71. 'weight' => 10,
  72. );
  73. $items['admin/config/regional/i18n_translation/configure'] = array(
  74. 'title' => 'Translation sets',
  75. 'description' => 'Overview of existing translation sets.',
  76. 'type' => MENU_DEFAULT_LOCAL_TASK,
  77. );
  78. return $items;
  79. }
  80. /**
  81. * Implements hook_hook_info().
  82. */
  83. function i18n_translation_hook_info() {
  84. $hooks['i18n_translation_set_info'] = array(
  85. 'group' => 'i18n',
  86. );
  87. return $hooks;
  88. }
  89. /**
  90. * Check whether this object can be part of a translation set
  91. */
  92. function i18n_translation_check_object($type, $object) {
  93. if ($info = i18n_translation_set_info($type)) {
  94. }
  95. }
  96. /**
  97. * Get form element for translation mode and language
  98. *
  99. * @param $object_type
  100. * Object type for the container element
  101. * @param $i18n_mode
  102. * Current or default translation mode
  103. * @param $langcode
  104. * Current or default language code
  105. * @param $options
  106. * Restricted list of translation modes if we don't want all of them
  107. */
  108. function i18n_translation_mode_element($object_type, $i18n_mode = I18N_MODE_NONE, $langcode = LANGUAGE_NONE, $options = NULL) {
  109. $form['i18n_translation'] = array(
  110. '#type' => 'fieldset',
  111. '#title' => t('Multilingual options'),
  112. '#collapsible' => TRUE,
  113. );
  114. $form['i18n_translation']['i18n_mode'] = array(
  115. '#type' => 'radios',
  116. '#title' => t('Translation mode'),
  117. '#options' => i18n_translation_options($object_type, $options),
  118. '#default_value' => $i18n_mode,
  119. '#description' => t('For localizable elements, to have all items available for translation visit the <a href="@locale-refresh">translation refresh</a> page.', array('@locale-refresh' => url('admin/config/regional/translate/i18n_string'))),
  120. );
  121. $form['i18n_translation']['language'] = array(
  122. '#default_value' => $langcode ? $langcode : LANGUAGE_NONE,
  123. '#description' => t('Predefined language. If set, it will apply to all items.'),
  124. '#required' => TRUE,
  125. '#states' => array(
  126. 'visible' => array('input[name="i18n_mode"]' => array('value' => (string)I18N_MODE_LANGUAGE)),
  127. ),
  128. ) + i18n_element_language_select();
  129. // The option value 'Language neutral' makes no sense here.
  130. $form['i18n_translation']['language']['#options'][LANGUAGE_NONE] = t('- Select a language -');
  131. return $form;
  132. }
  133. /**
  134. * Get list of translation modes
  135. *
  136. * @param $container_type
  137. * Object type for the container
  138. * @param $options
  139. * Options to include. If none, defaults for container type will be returned.
  140. */
  141. function i18n_translation_options($container_type, $options = NULL) {
  142. // Get names and translation options for container object and items
  143. $container_info = i18n_object_info($container_type, 'translation container');
  144. $replacements = array(
  145. '@container_name' => $container_info['name'],
  146. '@item_name_multiple' => $container_info['item name'],
  147. '@item_name_multiple_capitalized' => ucfirst($container_info['item name']),
  148. );
  149. $options = $options ? $options : $container_info['options'];
  150. return i18n_translation_options_list($replacements, $options);
  151. }
  152. /**
  153. * Get list of translation modes
  154. */
  155. function i18n_translation_options_list($replacements = array(), $options = array()) {
  156. $list = array(
  157. I18N_MODE_NONE => t('No multilingual options for @item_name_multiple. Only the @container_name will be translatable.', $replacements),
  158. I18N_MODE_LOCALIZE => t('Localize. @item_name_multiple_capitalized are common for all languages, but their name and description may be localized.', $replacements),
  159. I18N_MODE_TRANSLATE => t('Translate. Different @item_name_multiple will be allowed for each language and they can be translated.', $replacements),
  160. I18N_MODE_MULTIPLE => t('Translate and Localize. @item_name_multiple_capitalized with language will allow translations. @item_name_multiple_capitalized without language will be localized.', $replacements),
  161. I18N_MODE_LANGUAGE => t('Fixed Language. @item_name_multiple_capitalized will have a global language and they will only show up for pages in that language.', $replacements),
  162. );
  163. if ($options) {
  164. foreach (array_keys($list) as $key) {
  165. if (!in_array($key, $options, TRUE)) {
  166. unset($list[$key]);
  167. }
  168. }
  169. }
  170. return $list;
  171. }
  172. /**
  173. * Build translation fieldset for object
  174. */
  175. function i18n_translation_set_element($type, $object) {
  176. $element = array(
  177. '#type' => 'fieldset',
  178. '#title' => t('Translations'),
  179. );
  180. if ($set = i18n_translation_object($type, $object)) {
  181. $element['values']['#markup'] = i18n_translation_format_items($set->item_list());
  182. }
  183. else {
  184. $element['message']['#markup'] = t('No translations');
  185. }
  186. return $element;
  187. }
  188. /**
  189. * Format translation set info as table
  190. */
  191. function i18n_translation_format_items($translations) {
  192. foreach ($translations as $langcode => $item) {
  193. $rows[] = array(i18n_language_name($langcode), $item);
  194. }
  195. return !empty($rows) ? theme('table', array('rows' => $rows)) : '';
  196. }
  197. /**
  198. * Get translation set for object
  199. */
  200. function i18n_translation_object($type, $object, $create = FALSE) {
  201. if (($field = i18n_translation_set_info($type, 'field', 'i18n_tsid')) && ($tsid = i18n_object_field($object, $field))) {
  202. return i18n_translation_set_load($tsid, $type);
  203. }
  204. elseif ($create) {
  205. $set = i18n_translation_set_build($type);
  206. if ($langcode = i18n_object_langcode($object)) {
  207. $set->add_item($object, $langcode);
  208. }
  209. return $set;
  210. }
  211. }
  212. /**
  213. * Get information about translation sets
  214. */
  215. function i18n_translation_set_info($type = NULL, $property = NULL, $default = NULL) {
  216. $info = &drupal_static(__FUNCTION__);
  217. if (!$info) {
  218. $info = module_invoke_all('i18n_translation_set_info');
  219. drupal_alter('i18n_translation_set_info', $info);
  220. }
  221. if ($property && $type) {
  222. return isset($info[$type][$property]) ? $info[$type][$property] : $default;
  223. }
  224. elseif ($type) {
  225. return isset($info[$type]) ? $info[$type] : $default;
  226. }
  227. else {
  228. return $info;
  229. }
  230. }
  231. /**
  232. * Build a translation set from type, data
  233. */
  234. function i18n_translation_set_build($type, $data = array()) {
  235. $class = i18n_translation_set_info($type, 'class', 'i18n_translation_set');
  236. $set = new $class((array)$data);
  237. $set->type = $type;
  238. return $set;
  239. }
  240. /**
  241. * Create a new translation set
  242. */
  243. function i18n_translation_set_create($type, $bundle = '', $translations = NULL, $master_id = 0) {
  244. $set = i18n_translation_set_build($type, array('type' => $type, 'bundle' => $bundle, 'master_id' => $master_id, 'translations' => $translations));
  245. $set->insert();
  246. return $set;
  247. }
  248. /**
  249. * Load single translation set.
  250. *
  251. * @param int $tsid
  252. * Translation set id.
  253. * @param string $type
  254. * (Optional) translation set type (bundle).
  255. */
  256. function i18n_translation_set_load($tsid, $type = NULL) {
  257. $conditions['tsid'] = $tsid;
  258. $list = entity_load('i18n_translation', array($tsid));
  259. $entity = reset($list);
  260. if ($entity && $type && $entity->type != $type) {
  261. return NULL;
  262. }
  263. return $entity;
  264. }
  265. /**
  266. * Index objects in translation set by language
  267. */
  268. function i18n_translation_set_index($translations) {
  269. $list = array();
  270. foreach ($translations as $object) {
  271. if ($lang = i18n_object_langcode($object)) {
  272. $list[$lang] = $object;
  273. }
  274. }
  275. return $list;
  276. }
  277. /**
  278. * Translation set generic form
  279. */
  280. function i18n_translation_set_overview($form, &$form_state, $type = NULL, $tsids = NULL) {
  281. module_load_include('admin.inc', 'i18n_translation');
  282. return i18n_translation_admin_form($form, $form_state, $type, $tsids);
  283. }
  284. /**
  285. * Generate a tabular listing of translations for this type.
  286. */
  287. function i18n_translation_set_list_manage($type) {
  288. module_load_include('admin.inc', 'i18n_translation');
  289. return i18n_translation_admin_overview($type);
  290. }
  291. /**
  292. * Ask for confirmation of translation set deletion
  293. */
  294. function i18n_translation_set_delete_confirm($form, &$form_state, $translation_set) {
  295. $form['#translation_set'] = $translation_set;
  296. $form['tsid'] = array(
  297. '#type' => 'value',
  298. '#value' => $translation_set->tsid,
  299. );
  300. if ($items = $translation_set->item_list()) {
  301. $form['items'] = array(
  302. '#type' => 'item',
  303. '#title' => t('Items in this translation set'),
  304. '#markup' => theme('item_list', array('items' => $items)),
  305. );
  306. }
  307. return confirm_form($form,
  308. t('Are you sure you want to delete %title translation set?', array('%title' => $translation_set->get_title())),
  309. i18n_translation_set_info($translation_set->type, 'list path'),
  310. t('This action cannot be undone.'),
  311. t('Delete'),
  312. t('Cancel')
  313. );
  314. }
  315. /**
  316. * Execute translation set deletion
  317. */
  318. function i18n_translation_set_delete_confirm_submit($form, &$form_state) {
  319. if ($form_state['values']['confirm']) {
  320. $set = i18n_translation_set_load($form_state['values']['tsid']);
  321. $set->delete(TRUE);
  322. drupal_set_message(t('The translation set has been deleted.'));
  323. }
  324. $form_state['redirect'] = i18n_translation_set_info($set->type, 'list path');
  325. }