From 15f0171de334185588d02b159dffe8f9d0b6b147 Mon Sep 17 00:00:00 2001 From: catch <catch@35733.no-reply.drupal.org> Date: Mon, 7 Jan 2013 11:36:47 +0000 Subject: [PATCH] Issue #1831530 by plach, YesCT: Entity translation UI in core (part 2). --- .../taxonomy/TermTranslationController.php | 4 +- .../EntityTranslationController.php | 2 +- .../translation_entity.install | 17 ++- .../translation_entity.module | 118 ++++++++++++------ 4 files changed, 97 insertions(+), 44 deletions(-) diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php index 2fa4227a98ff..d32df127cd08 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php @@ -33,8 +33,8 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac function entityFormSave(array $form, array &$form_state) { if ($this->getSourceLangcode($form_state)) { $entity = translation_entity_form_controller($form_state)->getEntity($form_state); - // We need a redirect here, otherwise we would get an access denied page - // since the curret URL would be preserved and we would try to add a + // We need a redirect here, otherwise we would get an access denied page, + // since the current URL would be preserved and we would try to add a // translation for a language that already has a translation. $form_state['redirect'] = $this->getEditPath($entity); } diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php index b08518a3a3da..36202ebba52b 100644 --- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php +++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php @@ -243,7 +243,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac } if ($language_widget) { - $form_langcode['#multilingual'] = TRUE; + $form['langcode']['#multilingual'] = TRUE; } $form['#process'][] = array($this, 'entityFormSharedElements'); diff --git a/core/modules/translation_entity/translation_entity.install b/core/modules/translation_entity/translation_entity.install index e7cbb656adcc..b791071c1381 100644 --- a/core/modules/translation_entity/translation_entity.install +++ b/core/modules/translation_entity/translation_entity.install @@ -56,6 +56,9 @@ function translation_entity_schema() { * Implements hook_install(). */ function translation_entity_install() { + // Assign a fairly low weight to ensure our implementation of + // hook_module_implements_alter() is run among the last ones. + module_set_weight('translation_entity', 10); language_negotiation_include(); language_negotiation_set(LANGUAGE_TYPE_CONTENT, array(LANGUAGE_NEGOTIATION_URL => 0)); } @@ -64,10 +67,14 @@ function translation_entity_install() { * Implements hook_enable(). */ function translation_entity_enable() { - $t_args = array( - '!language_url' => url('admin/config/regional/language'), - '!settings_url' => url('admin/config/regional/content-language'), - ); - $message = t('Content translation has been enabled. To use content translation, <a href="!language_url">enable at least two languages</a> and <a href="!settings_url">enable translation</a> for <em>content types</em>, <em>taxonomy vocabularies</em>, <em>accounts</em>, or any other element you wish to translate.', $t_args); + // Translation works when at least two languages are enabled. + if (count(language_list()) < 2) { + $t_args = array('!language_url' => url('admin/config/regional/language')); + $message = t('Be sure to <a href="!language_url">enable at least two languages</a> to translate content.', $t_args); + drupal_set_message($message, 'warning'); + } + // Point the user to the content translation settings. + $t_args = array('!settings_url' => url('admin/config/regional/content-language')); + $message = t('<a href="!settings_url">Enable translation</a> for <em>content types</em>, <em>taxonomy vocabularies</em>, <em>accounts</em>, or any other element you wish to translate.', $t_args); drupal_set_message($message, 'warning'); } diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module index b9a2bedd96a5..fca7c4ab56ae 100644 --- a/core/modules/translation_entity/translation_entity.module +++ b/core/modules/translation_entity/translation_entity.module @@ -44,10 +44,27 @@ function translation_entity_help($path, $arg) { } } +/** + * Implements hook_module_implements_alter(). + */ +function translation_entity_module_implements_alter(&$implementations, $hook) { + switch ($hook) { + // Move some of our hook implementations to the end of the list. + case 'menu_alter': + case 'entity_info_alter': + $group = $implementations['translation_entity']; + unset($implementations['translation_entity']); + $implementations['translation_entity'] = $group; + break; + } +} + /** * Implements hook_language_type_info_alter(). */ function translation_entity_language_types_info_alter(array &$language_types) { + // Make content language negotiation configurable by removing its predefined + // configuration. unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']); } @@ -176,30 +193,23 @@ function translation_entity_menu() { * Implements hook_menu_alter(). */ function translation_entity_menu_alter(array &$items) { - // Some menu loaders in the item paths might have been altered: we need to - // replace any menu loader with a plain % to check if base paths are still - // compatible. - $paths = array(); - $regex = '|%[^/]+|'; - foreach ($items as $path => $item) { - $path = preg_replace($regex, '%', $path); - $paths[$path] = $path; - } - // Check that the declared menu base paths are actually valid. foreach (entity_get_info() as $entity_type => $info) { if (translation_entity_enabled($entity_type)) { $path = $info['menu_base_path']; - // If the base path is not defined or is not compatible with any defined - // one we cannot provide the translation UI for this entity type. - if (!isset($paths[preg_replace($regex, '%', $path)])) { - drupal_set_message(t('The entities of type %entity_type do not define a valid base path: it will not be possible to translate them.', array('%entity_type' => $info['label'])), 'warning'); + // If the base path is not defined we cannot provide the translation UI + // for this entity type. In some cases the actual base path might not have + // a menu loader associated, hence we need to check also for the plain "%" + // variant. See for instance comment_menu(). + if (!isset($items[$path]) && !isset($items[_translation_entity_menu_strip_loaders($path)])) { unset( $items["$path/translations"], - $items["$path/translations/add/%language"], + $items["$path/translations/add/%language/%language"], $items["$path/translations/delete/%language"] ); + $t_args = array('@entity_type' => isset($info['label']) ? $info['label'] : $entity_type); + watchdog('entity translation', 'The entities of type @entity_type do not define a valid base path: it will not be possible to translate them.', $t_args, WATCHDOG_WARNING); } else { $entity_position = count(explode('/', $path)) - 1; @@ -225,6 +235,19 @@ function translation_entity_menu_alter(array &$items) { } } +/** + * Strips out menu loaders from the given path. + * + * @param string $path + * The path to process. + * + * @return + * The given path where all the menu loaders are replaced with "%". + */ +function _translation_entity_menu_strip_loaders($path) { + return preg_replace('|%[^/]+|', '%', $path); +} + /** * Access callback for the translation overview page. * @@ -279,10 +302,10 @@ function translation_entity_library_info() { } /** - * Returns the key name used to store the configuration item. + * Returns the key name used to store the configuration setting. * - * Based on the entity type and bundle, the variables used to store the - * configuration will have a common root name. + * Based on the entity type and bundle, the keys used to store configuration + * will have a common root name. * * @param string $entity_type * The type of the entity the setting refers to. @@ -292,7 +315,7 @@ function translation_entity_library_info() { * The name of the setting. * * @return string - * The key name of the configuration item. + * The key name of the configuration setting. * * @todo Generalize this logic so that it is available to any module needing * per-bundle configuration. @@ -368,6 +391,34 @@ function translation_entity_enabled($entity_type, $bundle = NULL, $skip_handler return $enabled && ($skip_handler || field_has_translation_handler($entity_type, 'translation_entity')); } +/** + * Returns all the translatable entity types. + * + * @return array + * An array of entity types keyed by entity type. + */ +function translation_entity_types_translatable() { + $entity_types = &drupal_static(__FUNCTION__, array()); + + foreach (entity_get_info() as $entity_type => $info) { + if (translation_entity_enabled($entity_type)) { + // Lazy load router items. + if (!isset($items)) { + $items = menu_get_router(); + } + // Check whether the required paths are defined. We need to strip out the + // menu loader and replace it with a plain "%" as router items have no + // menu loader in them. + $path = _translation_entity_menu_strip_loaders($info['menu_base_path']); + if (!empty($items[$path]) && !empty($items[$path . '/translations'])) { + $entity_types[$entity_type] = $entity_type; + } + } + } + + return $entity_types; +} + /** * Entity translation controller factory. * @@ -507,12 +558,8 @@ function translation_entity_entity_load(array $entities, $entity_type) { * The type of the entities. */ function translation_entity_load_translation_data(array $entities, $entity_type) { - $result = db_select('translation_entity', 'te') - ->fields('te', array()) - ->condition('te.entity_type', $entity_type) - ->condition('te.entity_id', array_keys($entities)) - ->execute(); - + $query = 'SELECT * FROM {translation_entity} te WHERE te.entity_type = :entity_type AND te.entity_id IN (:entity_id)'; + $result = db_query($query, array(':entity_type' => $entity_type, ':entity_id' => array_keys($entities))); foreach ($result as $record) { $entity = $entities[$record->entity_id]; // @todo Declare these as entity (translation?) properties. @@ -604,21 +651,18 @@ function translation_entity_form_field_ui_field_settings_form_alter(array &$form $field = $form['#field']; $field_name = $field['field_name']; $translatable = $field['translatable']; - $title = t('Users may translate this field.'); + $label = t('Field translation'); if (field_has_data($field)) { - $path = "admin/config/regional/translation_entity/translatable/$field_name"; - $status = $translatable ? $title : t('This field has data in existing content.'); - $link_title = !$translatable ? t('Enable translation') : t('Disable translation'); - $form['field']['translatable'] = array( - 'message' => array( - '#markup' => $status . ' ', - ), + '#type' => 'item', + '#title' => $label, + '#attributes' => array('class' => 'translatable'), 'link' => array( '#type' => 'link', - '#title' => $link_title, - '#href' => $path, + '#prefix' => t('This field has data in existing content.') . ' ', + '#title' => !$translatable ? t('Enable translation') : t('Disable translation'), + '#href' => 'admin/config/regional/translation_entity/translatable/' . $field_name, '#options' => array('query' => drupal_get_destination()), '#access' => user_access('administer entity translation'), ), @@ -627,10 +671,12 @@ function translation_entity_form_field_ui_field_settings_form_alter(array &$form else { $form['field']['translatable'] = array( '#type' => 'checkbox', - '#title' => $title, + '#title' => t('Users may translate this field.'), '#default_value' => $translatable, ); } + + $form['field']['translatable']['#weight'] = 20; } /** -- GitLab