updated admin_menu, entity_translation, addressfield, addressfield_token, autocomplete_deluxe

This commit is contained in:
2019-05-13 17:41:56 +02:00
parent 472762edfa
commit 33210e10f2
65 changed files with 3124 additions and 700 deletions

View File

@@ -1,9 +1,83 @@
Entity Translation 7.x-1.x, xxxx-xx-xx
--------------------------------------
#2189567 by stefanos.petrakis, jmuzz: Fixed problems enabling and disabling translation on
a field with revisions enabled.
#2798721 by gnucifer: Path scheme not initialized on delete translation confirmation form.
#3025770 by sudheeshps, patelmayank7552, stefanos.petrakis: PHP 7.0
Compatibility
#2536292 by plopesc, stefanos.petrakis: "Warning: array_merge(): Argument #2 is
not an array in entity_translation_menu_alter" When 'page arguments' or
'access arguments' are not defined in the original item
#2921298 by Stevel, stefanos.petrakis: Missing test dependencies
Entity Translation 7.x-1.0, 2018-04-01
--------------------------------------
(no change)
Entity Translation 7.x-1.0-rc1, 2018-03-21
------------------------------------------
#2927815 by Skabbkladden, dawehner: Infinite loop with language neutral alias
and pathauto.
#2890683 by tobiberlin, stefanos.petrakis: entity_translation_field_attach_form()
adding unwanted fields to form.
#2907366 by swati.nuna: Invalid hook hook_translation_info() mentioned in
docblock for entity_translation_edit_form_info().
#1799770 by plach, bforchhammer: Update id and bundle when setting a wrapped
entity.
#2339315 by plach: Added documentation for
hook_entity_translation_source_field_state_alter().
#1506054 by plach, Owen Barton: Taxonomy term reference: language-aware widget
and autocomplete.
#2907275 by jalpesh: CSS class name misspelled in entity_translation_overview().
Entity Translation 7.x-1.0-beta7, 2017-08-21
--------------------------------------------
#2903195 by stefanos.petrakis, BAHbKA, plach: Enabling translation for not
empty taxonomy vocabulary.
#2425825 by jamesrward: Update from before beta4 fails.
#2900094 by joseph.olstad: code sniffer drupal.org recommended code syntax
fixes.
#2883805 by mikran: entity_translation_update_7008 is broken when taxonomy
module is not enabled.
#2877074 by plach, stefanos.petrakis, joseph.olstad: Refactor the
entity_translation_language() callback to make it bundle-specific.
#2743685 by stefanos.petrakis, bwaindwain: Pathauto update for all translations
for a single node.
#2899658 by joseph.olstad, stefanos.petrakis: entity_translation_upgrade_do
needs to automatically create the entity_translation row for the source
language in entity_translation.
#1800158 by meichr: Entity Translation Upgrade, drush extension.
#2885858 by StephaneQ: Can't delete taxonomy term translation since beta6
update.
#2572203 by mattew: Wrong query generated when several Translations
relationships are used.
#2824255 by ccarrascal, plach: Notice: Undefined index for language in
setTranslation().
#2750179 by wadmiraal: Allowed default translation handler to be completely
overridden.
#2307937 by meichr, joseph.olstad: Batch API needs $context['results'] handled
as an array, not a value.
#1175170 by hgoto, Pisco, alberto56: Optionally enable disabled languages for
entity translation.
#2870524 by stefanos.petrakis, joseph.olstad: Field copy fails with content
translation for fields with entity translation enabled.
Entity Translation 7.x-1.0-beta6, 2017-03-03
--------------------------------------------
#2849464 by plach, czigor, stefanos.petrakis: Added an API to set the active
language.
#2438615 by David_Rothstein, matthiasm11: New nodes are always created using
LANGUAGE_NONE (only changed to the correct language during form submission).
#2820454 by Dylan Donkersgoed: PHP notice when attaching single field
with field_attach_form.
#2826297 by Thomas Cys, dwebpoint, stefanos.petrakis: 'clone' is a reserved
keyword introduced in PHP version 5.0 and cannot be invoked as a function.
#2189567 by stefanos.petrakis, jmuzz: Fixed problems enabling and disabling
translation on a field with revisions enabled.
#2798721 by gnucifer: Path scheme not initialized on delete translation
confirmation form.
#2215771 by colan, stefanos.petrakis: Fixed "Undefined index: translate in
EntityTranslationDefaultHandler->entityForm()".
#1829636 by bforchhammer, stefanos.petrakis: Fixed "All languages" suffix not

View File

@@ -9,8 +9,9 @@ Project maintainers
The Entity translation maintainers oversee the development of the project as a
whole. The project maintainers for Entity translation are:
- Francesco Placella 'plach' <http://drupal.org/user/183211>
- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
- Francesco Placella 'plach' <https://www.drupal.org/u/plach>
- Daniel F. Kudwien 'sun' <https://www.drupal.org/u/sun>
- Stefanos Petrakis 'stefanos.petrakis' <https://www.drupal.org/u/stefanospetrakis>
Component maintainers
@@ -25,14 +26,15 @@ http://drupal.org/node/363367 to find out how to become a component maintainer.
Current component maintainers for Entity translation:
Base system
- Francesco Placella 'plach' <http://drupal.org/user/183211>
- Benedikt Forchhammer 'bforchhammer' <http://drupal.org/user/216396>
- Francesco Placella 'plach' <https://www.drupal.org/u/plach>
- Benedikt Forchhammer 'bforchhammer' <https://www.drupal.org/u/bforchhammer>
- Stefanos Petrakis 'stefanos.petrakis' <https://www.drupal.org/u/stefanospetrakis>
Menu integration
- Benedikt Forchhammer 'bforchhammer' <http://drupal.org/user/216396>
- Benedikt Forchhammer 'bforchhammer' <https://www.drupal.org/u/bforchhammer>
Views integration
- Fabian Sörqvist 'fabsor' <http://drupal.org/user/255704>
- Fabian Sörqvist 'fabsor' <https://www.drupal.org/u/fabsor>
Node translation upgrade
- Francesco Placella 'plach' <http://drupal.org/user/183211>
- Francesco Placella 'plach' <https://www.drupal.org/u/plach>

View File

@@ -18,6 +18,13 @@ function entity_translation_admin_form($form, $form_state) {
'#default_value' => variable_get('locale_field_language_fallback', TRUE),
);
$form['entity_translation_languages_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Use only enabled languages'),
'#description' => t('If checked, disabled languages will not show up as available languages. This setting does not apply to content types that are configured to use the Multilingual content (i18n_node) module as this module provides its own configuration.'),
'#default_value' => variable_get('entity_translation_languages_enabled', FALSE),
);
$form['entity_translation_show_fallback_on_overview_pages'] = array(
'#type' => 'checkbox',
'#title' => t('Show fallback statuses on overview pages'),
@@ -45,7 +52,7 @@ function entity_translation_admin_form($form, $form_state) {
);
$_null = NULL;
list($items, ) = menu_router_build();
list($items,) = menu_router_build();
_entity_translation_validate_path_schemes($_null, FALSE, $items);
foreach (entity_get_info() as $entity_type => $info) {
@@ -316,7 +323,7 @@ function entity_translation_overview($entity_type, $entity, $callback = NULL) {
$link = isset($add_links->links[$langcode]['href']) ? $add_links->links[$langcode] : array('href' => $add_path, 'language' => $language);
$link['query'] = isset($_GET['destination']) ? drupal_get_destination() : FALSE;
$options[] = $translatable ? l(t('add'), $link['href'], $link) : t('No translatable fields');
$classes[] = $translatable ? '' : 'non-traslatable';
$classes[] = $translatable ? '' : 'non-translatable';
}
$status = t('Not translated');
// Show fallback information if required.
@@ -389,7 +396,7 @@ function _entity_translation_label($entity_type, $entity, $langcode = NULL) {
/**
* Theme wrapper for the entity translation language page.
*/
function theme_entity_translation_overview($variables){
function theme_entity_translation_overview($variables) {
$rows = $variables['rows'];
return theme('table', array(
'rows' => $rows,
@@ -400,7 +407,7 @@ function theme_entity_translation_overview($variables){
/**
* Theme wrapper for the entity translation language outdated translation.
*/
function theme_entity_translation_overview_outdated($variables){
function theme_entity_translation_overview_outdated($variables) {
$message = $variables['message'];
return ' - <span class="marker">' . $message . '</span>';
}
@@ -410,7 +417,7 @@ function theme_entity_translation_overview_outdated($variables){
*/
function entity_translation_delete_confirm($form, $form_state, $entity_type, $entity, $langcode) {
$handler = entity_translation_get_handler($entity_type, $entity);
$handler->setFormLanguage($langcode);
$handler->setActiveLanguage($langcode);
$handler->initPathScheme();
$languages = language_list();
@@ -452,7 +459,7 @@ function entity_translation_delete_confirm_submit($form, &$form_state) {
$form_state['redirect'] = $handler->getTranslatePath();
}
/*
/**
* Confirm form for changing field translatability.
*/
function entity_translation_translatable_form($form, &$form_state, $field_name) {
@@ -547,7 +554,7 @@ function entity_translation_translatable_form_submit($form, $form_state) {
batch_set($batch);
}
/*
/**
* Toggle translatability of the given field.
*
* This is called from a batch operation, but should only run once per field.
@@ -602,12 +609,28 @@ function entity_translation_translatable_batch($translatable, $field_name, $copy
->range($offset, $limit)
->execute();
foreach ($result as $entity_type => $revisions) {
foreach ($revisions as $revision) {
// $revision is a partial entity object that will be used as an array of
// conditions.
$conditions = (array) $revision;
$entity = reset(entity_load($entity_type, FALSE, $conditions));
foreach ($result as $entity_type => $partial_entities) {
// Load all revisionable entities' revisions.
if (EntityTranslationDefaultHandler::isEntityTypeRevisionable($entity_type)) {
$entities = array();
// Extract the revision identifier from the entity's definition.
$entity_info = entity_get_info($entity_type);
$revision_id_key = $entity_info['entity keys']['revision'];
// Load each revisionable entity's revision using $conditions, which
// should include the revision id information.
foreach ($partial_entities as $partial_entity) {
$conditions = (array) $partial_entity;
$revision_condition = array_intersect_key($conditions, array($revision_id_key => $revision_id_key));
$entity_revisions = entity_load($entity_type, FALSE, $revision_condition);
$entities[] = reset($entity_revisions);
}
}
else {
$entities = entity_load($entity_type, array_keys($partial_entities));
}
foreach ($entities as $entity) {
$context['sandbox']['progress']++;
$handler = entity_translation_get_handler($entity_type, $entity);
$langcode = $handler->getLanguage();
@@ -626,9 +649,10 @@ function entity_translation_translatable_batch($translatable, $field_name, $copy
if ($translatable && isset($entity->{$field_name}[LANGUAGE_NONE])) {
// If the field is being switched to translatable and has data for
// LANGUAGE_NONE then we need to move the data to the right language.
// In case the 'Copy translations' option was selected, move the
// available LANGUAGE_NONE field data into all existing translation
// languages, otherwise only into the entity's language.
$translations = $handler->getTranslations();
if ($copy_all_languages && !empty($translations->data)) {
foreach ($translations->data as $translation) {
$entity->{$field_name}[$translation['language']] = $entity->{$field_name}[LANGUAGE_NONE];

View File

@@ -164,3 +164,17 @@ function hook_entity_translation_delete($entity_type, $entity, $langcode) {
*/
function hook_entity_translation_delete_revision($entity_type, $entity, $langcode) {
}
/**
* Allows to sets the right values in the form state when adding a translation.
*/
function hook_entity_translation_source_field_state_alter(&$field_state) {
if (isset($field_state['entity'])) {
module_load_include('inc', 'entity', 'includes/entity.ui');
foreach ($field_state['entity'] as $delta => $entity) {
if ($entity instanceof FieldCollectionItemEntity) {
$field_state['entity'][$delta] = entity_ui_clone_entity('field_collection_item', $entity);
}
}
}
}

View File

@@ -5,6 +5,9 @@ core = 7.x
configure = admin/config/regional/entity_translation
dependencies[] = locale (>7.14)
test_dependencies[] = pathauto:pathauto
test_dependencies[] = title:title
files[] = includes/translation.handler_factory.inc
files[] = includes/translation.handler.inc
files[] = includes/translation.handler.comment.inc
@@ -23,9 +26,8 @@ files[] = views/entity_translation_handler_filter_language.inc
files[] = views/entity_translation_handler_filter_translation_exists.inc
files[] = views/entity_translation_handler_field_field.inc
; Information added by Drupal.org packaging script on 2016-09-28
version = "7.x-1.0-beta5+15-dev"
; Information added by Drupal.org packaging script on 2019-01-20
version = "7.x-1.0+5-dev"
core = "7.x"
project = "entity_translation"
datestamp = "1475057941"
datestamp = "1548022384"

View File

@@ -175,6 +175,9 @@ function entity_translation_install() {
// Enable revision support for entity translation.
variable_set('entity_translation_revision_enabled', TRUE);
// Enable taxonomy autocomplete support.
variable_set('entity_translation_taxonomy_autocomplete', TRUE);
}
/**
@@ -356,7 +359,11 @@ function entity_translation_update_7006() {
'not null' => FALSE,
'description' => 'The entity revision id this translation relates to',
);
db_add_field('entity_translation', 'revision_id', $spec);
// Create revision id column if it doesn't exist already.
if (!db_field_exists('entity_translation', 'revision_id')) {
db_add_field('entity_translation', 'revision_id', $spec);
}
// Create the entity translation revision schema.
$table = array(
@@ -429,7 +436,11 @@ function entity_translation_update_7006() {
'primary key' => array('entity_type', 'revision_id', 'language'),
'indexes'=> array('revision_id' => array('revision_id')),
);
db_create_table('entity_translation_revision', $table);
// Create entity translation revision table if it doesn't exist already.
if (!db_table_exists('entity_translation_revision')) {
db_create_table('entity_translation_revision', $table);
}
}
/**
@@ -452,6 +463,9 @@ function entity_translation_update_7007() {
* through it.
*/
function entity_translation_update_7008() {
if (!module_exists('taxonomy')) {
return;
}
// According to EXPLAIN joining {taxonomy_vocabulary} here makes the query
// perform way worse, so we just split into two quick ones.
$query = "SELECT t.vid

View File

@@ -244,6 +244,13 @@ function entity_translation_menu() {
'file' => 'entity_translation.admin.inc',
);
$items['entity_translation/taxonomy_term/autocomplete'] = array(
'title' => 'Entity translation autocomplete',
'page callback' => 'entity_translation_taxonomy_term_autocomplete',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
return $items;
}
@@ -457,7 +464,11 @@ function entity_translation_menu_alter(&$items) {
// Replace the main edit callback with our proxy implementation to set
// form language to the current language and check access.
$entity_position = array_search($scheme['path wildcard'], $edit_path_parts);
$original_item = $edit_item;
// Make sure incoming page and access arguments are arrays.
$original_item = $edit_item + array(
'page arguments' => array(),
'access arguments' => array(),
);
$args = array($entity_type, $entity_position, FALSE, $original_item);
$edit_item['page callback'] = 'entity_translation_edit_page';
$edit_item['page arguments'] = array_merge($args, $original_item['page arguments']);
@@ -550,7 +561,7 @@ function entity_translation_edit_page() {
$handler = entity_translation_get_handler($entity_type, $entity);
$handler->initPathScheme();
$langcode = entity_translation_get_existing_language($entity_type, $entity, $langcode);
$handler->setFormLanguage($langcode);
$handler->setActiveLanguage($langcode);
// Display the entity edit form.
return _entity_translation_callback($edit_form_item['page callback'], $args, $edit_form_item);
@@ -693,7 +704,7 @@ function entity_translation_add_page() {
$handler = entity_translation_get_handler($entity_type, $entity);
$handler->initPathScheme();
$handler->setFormLanguage($langcode);
$handler->setActiveLanguage($langcode);
$handler->setSourceLanguage($source);
// Display the entity edit form.
@@ -918,7 +929,7 @@ function entity_translation_field_language_alter(&$display_language, $context) {
if (isset($translations->data[$context['language']]) && !entity_translation_access($entity_type, $translations->data[$context['language']])) {
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
$instances = field_info_instances($entity_type, $bundle);
$entity = clone($entity);
$entity = clone $entity;
foreach ($translations->data as $langcode => $translation) {
if ($langcode == $context['language'] || !entity_translation_access($entity_type, $translations->data[$langcode])) {
@@ -1194,7 +1205,7 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
if (empty($form['#entity_translation_source_form']) && entity_translation_enabled($entity_type, $bundle)) {
$handler = entity_translation_get_handler($entity_type, $entity);
$langcode = !empty($langcode) ? $langcode : $handler->getLanguage();
$form_langcode = $handler->getFormLanguage();
$form_langcode = $handler->getActiveLanguage();
$translations = $handler->getTranslations();
$update_langcode = $form_langcode && ($form_langcode != $langcode);
$source = $handler->getSourceLanguage();
@@ -1217,7 +1228,7 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
// language information from source to target language, this way the
// user can find the form items already populated with the source values
// while the field form element holds the correct language information.
if ($field['translatable']) {
if ($field['translatable'] && isset($form[$field_name])) {
$element = &$form[$field_name];
$element['#entity_type'] = $entity_type;
$element['#entity'] = $entity;
@@ -1253,11 +1264,14 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
foreach (field_info_instances($entity_type, $bundle) as $instance) {
$field_name = $instance['field_name'];
$field = field_info_field($field_name);
// If access is not set or is granted we check whether the user has
// access to shared fields.
$form[$field_name]['#access'] = (!isset($form[$field_name]['#access']) || $form[$field_name]['#access']) && ($field['translatable'] || $shared_access);
$form[$field_name]['#multilingual'] = (boolean) $field['translatable'];
// Check if a field is part of the form array.
if (isset($form[$field_name])) {
$field = field_info_field($field_name);
// If access is not set or is granted we check whether the user has
// access to shared fields.
$form[$field_name]['#access'] = (!isset($form[$field_name]['#access']) || $form[$field_name]['#access']) && ($field['translatable'] || $shared_access);
$form[$field_name]['#multilingual'] = (boolean) $field['translatable'];
}
}
}
@@ -1491,7 +1505,7 @@ function entity_translation_form_alter(&$form, &$form_state) {
if (!$handler->isNewEntity()) {
$handler->entityForm($form, $form_state);
$translations = $handler->getTranslations();
$form_langcode = $handler->getFormLanguage();
$form_langcode = $handler->getActiveLanguage();
if (!isset($translations->data[$form_langcode]) || count($translations->data) > 1) {
// Hide shared form elements if the user is not allowed to edit them.
$handler->entityFormSharedElements($form);
@@ -1520,7 +1534,7 @@ function entity_translation_form_alter(&$form, &$form_state) {
function entity_translation_entity_form_source_language_submit($form, &$form_state) {
$handler = entity_translation_entity_form_get_handler($form, $form_state);
$langcode = $form_state['values']['source_language']['language'];
$path = "{$handler->getEditPath()}/add/$langcode/{$handler->getFormLanguage()}";
$path = "{$handler->getEditPath()}/add/$langcode/{$handler->getActiveLanguage()}";
$options = array();
if (isset($_GET['destination'])) {
$options['query'] = drupal_get_destination();
@@ -1536,7 +1550,7 @@ function entity_translation_entity_form_source_language_submit($form, &$form_sta
*/
function entity_translation_entity_form_delete_translation_submit($form, &$form_state) {
$handler = entity_translation_entity_form_get_handler($form, $form_state);
$path = "{$handler->getTranslatePath()}/delete/{$handler->getFormLanguage()}";
$path = "{$handler->getTranslatePath()}/delete/{$handler->getActiveLanguage()}";
$options = array();
if (isset($_GET['destination'])) {
$options['query'] = drupal_get_destination();
@@ -1564,7 +1578,7 @@ function entity_translation_entity_form_language_update($element, &$form_state,
// needed when responding to an AJAX request where the languages cannot be set
// from the usual page callback.
if (!empty($form_state['entity_translation']['form_langcode'])) {
$handler->setFormLanguage($form_state['entity_translation']['form_langcode']);
$handler->setActiveLanguage($form_state['entity_translation']['form_langcode']);
}
// When responding to an AJAX request we should ignore any change in the
// language widget as it may alter the field language expected by the AJAX
@@ -1597,6 +1611,9 @@ function entity_translation_field_attach_submit($entity_type, $entity, $form, &$
// Update the wrapped entity with the submitted values.
$handler->setEntity($entity);
$handler->entityFormSubmit($form, $form_state);
// Process in-place translations for the taxonomy autocomplete widget.
entity_translation_taxonomy_term_field_attach_submit($entity_type, $entity, $form, $form_state);
}
}
@@ -1671,7 +1688,7 @@ function theme_entity_translation_language_tabs($variables) {
* Adds an option to enable field synchronization.
* Enable a selector to choose whether a field is translatable.
*/
function entity_translation_form_field_ui_field_edit_form_alter(&$form, $form_state) {
function entity_translation_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
$instance = $form['#instance'];
$entity_type = $instance['entity_type'];
$field_name = $instance['field_name'];
@@ -1691,7 +1708,8 @@ function entity_translation_form_field_ui_field_edit_form_alter(&$form, $form_st
$label = t('Field translation');
$title = t('Users may translate all occurrences of this field:') . _entity_translation_field_desc($field);
if (field_has_data($field)) {
$form_state['field_has_data'] = field_has_data($field);
if ($form_state['field_has_data']) {
$path = "admin/config/regional/entity_translation/translatable/$field_name";
$status = $translatable ? $title : (t('All occurrences of this field are untranslatable:') . _entity_translation_field_desc($field));
$link_title = !$translatable ? t('Enable translation') : t('Disable translation');
@@ -1719,6 +1737,11 @@ function entity_translation_form_field_ui_field_edit_form_alter(&$form, $form_st
'#default_value' => $translatable,
);
}
$function = 'entity_translation_form_field_ui_field_edit_' . $instance['widget']['type'] . '_form_alter';
if (function_exists($function)) {
$function($form, $form_state);
}
}
/**
@@ -1821,32 +1844,37 @@ function entity_translation_settings($entity_type, $bundle) {
* Entity language callback.
*
* This callback changes the entity language from the actual one to the active
* form language. This overriding allows to obtain language dependent form
* widgets where multilingual values are supported (e.g. field or path alias
* widgets) even if the code was not originally written with supporting multiple
* values per language in mind.
* language. This overriding allows to obtain language dependent form widgets
* where multilingual values are supported (e.g. field or path alias widgets)
* even if the code was not originally written with supporting multiple values
* per language in mind.
*
* The main drawback of this approach is that code needing to access the actual
* language in the entity form build/validation/submit workflow cannot rely on
* the entity_language() function. On the other hand in these scenarios assuming
* the presence of Entity translation should be safe, thus being able to rely on
* the EntityTranslationHandlerInterface::getLanguage() method.
* the presence of Entity translation should be safe, thus developers can rely
* on the EntityTranslationHandlerInterface::getLanguage() method.
*
* @param $entity_type
* @param string $entity_type
* The the type of the entity.
* @param $entity
* @param object $entity
* The entity whose language has to be returned.
*
* @return
* @return string
* A valid language code.
*/
function entity_translation_language($entity_type, $entity) {
$handler = entity_translation_get_handler($entity_type, $entity);
if (empty($handler)) {
if (!$handler) {
return LANGUAGE_NONE;
}
$langcode = $handler->getFormLanguage();
return !empty($langcode) ? $langcode : $handler->getLanguage();
if (entity_translation_enabled($entity_type, $entity)) {
$langcode = $handler->getActiveLanguage();
return $langcode ? $langcode : $handler->getLanguage();
}
else {
return $handler->getLanguage();
}
}
/**
@@ -1862,15 +1890,8 @@ function entity_translation_language($entity_type, $entity) {
* A class implementing EntityTranslationHandlerInterface.
*/
function entity_translation_get_handler($entity_type = NULL, $entity = NULL) {
if (class_exists('EntityTranslationHandlerFactory')) {
$factory = EntityTranslationHandlerFactory::getInstance();
return empty($entity) ? $factory->getLastHandler($entity_type) : $factory->getHandler($entity_type, $entity);
}
// @todo BC layer. Remove before the first stable release.
elseif (!empty($entity_type) && is_object($entity)) {
$entity_info = entity_get_info($entity_type);
return new EntityTranslationDefaultHandler($entity_type, $entity_info, $entity);
}
$factory = EntityTranslationHandlerFactory::getInstance();
return empty($entity) ? $factory->getLastHandler($entity_type) : $factory->getHandler($entity_type, $entity);
}
/**
@@ -1915,7 +1936,7 @@ function entity_translation_current_form_get_handler() {
}
/**
* Returns an array of edit form info as defined in hook_translation_info().
* Returns an array of edit form info as defined in hook_entity_info().
*
* @param $form
* The entity edit form.
@@ -2027,7 +2048,7 @@ function entity_translation_entity_uuid_presave(&$entity, $entity_type) {
}
/**
* Implement hook_pathauto_alias_alter().
* Implements hook_pathauto_alias_alter().
*
* When bulk-updating aliases for nodes automatically create a path for every
* translation.
@@ -2037,17 +2058,20 @@ function entity_translation_pathauto_alias_alter(&$alias, array &$context) {
$entity_type = $context['module'];
// Ensure that we are dealing with a bundle having entity translation enabled.
if ($context['op'] == 'bulkupdate' && !empty($info[$entity_type]['token type']) && !empty($context['data'][$info[$entity_type]['token type']])) {
if (in_array($context['op'], array('bulkupdate', 'update')) && !empty($info[$entity_type]['token type']) && !empty($context['data'][$info[$entity_type]['token type']])) {
$entity = $context['data'][$info[$entity_type]['token type']];
if (entity_translation_enabled($entity_type, $entity)) {
$translations = entity_translation_get_handler($entity_type, $entity)->getTranslations();
// Only create extra aliases if we are working on the original language to
// avoid infinite recursion.
if ($context['language'] == $translations->original) {
// To avoid infinite recursion, remember the starting language.
static $pathauto_start_language;
if (!$pathauto_start_language) {
$pathauto_start_language = $context['language'];
}
if ($context['language'] == $pathauto_start_language && $context['language'] != LANGUAGE_NONE) {
foreach ($translations->data as $language => $translation) {
// We already have an alias for the original language, so let's not
// We already have an alias for the starting language, so let's not
// create another one.
if ($language == $translations->original) {
if ($language == $pathauto_start_language) {
continue;
}
pathauto_create_alias($entity_type, $context['op'], $context['source'], $context['data'], $context['type'], $language);
@@ -2085,3 +2109,11 @@ function entity_translation_entity_save($entity_type, $entity) {
field_attach_update($entity_type, $entity);
}
}
/**
* Implements hook_field_attach_prepare_translation_alter().
*/
function entity_translation_field_attach_prepare_translation_alter(&$entity, $context) {
$handler = entity_translation_get_handler('node', $entity);
$handler->setActiveLanguage($context['langcode']);
}

View File

@@ -40,6 +40,9 @@ function entity_translation_taxonomy_term_menu_alter(&$items, $backup) {
$items['taxonomy/term/%taxonomy_term/translate']['access callback'] = 'entity_translation_taxonomy_term_tab_access';
$items['taxonomy/term/%taxonomy_term/translate']['file'] = 'entity_translation.admin.inc';
$items['taxonomy/term/%taxonomy_term/translate']['module'] = 'entity_translation';
// Delete translation callback.
$items['taxonomy/term/%taxonomy_term/translate/delete/%entity_translation_language']['access arguments'] = $access_arguments;
}
/**
@@ -94,3 +97,472 @@ function entity_translation_form_taxonomy_form_vocabulary_submit($form, &$form_s
variable_set('entity_translation_taxonomy', $info);
}
/**
* Returns a translated label for the specified taxonomy term.
*
* @param object $term
* A taxonomy term object.
* @param string $langcode
* The language the label should be translated in.
*
* @return string
* The translated taxonomy term label.
*
* @internal This is supposed to be used only by the ET taxonomy integration
* code, as it might be removed/replaced in any moment of the ET lifecycle.
*/
function _entity_translation_taxonomy_label($term, $langcode) {
$entity_type = 'taxonomy_term';
if (function_exists('title_entity_label')) {
$label = title_entity_label($term, $entity_type, $langcode);
}
else {
$label = entity_label($entity_type, $term);
}
return (string) $label;
}
/**
* Implements entity_translation_form_field_ui_field_edit_WIDGET_TYPE_form_alter().
*
* {@inheritdoc}
*/
function entity_translation_form_field_ui_field_edit_taxonomy_autocomplete_form_alter(&$form, &$form_state) {
$key = 'entity_translation_taxonomy_autocomplete_translate';
$instance = $form['#instance'];
$field_name = $instance['field_name'];
$entity_type = $instance['entity_type'];
$field = field_info_field($field_name);
$translatable = field_is_translatable($entity_type, $field);
$bundle = !empty($field['settings']['allowed_values'][0]['vocabulary']) ? $field['settings']['allowed_values'][0]['vocabulary'] : NULL;
$access = variable_get('entity_translation_taxonomy_autocomplete', FALSE);
// Add a checkbox to toggle in-place translation for autocomplete widgets.
$form['instance']['settings'][$key] = array(
'#type' => 'checkbox',
'#title' => t('Enable in-place translation of terms'),
'#description' => t('Check this option if you wish to use translation forms to perform in-place translation for terms entered in the original language.'),
'#default_value' => !$translatable && !empty($form['#instance']['settings'][$key]),
'#access' => $access && (!$form_state['field_has_data'] || !$translatable) && entity_translation_enabled('taxonomy_term', $bundle),
'#states' => array(
'visible' => array(':input[name="field[translatable]"]' => array('checked' => FALSE)),
),
'#weight' => -8,
);
}
/**
* Checks whether in-place translation is enabled for the autocomplete widget.
*
* @param array $element
* The widget form element.
* @param array $form_state
* The form state array.
*
* @return bool
* TRUE if in-place translation is enabled, FALSE otherwise.
*/
function _entity_translation_taxonomy_autocomplete_translation_enabled($element, $form_state) {
$field = field_info_field($element['#field_name']);
if (field_is_translatable($element['#entity_type'], $field)) {
return FALSE;
}
list($id, , $bundle) = entity_extract_ids($element['#entity_type'], $element['#entity']);
if (!$id) {
return FALSE;
}
$entity_type = 'taxonomy_term';
$parent_handler = entity_translation_get_handler($element['#entity_type'], $element['#entity']);
$active_langcode = $parent_handler->getActiveLanguage();
$translations = $parent_handler->getTranslations();
$entity_langcode = isset($translations->original) ? $translations->original : LANGUAGE_NONE;
$instance = field_info_instance($element['#entity_type'], $field['field_name'], $bundle);
// We need to make sure that we are not dealing with a translation form.
// However checking the active language is not enough, because the user may
// have changed the entity language.
return
(isset($form_state['entity_translation']['is_translation']) ?
$form_state['entity_translation']['is_translation'] : ($active_langcode != $entity_langcode)) &&
!empty($instance['settings']['entity_translation_taxonomy_autocomplete_translate']) &&
(user_access('translate any entity') || user_access("translate $entity_type entities"));
}
/**
* Implements hook_field_widget_WIDGET_TYPE_form_alter().
*
* {@inheritdoc}
*/
function entity_translation_field_widget_taxonomy_autocomplete_form_alter(&$element, &$form_state, $context) {
// The autocomplete widget is also displayed in the field configuration form,
// in which case we do not need to perform any alteration. To preserve BC, by
// default we enable our taxonomy autocomplete override only on new sites.
if (!isset($element['#entity']) || !variable_get('entity_translation_taxonomy_autocomplete', FALSE)) {
return;
}
// We will need to translate term names, if Title is enabled and configured
// for this vocabulary.
$entity_type = 'taxonomy_term';
$field = field_widget_field($element, $form_state);
$bundle = !empty($field['settings']['allowed_values'][0]['vocabulary']) ? $field['settings']['allowed_values'][0]['vocabulary'] : NULL;
if ($bundle && entity_translation_enabled($entity_type, $bundle)) {
$parent_handler = entity_translation_get_handler($element['#entity_type'], $element['#entity']);
$langcode = $parent_handler->getActiveLanguage();
$terms = array_values(_entity_translation_taxonomy_autocomplete_widget_get_terms($element));
// If we are using the regular autocomplete behavior also in translation
// forms, we need to set our custom callback.
if (!_entity_translation_taxonomy_autocomplete_translation_enabled($element, $form_state)) {
$element['#autocomplete_path'] = 'entity_translation/' . $entity_type . '/autocomplete/' . $langcode . '/' . $element['#field_name'];
$translations = $parent_handler->getTranslations();
if (isset($translations->original) && $translations->original != $langcode) {
$labels = array();
foreach ($terms as $delta => $term) {
$labels[] = _entity_translation_taxonomy_label($term, $langcode);
}
$element['#default_value'] = implode(', ', $labels);
}
}
// Otherwise we just provide the in-place translation widget.
else {
$element['#type'] = 'fieldset';
$element['#description'] = t('Enter one translation for each term');
$element['#access'] = (bool) $terms;
foreach ($terms as $delta => $term) {
$element[$delta] = array(
'#type' => 'textfield',
'#default_value' => _entity_translation_taxonomy_label($term, $langcode),
'#required' => TRUE,
'#tid' => $term->tid,
);
}
$element['#process'][] = 'entity_translation_taxonomy_autocomplete_process';
}
// The native term save logic is performed at widget validation level, so we
// just replace the validation handler to provide our logic instead.
$element['#element_validate'] = array_values(array_diff($element['#element_validate'], array('taxonomy_autocomplete_validate')));
$element['#element_validate'][] = 'entity_translation_taxonomy_autocomplete_validate';
}
}
/**
* Returns the terms referenced by the taxonomy autocomplete widget field.
*
* @param array $element
* The taxonomy autocomplete form element.
*
* @return object[]
* An associative array of taxonomy term object keyed by their identifiers.
*/
function _entity_translation_taxonomy_autocomplete_widget_get_terms($element) {
$items = isset($element['#entity']->{$element['#field_name']}[$element['#language']]) ?
$element['#entity']->{$element['#field_name']}[$element['#language']] : array();
$tids = array_map(function ($item) { return $item['tid']; }, $items);
return taxonomy_term_load_multiple($tids);
}
/**
* Process callback for the ET taxonomy autocomplete widget.
*
* {@inheritdoc}
*/
function entity_translation_taxonomy_autocomplete_process($element) {
// The in-place translation widget makes sense only for untranslatable field,
// which may have the "(all languages)" label suffix. In this case it would be
// confusing so we need to revert that.
$instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
$element['#title'] = check_plain($instance['label']);
return $element;
}
/**
* Entity translation taxonomy autocomplete callback.
*
* @param string $langcode
* The input language.
* @param string $field_name
* The name of the term reference field.
* @param string $tags_typed
* (optional) A comma-separated list of term names entered in the
* autocomplete form element. Only the last term is used for autocompletion.
* Defaults to an empty string.
*
* @see taxonomy_autocomplete()
*/
function entity_translation_taxonomy_term_autocomplete($langcode = NULL, $field_name = '', $tags_typed = '') {
// If the request has a '/' in the search text, then the menu system will have
// split it into multiple arguments, recover the intended $tags_typed.
$args = func_get_args();
// Shift off the $langcode and $field_name arguments.
array_shift($args);
array_shift($args);
$tags_typed = implode('/', $args);
// Make sure the field exists and is a taxonomy field.
if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') {
// Error string. The JavaScript handler will realize this is not JSON and
// will display it as debugging information.
print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name));
exit;
}
// The user enters a comma-separated list of tags. We only autocomplete the
// last tag.
$tags_typed = drupal_explode_tags($tags_typed);
$tag_last = drupal_strtolower(array_pop($tags_typed));
$term_matches = array();
if ($tag_last != '') {
if (!isset($langcode) || $langcode == LANGUAGE_NONE) {
$langcode = $GLOBALS['language_content']->language;
}
// Part of the criteria for the query come from the field's own settings.
$vocabulary = _entity_translation_taxonomy_reference_get_vocabulary($field);
$entity_type = 'taxonomy_term';
$query = new EntityFieldQuery();
$query->addTag('taxonomy_term_access');
$query->entityCondition('entity_type', $entity_type);
// If the Title module is enabled and the taxonomy term name is replaced for
// the current bundle, we can look for translated names, otherwise we fall
// back to the regular name property.
if (module_invoke('title', 'field_replacement_enabled', $entity_type, $vocabulary->machine_name, 'name')) {
$name_field = 'name_field';
$language_group = 0;
// Do not select already entered terms.
$column = 'value';
if (!empty($tags_typed)) {
$query->fieldCondition($name_field, $column, $tags_typed, 'NOT IN', NULL, $language_group);
}
$query->fieldCondition($name_field, $column, $tag_last, 'CONTAINS', NULL, $language_group);
$query->fieldLanguageCondition($name_field, array($langcode, LANGUAGE_NONE), NULL, NULL, $language_group);
}
else {
$name_field = 'name';
// Do not select already entered terms.
if (!empty($tags_typed)) {
$query->propertyCondition($name_field, $tags_typed, 'NOT IN');
}
$query->propertyCondition($name_field, $tag_last, 'CONTAINS');
}
// Select rows that match by term name.
$query->propertyCondition('vid', $vocabulary->vid);
$query->range(0, 10);
$result = $query->execute();
// Populate the results array.
$prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
$terms = !empty($result[$entity_type]) ? taxonomy_term_load_multiple(array_keys($result[$entity_type])) : array();
foreach ($terms as $tid => $term) {
$name = _entity_translation_taxonomy_label($term, $langcode);
$n = $name;
// Term names containing commas or quotes must be wrapped in quotes.
if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
$n = '"' . str_replace('"', '""', $name) . '"';
}
$term_matches[$prefix . $n] = check_plain($name);
}
}
drupal_json_output($term_matches);
}
/**
* Returns the vocabulary enabled for the specified taxonomy reference field.
*
* @param array $field
* A field definition.
*
* @return object|null
* A vocabulary object or NULL if none is found.
*/
function _entity_translation_taxonomy_reference_get_vocabulary($field) {
$vocabulary = NULL;
if (!empty($field['settings']['allowed_values'])) {
$vids = array();
$vocabularies = taxonomy_vocabulary_get_names();
foreach ($field['settings']['allowed_values'] as $tree) {
$vids[] = $vocabularies[$tree['vocabulary']]->vid;
}
$vocabulary = taxonomy_vocabulary_load(reset($vids));
}
return $vocabulary;
}
/**
* Form element validate handler for taxonomy term autocomplete element.
*
* {@inheritdoc}
*
* @see taxonomy_autocomplete_validate()
*/
function entity_translation_taxonomy_autocomplete_validate($element, &$form_state) {
$value = array();
list($id) = entity_extract_ids($element['#entity_type'], $element['#entity']);
$is_new = !isset($id);
// This is the language of the parent entity, that we will be applying to new
// terms.
$parent_handler = entity_translation_get_handler($element['#entity_type'], $element['#entity']);
$langcode = !empty($form_state['entity_translation']['form_langcode']) ?
$form_state['entity_translation']['form_langcode'] : $parent_handler->getActiveLanguage();
// Handle in-place translation.
if (_entity_translation_taxonomy_autocomplete_translation_enabled($element, $form_state)) {
// The referenced terms cannot change, so we just need to collect their term
// identifiers. We also build a map of the corresponding deltas for later
// use.
$deltas = array();
foreach (element_children($element) as $delta) {
$tid = $element[$delta]['#tid'];
$deltas[$tid] = $delta;
$value[$delta]['tid'] = $tid;
}
// Save term translations.
$entity_type = 'taxonomy_term';
$name_field = 'name_field';
$source_langcode = $parent_handler->getSourceLanguage();
// This is a validation handler, so we must defer the actual save to the
// submit phase.
$terms_to_save = &$form_state['entity_translation']['taxonomy_autocomplete'][$element['#entity_type']][$id][$element['#field_name']];
foreach (taxonomy_term_load_multiple(array_keys($deltas)) as $term) {
// This is also the right context to perform validation.
$term_translation = $element[$deltas[$term->tid]]['#value'];
if (!$term_translation) {
$instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
drupal_set_message(t('The translations for %field_label cannot be empty.', array('%field_label' => $instance['label'])), 'error', FALSE);
continue;
}
$handler = entity_translation_get_handler($entity_type, $term);
$translations = $handler->getTranslations();
$term_langcode = $handler->getLanguage();
$typed_langcode = $term_langcode != LANGUAGE_NONE ? $langcode : $term_langcode;
// Create a new translation in the active language, if it is missing.
if (!isset($translations->data[$typed_langcode]) && $typed_langcode != LANGUAGE_NONE) {
$translation = array(
'language' => $typed_langcode,
'source' => $source_langcode,
'uid' => $GLOBALS['user']->uid,
'status' => 1,
'created' => REQUEST_TIME,
'changed' => REQUEST_TIME,
);
$translation_values = array(
$name_field => array($typed_langcode => array(array('value' => $term_translation))),
);
$handler->setTranslation($translation, $translation_values);
$terms_to_save[] = $term;
}
// Otherwise we just update the existing translation, if it has changed.
// If the term is language-neutral, we just update its main value. This is
// expected to happen normally, but could when referencing existing terms.
elseif ($term_translation != _entity_translation_taxonomy_label($term, $typed_langcode)) {
$term->{$name_field}[$typed_langcode][0]['value'] = $term_translation;
$terms_to_save[] = $term;
}
}
}
// Autocomplete widgets do not send their tids in the form, so we must detect
// them here and process them independently.
elseif ($tags = $element['#value']) {
$entity_type = 'taxonomy_term';
$field = field_widget_field($element, $form_state);
$vocabulary = _entity_translation_taxonomy_reference_get_vocabulary($field);
$typed_tags = drupal_explode_tags($tags);
// Collect existing terms by name.
$existing_terms = array();
foreach (_entity_translation_taxonomy_autocomplete_widget_get_terms($element) as $term) {
$name = _entity_translation_taxonomy_label($term, $langcode);
$existing_terms[$name] = $term;
}
// Select terms that match by the (translated) name.
$query = new EntityFieldQuery();
$query->addTag('taxonomy_term_access');
$query->entityCondition('entity_type', $entity_type);
$query->propertyCondition('vid', $vocabulary->vid);
if ($langcode != LANGUAGE_NONE && module_invoke('title', 'field_replacement_enabled', $entity_type, $vocabulary->machine_name, 'name')) {
$language_group = 0;
// Do not select already entered terms.
$name_field = 'name_field';
$column = 'value';
$query->fieldCondition($name_field, $column, $typed_tags, NULL, NULL, $language_group);
// When we are creating a new entity, we cannot filter by active language,
// as that may have not be applied to the autocomplete query.
if (!$is_new) {
$query->fieldLanguageCondition($name_field, array($langcode, LANGUAGE_NONE), NULL, NULL, $language_group);
}
}
else {
$query->propertyCondition('name', $typed_tags);
}
$result = $query->execute();
// When we are creating a new entity, the language used for the autocomplete
// query is the current content language, so we should use that to update
// the map of existing terms.
if (!empty($result[$entity_type])) {
$typed_langcode = !$is_new ? $langcode : $GLOBALS['language_content']->language;
foreach (taxonomy_term_load_multiple(array_keys($result[$entity_type])) as $term) {
$name = _entity_translation_taxonomy_label($term, $typed_langcode);
$existing_terms[$name] = $term;
}
}
// Now collect the identifiers for the various terms and update the taxonomy
// reference field values.
foreach ($typed_tags as $delta => $typed_tag) {
// See if the term exists in the chosen vocabulary and return the tid.
// Otherwise create a new 'autocreate' term for insert/update.
if (isset($existing_terms[$typed_tag])) {
$term = $existing_terms[$typed_tag];
}
else {
$term = (object) array(
'tid' => 'autocreate',
'vid' => $vocabulary->vid,
'name' => $typed_tag,
'vocabulary_machine_name' => $vocabulary->machine_name,
);
$handler = entity_translation_get_handler($entity_type, $term);
$handler->setOriginalLanguage($langcode);
$handler->initTranslations();
}
$value[] = (array) $term;
}
}
form_set_value($element, $value, $form_state);
}
/**
* Term-specific implementation of hook_field_attach_submit().
*/
function entity_translation_taxonomy_term_field_attach_submit($entity_type, $entity, $form, &$form_state) {
// Finally save in-place translations
if (!empty($form_state['entity_translation']['taxonomy_autocomplete'])) {
foreach ($form_state['entity_translation']['taxonomy_autocomplete'] as $entity_type => $entity_type_data) {
foreach ($entity_type_data as $id => $field_name_data) {
foreach ($field_name_data as $field_name => $term_data) {
if (!is_array($term_data)) {
continue;
}
foreach ($term_data as $term) {
entity_translation_entity_save('taxonomy_term', $term);
}
}
}
}
}
}

View File

@@ -7,9 +7,8 @@ dependencies[] = i18n
dependencies[] = i18n_menu
files[] = entity_translation_i18n_menu.test
; Information added by Drupal.org packaging script on 2016-09-28
version = "7.x-1.0-beta5+15-dev"
; Information added by Drupal.org packaging script on 2019-01-20
version = "7.x-1.0+5-dev"
core = "7.x"
project = "entity_translation"
datestamp = "1475057941"
datestamp = "1548022384"

View File

@@ -164,7 +164,7 @@ function entity_translation_i18n_menu_form(&$form, &$form_state) {
$default = isset($source_menu['language']) && $source_menu['language'] != LANGUAGE_NONE;
$languages = language_list();
$handler = entity_translation_entity_form_get_handler($form, $form_state);
$langcode = $handler->getFormLanguage();
$langcode = $handler->getActiveLanguage();
$language_name = isset($languages[$langcode]) ? t($languages[$langcode]->name) : t('current');
$form['menu']['#multilingual'] = TRUE;

View File

@@ -125,23 +125,36 @@ class EntityTranslationMenuTranslationTestCase extends EntityTranslationTestCase
$this->assertText($link_title, 'New menu link title found: ' . $link_title);
}
/**
* Asserts a link with a given label and title is found in the page.
*/
function assertLinkWithTitleAttribute($label, $title) {
$links = $this->xpath('//a[normalize-space(text())=:label and normalize-space(@title)=:title]', array(
':label' => $label,
':title' => $title,
));
$this->assert(isset($links[0]));
}
/**
* Test if menu localization works.
*/
function testMenuLocalization() {
// Create Basic page in English.
$link_title_en = $this->randomName();
$node = $this->createPage($link_title_en, NULL, 'en');
$link_description_en = $this->randomName() . ' & htmlentity';
$node = $this->createPage($link_title_en, $link_description_en, 'en');
// Submit translation in Spanish.
$link_title_es = $this->randomName();
$node_translation = $this->createTranslation($node, $link_title_es, NULL, 'es');
$link_description_es = $this->randomName() . ' & htmlentity';
$node_translation = $this->createTranslation($node, $link_title_es, $link_description_es, 'es');
// Check menu links in both languages.
$this->get('en', '<front>');
$this->assertText($link_title_en);
$this->assertLinkWithTitleAttribute($link_title_en, $link_description_en);
$this->get('es', '<front>');
$this->assertText($link_title_es);
$this->assertLinkWithTitleAttribute($link_title_es, $link_description_es);
// Edit English menu link.
$link_title_en2 = $this->randomName();
@@ -149,15 +162,19 @@ class EntityTranslationMenuTranslationTestCase extends EntityTranslationTestCase
// Check that Spanish menu link has not changed.
$this->get('es', '<front>');
$this->assertText($link_title_es);
$this->assertLinkWithTitleAttribute($link_title_es, $link_description_es);
// Edit Spanish menu link.
$link_title_es2 = $this->randomName();
$this->editPage($node, $link_title_es, $link_title_es2, 'es');
// Check that English menu link has not changed.
// Check that English menu link has changed.
$this->get('en', '<front>');
$this->assertText($link_title_en2);
$this->assertLinkWithTitleAttribute($link_title_en2, $link_description_en);
// Check that Spanish menu link has changed.
$this->get('es', '<front>');
$this->assertLinkWithTitleAttribute($link_title_es2, $link_description_es);
// Delete Spanish translation and check that the respective menu item has
// been deleted as well.

View File

@@ -34,8 +34,8 @@ function entity_translation_upgrade_start($types) {
*/
function entity_translation_upgrade_end($success, $results, $operations, $elapsed) {
if (!empty($results)) {
$message = format_plural($results, '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
watchdog('entity translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results), WATCHDOG_INFO);
$message = format_plural($results['total'], '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
watchdog('entity translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results['total']), WATCHDOG_INFO);
}
else {
$message = t('No node translation available for the upgrade.');
@@ -91,6 +91,10 @@ function entity_translation_upgrade_do($types, &$context) {
$node = $nodes[$nid];
$original = $nodes[$node->tnid];
$handler = entity_translation_get_handler('node', $original);
// Instantiate the data and original properties of the translations.
if (empty($handler->getTranslations()->data)) {
$handler->initTranslations();
}
if (!isset($instances[$node->type])) {
$instances[$node->type] = field_info_instances('node', $node->type);
@@ -185,7 +189,7 @@ function entity_translation_upgrade_do($types, &$context) {
$context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
if ($context['finished'] >= 1) {
$context['results'] = $context['sandbox']['total'];
$context['results']['total'] = $context['sandbox']['total'];
}
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* Implements hook_drush_command().
*/
function entity_translation_upgrade_drush_command() {
$items = array();
$items['entity-translation-upgrade'] = array(
'description' => "Upgrades all nodes of the specified content type from Content Translation to Entity Translation.",
'arguments' => array(
'content_type' => 'Content type of nodes to be upgraded.',
),
'examples' => array(
'drush entity-translation-upgrade article' => 'Upgrades all nodes of content type "article" from Content Translation to Entity Translation.',
),
'aliases' => array('etu'),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
);
return $items;
}
/**
* Implements hook_drush_help().
*
* @param
* A string with the help section
*
* @return
* A string with the help text for the entity-translation-upgrade command
*/
function entity_translation_upgrade_drush_help($section) {
switch ($section) {
case 'drush:entity-translation-upgrade':
return dt("Brief help for Drush command entity-translation-upgrade.");
case 'meta:entity_translation_upgrade:title':
return dt("Entity Translation Upgrade commands");
case 'meta:entity_translation_upgrade:summary':
return dt("Upgrading nodes to Entity Translation.");
}
}
/**
* Implements drush_hook_COMMAND().
*
* @param
* The content type of which the nodes shall be upgraded
*
* Runs the batch upgrading nodes of the specified content_type to Entity
* Translation. Lets user choose content type from a list, if argument has
* not been provided.
*/
function drush_entity_translation_upgrade($content_type = "") {
// Get all installed content types.
$available_types = array();
$available_types_chose = array();
$available_types_str = '';
foreach (node_type_get_types() as $type) {
$available_types[$type->type] = $type->type;
$available_types_chose[$type->type] = $type->name;
if (strlen($available_types_str) > 0) {
$available_types_str .= ', ';
}
$available_types_str .= $type->type;
}
// If argument content_type is empty, prompt user for content type.
if (!$content_type) {
$content_type = drush_choice($available_types_chose, dt('Choose the content type of the nodes to be upgraded to Entity Translation:'));
}
// Do content type argument checks.
if (!$content_type) {
return TRUE;
}
if (strlen($available_types_str) == 0) {
return drush_set_error(dt('Entity Translation Upgrade cannot run as no content type has been installed.'));
}
if (!in_array($content_type, $available_types)) {
return drush_set_error(dt('"@content_type" is not a valid content type machine name. Please use one of these installed content types as argument: @available_types_str.', array('@content_type' => $content_type, '@available_types_str' => $available_types_str)));
}
// Start batch to upgrade nodes of the specified content type.
$types = array($content_type => $content_type);
$batch = array(
'operations' => array(
array('entity_translation_upgrade_do', array($types)),
array('entity_translation_upgrade_complete', array()),
),
'finished' => 'entity_translation_upgrade_drush_end',
'file' => drupal_get_path('module', 'entity_translation_upgrade') . '/entity_translation_upgrade.admin.inc',
'progressive' => FALSE,
);
batch_set($batch);
drush_backend_batch_process();
}
/**
* This is the 'finished' batch callback, drush version.
*/
function entity_translation_upgrade_drush_end($success, $results, $operations, $elapsed) {
// Print result messages.
if (!empty($results)) {
$message = format_plural($results['total'], '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
$severity = 'ok';
watchdog('Entity Translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results['total']), WATCHDOG_INFO);
}
else {
$message = t('No node translation available for the upgrade.');
$severity = 'warning';
}
drush_log($message, $severity);
}

View File

@@ -3,10 +3,10 @@ description = Provides an upgrade path from node-based translation to field-base
package = Multilingual - Entity Translation
core = 7.x
dependencies[] = entity_translation
files[] = entity_translation_upgrade.test
; Information added by Drupal.org packaging script on 2016-09-28
version = "7.x-1.0-beta5+15-dev"
; Information added by Drupal.org packaging script on 2019-01-20
version = "7.x-1.0+5-dev"
core = "7.x"
project = "entity_translation"
datestamp = "1475057941"
datestamp = "1548022384"

View File

@@ -0,0 +1,163 @@
<?php
/**
* @file
* Tests for Entity Translation module.
*/
/**
* Tests for the upgrade translation process.
*/
class EntityTranslationUpgradeTestCase extends EntityTranslationTestCase {
/**
* Return the test information.
*/
public static function getInfo() {
return array(
'name' => 'Translation upgrade',
'description' => 'Tests for the upgrade from Content Translation to Entity Translation.',
'group' => 'Entity translation',
'dependencies' => array(),
);
}
function setUp() {
parent::setUp('locale', 'translation', 'translation_test', 'entity_translation', 'entity_translation_upgrade');
$this->getAdminUser(array(
'toggle field translatability',
'administer entity translation',
));
$this->getTranslatorUser(array(
'translate content',
));
$this->login($this->getAdminUser());
$this->addLanguage('en');
$this->addLanguage('es');
$this->configureContentTypeForContentTranslation();
$this->enableUrlLanguageDetection();
$this->login($this->getTranslatorUser());
}
/**
* Configure the "Basic page" content type for entity translation tests.
*/
public function configureContentTypeForContentTranslation() {
// Configure the "Basic page" content type to use multilingual support with
// content translation.
$edit = array();
$edit['language_content_type'] = TRANSLATION_ENABLED;
$this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
}
/**
* Toggle body field's translatability.
*/
public function makeBodyFieldTranslatable() {
$edit = array();
$this->drupalGet('admin/structure/types/manage/page/fields/body');
$this->clickLink('Enable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
$this->assertRaw(t('Data successfully processed.'), t('Body field have been made translatable.'));
}
/**
* @see TranslationTestCase::createPage
*/
function createContentTranslationPage($title, $body, $language = NULL) {
$edit = array();
$langcode = LANGUAGE_NONE;
$edit["title"] = $title;
$edit["body[$langcode][0][value]"] = $body;
if (!empty($language)) {
$edit['language'] = $language;
}
$this->drupalPost('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Basic page created.');
// Check to make sure the node was created.
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node, 'Node found in database.');
return $node;
}
/**
* @see TranslationTestCase::createTranslation
*/
function createContentTranslationTranslation($node, $title, $body, $language) {
$this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language)));
$langcode = LANGUAGE_NONE;
$body_key = "body[$langcode][0][value]";
$this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated.");
$this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[LANGUAGE_NONE][0]['value'], "Original body value correctly populated.");
$edit = array();
$edit["title"] = $title;
$edit[$body_key] = $body;
$this->drupalPost(NULL, $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Translation created.');
// Check to make sure that translation was successful.
$translation = $this->drupalGetNodeByTitle($title);
$this->assertTrue($translation, 'Node found in database.');
$this->assertTrue($translation->tnid == $node->nid, 'Translation set id correctly stored.');
return $translation;
}
/**
* Tests copying of source node's body value in the add translation form page.
*/
public function testUpgradeContentToEntityTranslation() {
// Create Basic page in English.
$node_title = $this->randomName();
$node_body = $this->randomName();
$node = $this->createContentTranslationPage($node_title, $node_body, 'en');
// Submit translation in Spanish.
$this->drupalGet('node/' . $node->nid . '/translate');
$node_translation_title = $this->randomName();
$node_translation_body = $this->randomName();
$node_translation = $this->createContentTranslationTranslation($node, $node_translation_title, $node_translation_body, 'es');
// Make Body field translatable before we run the upgrade.
$this->login($this->getAdminUser());
$this->makeBodyFieldTranslatable();
// Run the upgrade for all Page nodes.
$edit = array(
'types[page]' => 'page',
);
$this->drupalPost('admin/config/regional/entity_translation', $edit, t('Upgrade'));
// Switch to our translator user.
$this->login($this->getTranslatorUser());
// Check that the unpublished target node triggers a redirect.
$this->drupalGet('node/' . $node_translation->nid);
$headers = $this->drupalGetHeaders(TRUE);
list(, $status) = explode(' ', $headers[0][':status'], 3);
$this->assertEqual($status, 301, 'Expected response code was sent.');
$languages = language_list();
$this->assertEqual($this->getUrl(), url('node/' . $node->nid, array('absolute' => TRUE, 'language' => $languages['es'])), 'entity_translation_upgrade_redirect() redirected to expected URL.');
// Check that the body is displayed when the active language is English.
$this->drupalGet('node/' . $node->nid);
$this->assertRaw($node_body, t('Body field displayed correctly in the source language.'));
// Check that the translated body is displayed when the active language is Spanish.
$this->drupalGet('es/node/' . $node->nid);
$this->assertRaw($node_translation_body, t('Body field displayed correctly in the target language.'));
// Check that the edit forms are initialized correctly in the target language.
$this->drupalGet('node/' . $node->nid . '/edit');
$this->assertFieldByXPath("//textarea[@name='body[en][0][value]']", $node_body, "Body field correctly instantiated with the value of the source language.");
$this->drupalGet('es/node/' . $node->nid . '/edit');
$this->assertFieldByXPath("//textarea[@name='body[es][0][value]']", $node_translation_body, "Body field correctly instantiated with the value of the target language.");
}
}

View File

@@ -98,6 +98,62 @@ interface EntityTranslationHandlerInterface {
*/
public function getLanguage();
/**
* Sets the active language.
*
* This is the language that determines which translation should be considered
* "active" for the wrapped entity. The "Entity Translation" module uses this
* information to implement the UI-based translation workflow. Other modules
* can rely on it to implement their own entity translation-related logic.
*
* This will affect which language is returned by the core "entity_language()"
* function.
*
* @param string $langcode
* The active language code.
*
* @see entity_language()
* @see entity_translation_language()
* @see ::getActiveLanguage()
*/
public function setActiveLanguage($langcode);
/**
* Returns the active language.
*
* @return string
* The active language for the wrapped entity.
*
* @see ::setActiveLanguage()
*/
public function getActiveLanguage();
/**
* Sets the active form language.
*
* @param string $langcode
* The active form language code.
*
* @deprecated in 7.x-1.0-beta6, will be removed before 7.x-1.0. Use
* ::setActiveLanguage() instead.
*
* @see ::setActiveLanguage()
*/
public function setFormLanguage($langcode);
/**
* Retrieves the active form language.
*
* @return string
* The active form language code.
*
* @deprecated in 7.x-1.0-beta6, will be removed before 7.x-1.0. Use
* ::getActiveLanguage() instead.
*
* @see ::getActiveLanguage()
*/
public function getFormLanguage();
/**
* Returns the translation object key for the wrapped entity type.
*/
@@ -109,7 +165,7 @@ interface EntityTranslationHandlerInterface {
public function getDefaultLanguage();
/**
* Sets the language of the orginal translation.
* Sets the language of the original translation.
*
* @param $langcode
* The language code of the original content values.
@@ -272,16 +328,6 @@ interface EntityTranslationHandlerInterface {
*/
public function isAliasEnabled();
/**
* Sets the active form language.
*/
public function setFormLanguage($langcode);
/**
* Retrieves the active form language.
*/
public function getFormLanguage();
/**
* Sets the source language for the translation being created.
*/
@@ -364,19 +410,19 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
*/
protected $children = array();
private $entityForm;
private $translating;
private $outdated;
private $formLanguage;
private $sourceLanguage;
protected $entityForm;
protected $translating;
protected $outdated;
protected $activeLanguage;
protected $sourceLanguage;
private $pathScheme;
private $pathWildcard;
private $basePath;
private $editPath;
private $translatePath;
private $viewPath;
private $routerMap;
protected $pathScheme;
protected $pathWildcard;
protected $basePath;
protected $editPath;
protected $translatePath;
protected $viewPath;
protected $routerMap;
/**
* Initializes an instance of the translation handler.
@@ -396,7 +442,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
$this->entityForm = FALSE;
$this->translating = FALSE;
$this->outdated = FALSE;
$this->formLanguage = FALSE;
$this->activeLanguage = FALSE;
$this->sourceLanguage = FALSE;
$this->pathScheme = 'default';
$this->routerMap = array();
@@ -481,7 +527,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
public function addChild($entity_type, $entity) {
if (!empty($this->factory)) {
$handler = $this->factory->getHandler($entity_type, $entity);
$handler->setFormLanguage($this->getFormLanguage());
$handler->setActiveLanguage($this->getActiveLanguage());
$handler->setSourceLanguage($this->getSourceLanguage());
// Avoid registering more than one child handler for each entity.
$hid = $this->factory->getHandlerId($entity_type, $entity);
@@ -632,6 +678,12 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
throw new Exception('Invalid translation language');
}
// $args will be used later on in a call to notifyChildren(). We need
// to call func_get_args() before any modifications to the function's
// arguments take place. This is due to changes in PHP 7.0 and onwards.
// @see http://php.net/manual/en/function.func-get-args.php#refsect1-function.func-get-args-notes
$args = func_get_args();
$translations = $this->getTranslations();
$langcode = $translation['language'];
@@ -658,13 +710,12 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
foreach (field_info_instances($this->entityType, $this->bundle) as $instance) {
$field_name = $instance['field_name'];
$field = field_info_field($field_name);
if ($field['translatable'] && isset($values[$field_name])) {
if ($field['translatable'] && isset($values[$field_name][$langcode])) {
$this->entity->{$field_name}[$langcode] = $values[$field_name][$langcode];
}
}
}
$args = func_get_args();
$this->notifyChildren(__FUNCTION__, $args);
}
@@ -803,6 +854,55 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
}
}
/**
* {@inheritdoc}
*/
public function setActiveLanguage($langcode) {
// @todo To fully preserve BC, we proxy the call to the deprecated
// ::setFormLanguage method. This will keep things working even when it
// has been overridden. Inline its implementation here upon removal.
$this->setFormLanguage($langcode);
}
/**
* {@inheritdoc}
*/
public function getActiveLanguage() {
// @todo To fully preserve BC, we proxy the call to the deprecated
// ::getFormLanguage method. This will keep things working even when it
// has been overridden. Inline its implementation here upon removal.
return $this->getFormLanguage();
}
/**
* {@inheritdoc}
*/
public function setFormLanguage($langcode) {
$this->activeLanguage = $langcode;
$args = func_get_args();
$this->notifyChildren(__FUNCTION__, $args);
}
/**
* {@inheritdoc}
*/
public function getFormLanguage() {
if (!empty($this->activeLanguage)) {
return $this->activeLanguage;
}
// For new entities the active language should match the default language.
// The language stored with the entity itself (for example, $node->language)
// may not be reliable since the function creating the entity object will
// not know which language "Entity Translation" is configured to create the
// entity in.
elseif ($this->isNewEntity()) {
return $this->getDefaultLanguage();
}
else {
return $this->getLanguage();
}
}
/**
* @see EntityTranslationHandlerInterface::getLanguageKey()
*/
@@ -952,7 +1052,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
if ($outdated) {
$translations = $this->getTranslations();
foreach ($translations->data as $langcode => &$translation) {
if ($langcode != $this->getFormLanguage()) {
if ($langcode != $this->getActiveLanguage()) {
$translation['translate'] = 1;
}
}
@@ -1097,7 +1197,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
*/
public function getSharedFieldsAccess() {
$settings = entity_translation_settings($this->entityType, $this->bundle);
return ($settings['shared_fields_original_only'] == FALSE || $this->getLanguage() == $this->getFormLanguage()) &&
return ($settings['shared_fields_original_only'] == FALSE || $this->getLanguage() == $this->getActiveLanguage()) &&
(!entity_translation_workflow_enabled() || user_access('edit translation shared fields') || user_access("edit {$this->entityType} translation shared fields"));
}
@@ -1108,22 +1208,6 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
return !empty($this->entityInfo['translation']['entity_translation']['alias']);
}
/**
* @see EntityTranslationHandlerInterface::setFormLanguage()
*/
public function setFormLanguage($langcode) {
$this->formLanguage = $langcode;
$args = func_get_args();
$this->notifyChildren(__FUNCTION__, $args);
}
/**
* @see EntityTranslationHandlerInterface::getFormLanguage()
*/
public function getFormLanguage() {
return !empty($this->formLanguage) ? $this->formLanguage : $this->getLanguage();
}
/**
* @see EntityTranslationHandlerInterface::setSourceLanguage()
*/
@@ -1161,7 +1245,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
public function entityForm(&$form, &$form_state) {
$this->entityForm = TRUE;
$translations = $this->getTranslations();
$form_langcode = $this->getFormLanguage();
$form_langcode = $this->getActiveLanguage();
$langcode = $this->getLanguage();
$is_translation = $this->isTranslationForm();
$new_translation = !isset($translations->data[$form_langcode]);
@@ -1461,7 +1545,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
$language_key = $this->getLanguageKey();
if (isset($form_state['values'][$language_key]) && !$this->isTranslationForm()) {
$langcode = $form_state['values'][$language_key];
$this->setFormLanguage($langcode);
$this->setActiveLanguage($langcode);
}
}
@@ -1474,7 +1558,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
}
$this->updateFormLanguage($form_state);
$form_langcode = $this->getFormLanguage();
$form_langcode = $this->getActiveLanguage();
foreach (field_info_instances($this->entityType, $this->bundle) as $instance) {
$field_name = $instance['field_name'];
@@ -1496,7 +1580,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
* @see EntityTranslationHandlerInterface::entityFormSubmit()
*/
public function entityFormSubmit($form, &$form_state) {
$form_langcode = $this->getFormLanguage();
$form_langcode = $this->getActiveLanguage();
$translations = $this->getTranslations();
$is_translation = !empty($form_state['entity_translation']['is_translation']);
$new_translation = !isset($translations->data[$form_langcode]);
@@ -1551,7 +1635,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
if (count($translations->data) > 0) {
$languages = language_list();
$form_langcode = $this->getFormLanguage();
$form_langcode = $this->getActiveLanguage();
$language_tabs = array();
if ($this->getSourceLanguage()) {
@@ -1624,7 +1708,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
* Returns TRUE if an entity translation is being edited.
*/
protected function isTranslationForm() {
return !$this->isNewEntity() && $this->getFormLanguage() != $this->getLanguage();
return !$this->isNewEntity() && $this->getActiveLanguage() != $this->getLanguage();
}
/**
@@ -1653,7 +1737,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
*
* @throws Exception
*/
private function initPathVariables() {
protected function initPathVariables() {
if (empty($this->pathScheme) || !isset($this->entityInfo['translation']['entity_translation']['path schemes'][$this->pathScheme])) {
throw new Exception("Cannot initialize entity translation path variables (invalid path scheme).");
}

View File

@@ -87,10 +87,7 @@ class EntityTranslationHandlerFactory {
if (!isset($this->handlers[$entity_type][$id])) {
$entity_info = entity_get_info($entity_type);
$class = $entity_info['translation']['entity_translation']['class'];
// @todo Remove the fourth parameter once 3rd-party translation handlers
// have been fixed and no longer require the deprecated entity_id
// parameter.
$handler = new $class($entity_type, $entity_info, $entity, NULL);
$handler = new $class($entity_type, $entity_info, $entity);
$handler->setFactory($this);
$this->handlers[$entity_type][$id] = $handler;
}

View File

@@ -14,6 +14,9 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
protected $admin_user;
protected $translator_user;
/**
* {@inheritdoc}
*/
function setUp() {
$args = func_get_args();
call_user_func_array(array('parent', 'setUp'), $args);
@@ -133,6 +136,19 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
}
}
/**
* Disable a language which is in the language list.
*
* @param string $langcode
* The code of the language to disable, which must exist.
*/
function disableLanguage($langcode) {
$edit = array(
'enabled[' . $langcode . ']' => FALSE,
);
$this->drupalPost('admin/config/regional/language', $edit, 'Save configuration');
}
/**
* Install a specified language if it has not been already, otherwise make sure that the language is enabled.
*
@@ -190,7 +206,7 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
// Check if the setting works.
$this->drupalGet('node/add/page');
$this->assertFieldById('edit-body-und-add-more', t('Add another item'), t('Add another item button found.'));
$this->assertFieldById('edit-body-en-add-more', t('Add another item'), t('Add another item button found.'));
}
/**
@@ -205,9 +221,8 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
*/
function createPage($title, $body, $langcode) {
$edit = array();
$language_none = LANGUAGE_NONE;
$edit["title"] = $title;
$edit["body[$language_none][0][value]"] = $body;
$edit["body[$langcode][0][value]"] = $body;
$edit['language'] = $langcode;
$this->drupalPost('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));
@@ -270,10 +285,27 @@ class EntityTranslationTranslationTestCase extends EntityTranslationTestCase {
$this->login($this->getAdminUser());
$this->addLanguage('en');
$this->addLanguage('es');
$this->addLanguage('fr');
$this->disableLanguage('fr');
$this->configureContentType();
$this->login($this->getTranslatorUser());
}
/**
* Test disabled languages.
*
* Make sure disabled languages are not accessible in the language list when
* the option entity_translation_languages_enabled is enabled.
*/
function testDisabledLanguages() {
$this->drupalGet('node/add/page');
$this->assertRaw('value="fr"', 'French is available even if the language is disabled');
variable_set('entity_translation_languages_enabled', TRUE);
$this->drupalGet('node/add/page');
$this->assertNoRaw('value="fr"', 'French is not available when the language is disabled and the option entity_translation_languages_enabled is enabled.');
}
/**
* Test if field based translation works.
*
@@ -525,3 +557,788 @@ class EntityTranslationHookTestCase extends EntityTranslationTestCase {
return $info;
}
}
/**
* Tests that entity translation handler hierarchy works properly.
*/
class EntityTranslationHierarchyTestCase extends EntityTranslationTestCase {
/**
* Return the test information.
*/
public static function getInfo() {
return array(
'name' => 'Entity translation hierarchy',
'description' => 'Tests that entity translation handler hierarchy works properly.',
'group' => 'Entity translation',
);
}
/**
* {@inheritdoc}
*/
function setUp() {
parent::setUp('locale', 'entity_translation');
}
/**
* Tests the handler hierarchy.
*/
public function testHierarchy() {
$entity_type = 'node';
$node = $this->drupalCreateNode();
$factory = EntityTranslationHandlerFactory::getInstance();
$handler = $factory->getHandler($entity_type, $node);
$children = array();
foreach (range(0, 4) as $index) {
$children[$index] = $this->drupalCreateNode();
$handler->addChild($entity_type, $children[$index]);
}
$langcode = 'it';
$handler->setActiveLanguage($langcode);
foreach ($children as $child) {
$child_handler = $factory->getHandler($entity_type, $child);
$this->assertEqual($child_handler->getActiveLanguage(), $langcode);
}
$rm_index = mt_rand(0, count($children) - 1);
$handler->removeChild($entity_type, $children[$rm_index]);
$langcode = 'fr';
$handler->setActiveLanguage($langcode);
foreach ($children as $index => $child) {
$child_handler = $factory->getHandler($entity_type, $child);
$this->assertEqual($child_handler->getActiveLanguage() == $langcode, $index != $rm_index);
}
// @todo Test the other properties.
}
}
/**
* Basic tests for nodes using both content and entity translation.
*/
class EntityTranslationContentTranslationTestCase extends EntityTranslationTestCase {
/**
* Return the test information.
*/
public static function getInfo() {
return array(
'name' => 'Content and entity translation',
'description' => 'Basic tests for nodes using both content and entity translatio.',
'group' => 'Entity translation',
);
}
/**
* {@inheritdoc}
*/
public function setUp() {
// Activate modules and unset users.
parent::setUp('locale', 'translation', 'translation_test', 'entity_translation');
// Create admin and translator users with one extra permission,
// namely the 'translate content' permission.
// These getters works also as setters.
$this->getAdminUser(array(
'translate content',
));
$this->getTranslatorUser(array(
'translate content',
));
$this->login($this->getAdminUser());
$this->addLanguage('en');
$this->addLanguage('es');
$this->enableUrlLanguageDetection();
$this->configureContentType();
$this->login($this->getTranslatorUser());
}
/**
* Configure the "Basic page" content type for entity translation tests.
*/
public function configureContentType() {
// Configure the "Basic page" content type to use multilingual support with
// content translation.
$edit = array();
$edit['language_content_type'] = TRANSLATION_ENABLED;
$this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
// Toggle body field's translatability.
$edit = array();
$edit['field[translatable]'] = 1;
$this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
$this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));
}
/**
* @see TranslationTestCase::createPage()
*/
function createPage($title, $body, $language = NULL) {
$edit = array();
$langcode = LANGUAGE_NONE;
$edit["title"] = $title;
$edit["body[$langcode][0][value]"] = $body;
if (!empty($language)) {
$edit['language'] = $language;
}
$this->drupalPost('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Basic page created.');
// Check to make sure the node was created.
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node, 'Node found in database.');
return $node;
}
/**
* Tests copying of source node's body value in the add translation form page.
*/
public function testCopyFieldsUsingContentTranslation() {
// Create Basic page in English.
$node_title = $this->randomName();
$node_body = $this->randomName();
$node = $this->createPage($node_title, $node_body, 'en');
// Check that the edit form correctly copies over the field's values from
// the source node.
$target_language = 'es';
$this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $target_language)));
$body_key = "body[${target_language}][0][value]";
$this->assertFieldByXPath("//textarea[@name='$body_key']", $node_body, "Body field correctly instantiated with the value of the source language.");
}
}
/**
* Tests for integration of Entity Translation with other modules.
*/
class EntityTranslationIntegrationTestCase extends EntityTranslationTestCase {
/**
* Return the test information.
*/
public static function getInfo() {
return array(
'name' => 'Integration with other modules',
'description' => 'Tests for integration of Entity Translation with other modules.',
'group' => 'Entity translation',
// We need to add this to the test_dependencies[] as well.
'dependencies' => array('pathauto'),
);
}
/**
* {@inheritdoc}
*/
public function setUp() {
// Activate modules.
parent::setUp('locale', 'entity_translation');
// Create admin and translator users with one extra permission,
// namely the 'administer content' permission for the admin, to
// allow enabling the pathauto module during testing. The
// Translator user needs to be able to create url aliases.
$this->getAdminUser(array(
'administer modules',
));
$this->getTranslatorUser(array(
'create url aliases',
));
$this->login($this->getAdminUser());
$this->addLanguage('en');
$this->addLanguage('es');
$this->enableUrlLanguageDetection();
$this->configureContentType();
$this->login($this->getTranslatorUser());
}
/**
* Returns the role id of an $account object.
*/
protected function getUserRole($account) {
return reset($account->roles);
}
/**
* Tests Pathauto integration.
*/
public function testPathautoIntegration() {
$languages = language_list();
// Enable the path module to add aliases manually.
$this->login($this->getAdminUser());
if (!module_exists('path')) {
module_enable(array('path'));
}
$this->login($this->getTranslatorUser());
// Create Basic page in English.
$node_title = $this->randomName();
$node_body = $this->randomName();
$node = $this->createPage($node_title, $node_body, 'en');
$node_alias = $this->randomName();
$edit = array(
'path[alias]' => $node_alias,
);
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
// Submit translation in Spanish.
$node_translation_body = $this->randomName();
$this->createTranslation($node, $node_title, $node_translation_body, 'es');
$node_translation_alias = $this->randomName();
$edit = array(
'path[alias]' => $node_translation_alias,
);
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'), array('language' => $languages['es']));
// Enable the pathauto module.
$this->login($this->getAdminUser());
if (!module_exists('pathauto')) {
module_enable(array('pathauto'));
}
$admin_rid = $this->getUserRole($this->getAdminUser());
user_role_grant_permissions($admin_rid, array('administer url aliases', 'administer pathauto'));
$translator_rid = $this->getUserRole($this->getTranslatorUser());
user_role_grant_permissions($translator_rid, array('create url aliases'));
$this->login($this->getTranslatorUser());
// Create pathauto alias for source node.
$edit = array(
'path[pathauto]' => TRUE,
);
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
// Clear the static caches in case they interfere.
drupal_lookup_path('wipe');
$node_pathauto_alias = pathauto_node_update_alias($node, 'return');
$node_translation_pathauto_alias = pathauto_node_update_alias($node, 'return', array('language' => 'es'));
// Check that the new alias for the translation matches the
// pathauto's logic.
$this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_pathauto_alias), array('absolute' => TRUE)));
// Check that a pathauto alias was created for the source and
// matches the pathauto's logic.
$this->drupalGet('node/' . $node->nid, array('language' => $languages['es']));
$this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_translation_pathauto_alias), array('absolute' => TRUE, 'language' => $languages['es'])));
// Delete the two aliases.
path_delete(array('source' => 'node/' . $node->nid));
// Create pathauto alias for the translation of the node.
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'), array('language' => $languages['es']));
// Clear the static caches in case they interfere.
drupal_lookup_path('wipe');
$node_pathauto_alias = pathauto_node_update_alias($node, 'return');
$node_translation_pathauto_alias = pathauto_node_update_alias($node, 'return', array('language' => 'es'));
// Check that the new alias for the translation matches the
// pathauto's logic.
$this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_translation_pathauto_alias), array('absolute' => TRUE, 'language' => $languages['es'])));
// Check that a pathauto alias was created for the source and
// matches the pathauto's logic.
$this->drupalGet('node/' . $node->nid);
$this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_pathauto_alias), array('absolute' => TRUE)));
}
}
/**
* Tests for enabling fields to use Entity Translation or disabling them.
*/
class EntityTranslationToggleFieldsTranslatabilityTestCase extends EntityTranslationTestCase {
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Fields translatability toggling',
'description' => 'Tests for enabling fields to use Entity Translation or disabling them.',
'group' => 'Entity translation',
);
}
/**
* {@inheritdoc}
*/
public function setUp() {
// Activate modules.
parent::setUp('locale', 'taxonomy', 'entity_translation', 'entity_translation_test');
$this->login($this->getAdminUser(array(
'administer taxonomy',
'toggle field translatability',
)));
$this->login($this->getTranslatorUser(array(
'administer taxonomy',
)));
}
/**
* Configure the "Basic page" content type for entity translation tests.
*/
protected function configureContentTypeForRevisions() {
// Configure the "Basic page" content type to use revisions.
$edit = array(
'node_options[revision]' => 1,
);
$this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
}
/**
* Create a "Basic page" in the specified language.
*
* @param $title
* Title of the basic page in the specified language.
* @param $body
* Body of the basic page in the specified language.
*/
protected function createUntranslatedPage($title, $body) {
$edit = array(
'title' => $title,
'body[und][0][value]' => $body,
);
$this->drupalPost('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));
// Check to make sure the node was created.
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node, t('Node found in database.'));
return $node;
}
/**
* Create a "Tags" term in the specified language.
*
* @param $name
* Name of the term.
* @param $description
* Description of the term.
* @param $text
* Content for the field_simple_text field.
*/
protected function createUntranslatedTag($name, $description, $text) {
$edit = array(
'name' => $name,
'description[value]' => $description,
"field_simple_text[und][0][value]" => $text,
);
$this->drupalPost('admin/structure/taxonomy/tags/add', $edit, t('Save'));
// Check to make sure the term was created.
$term = current(entity_load('taxonomy_term', FALSE, array('name' => $name), TRUE));
$this->assertTrue($term, t('Term found in database.'));
return $term;
}
/**
* Tests toggling translatability on fields with data (non-revisionable).
*/
public function testTogglingFieldsWithDataNonRevisionable() {
// Create an untranslated Basic page.
$node_title = $this->randomName();
$node_body = $this->randomName();
$node = $this->createUntranslatedPage($node_title, $node_body);
$this->assert(isset($node->body[LANGUAGE_NONE]), t('Found body field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
// Create an untranslated Tags term.
$term_name = $this->randomName();
$term_description = $this->randomName();
$term_simple_text = $this->randomName();
$term = $this->createUntranslatedTag($term_name, $term_description, $term_simple_text);
$this->assert(isset($term->field_simple_text[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($term->field_simple_text[LANGUAGE_NONE][0]['value'], $term_simple_text);
// Enable translation for field body and check field migration.
$this->login($this->getAdminUser());
$this->drupalGet('admin/structure/types/manage/page/fields/body');
$this->clickLink('Enable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
$node = current(entity_load('node', FALSE, array('title' => $node_title), TRUE));
$this->assert(isset($node->body['en']), t('Found field data in English as expected.'));
$this->assertEqual($node->body['en'][0]['value'], $node_body);
$this->assert(!isset($node->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
// Disable translation for body field and check field reverse migration.
$this->drupalGet('admin/structure/types/manage/page/fields/body');
$this->clickLink('Disable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
$node = current(entity_load('node', FALSE, array('title' => $node_title), TRUE));
$this->assert(isset($node->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
$this->assert(!isset($node->body['en']), t('No field data in English found.'));
// Enable translation for field_simple_text and check field migration.
$this->drupalGet('admin/structure/taxonomy/tags/fields/field_simple_text');
$this->clickLink('Enable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
// Clear the field cache in order to load current field data.
field_info_cache_clear();
// Load the term and check that the fields data are under 'en'.
$term = current(entity_load('taxonomy_term', FALSE, array('name' => $term_name), TRUE));
$this->assert(isset($term->field_simple_text['en']), t('Found field data in English as expected.'));
$this->assertEqual($term->field_simple_text['en'][0]['value'], $term_simple_text);
$this->assert(!isset($term->field_simple_text[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
// Disable translation for field_simple_text.
$this->drupalGet('admin/structure/taxonomy/tags/fields/field_simple_text');
$this->clickLink('Disable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
// Load the term and check that the fields data are under LANGUAGE_NONE.
$term = current(entity_load('taxonomy_term', FALSE, array('name' => $term_name), TRUE));
$this->assert(isset($term->field_simple_text[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($term->field_simple_text[LANGUAGE_NONE][0]['value'], $term_simple_text);
$this->assert(!isset($term->field_simple_text['en']), t('No field data in English found.'));
}
/**
* Tests toggling translatability on fields with data (revisionable).
*/
public function testTogglingFieldsWithDataRevisionable() {
// Enable revisions for Basic pages.
$this->login($this->getAdminUser());
$this->configureContentTypeForRevisions();
// Create an untranslated Basic page.
$this->login($this->getTranslatorUser());
$node_title = $this->randomName();
$node_body = $this->randomName();
$node = $this->createUntranslatedPage($node_title, $node_body);
$this->assert(isset($node->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
// Create a new revision for the page.
$edit_revision = array(
'title' => $this->randomName(),
);
$this->drupalPost('node/' . $node->nid . '/edit', $edit_revision, t('Save'));
$node = node_load($node->nid, NULL, TRUE);
$this->assert($node->vid == $node->nid + 1, t('Correct vid attached to the node object.'));
// Enable translation for field body and check field migration on all
// revisions.
$this->login($this->getAdminUser());
$this->drupalGet('admin/structure/types/manage/page/fields/body');
$this->clickLink('Enable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
$node_current_revision = current(entity_load('node', FALSE, array('vid' => $node->vid), TRUE));
$this->assert(isset($node_current_revision->body['en']), t('Found field data in English as expected.'));
$this->assertEqual($node_current_revision->body['en'][0]['value'], $node_body);
$this->assert(!isset($node_current_revision->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
$node_previous_revision = current(entity_load('node', FALSE, array('vid' => ($node->vid - 1)), TRUE));
$this->assert(isset($node_previous_revision->body['en']), t('Found field data in English as expected.'));
$this->assertEqual($node_previous_revision->body['en'][0]['value'], $node_body);
$this->assert(!isset($node_previous_revision->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
// Disable translation for field_body.
$this->drupalGet('admin/structure/types/manage/page/fields/body');
$this->clickLink('Disable translation');
$this->drupalPost(NULL, array(), t('Confirm'));
// Disable translation for field body and check field reverse migration on
// all revisions.
$node_current_revision = current(entity_load('node', FALSE, array('vid' => $node->vid), TRUE));
$this->assert(isset($node_current_revision->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($node_current_revision->body[LANGUAGE_NONE][0]['value'], $node_body);
$this->assert(!isset($node_current_revision->body['en']), t('No field data in English found.'));
$node_previous_revision = current(entity_load('node', FALSE, array('vid' => ($node->vid - 1)), TRUE));
$this->assert(isset($node_previous_revision->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
$this->assertEqual($node_previous_revision->body[LANGUAGE_NONE][0]['value'], $node_body);
$this->assert(!isset($node_previous_revision->body['en']), t('No field data in English found.'));
}
}
/**
* Tests for the taxonomy autocomplete translation modes.
*/
class EntityTranslationTaxonomyAutocompleteTestCase extends EntityTranslationTestCase {
/**
* Returns the test information.
*/
public static function getInfo() {
return array(
'name' => 'Entity translation taxonomy autocomplete',
'description' => 'Tests for the taxonomy autocomplete translation modes.',
'group' => 'Entity translation',
'dependencies' => array('title'),
);
}
/**
* {@inheritdoc}
*/
function setUp() {
parent::setUp('locale', 'entity_translation', 'taxonomy', 'title');
$this->login($this->getAdminUser(array(
'administer taxonomy',
'administer entity translation',
)));
$this->addLanguage('en');
$this->addLanguage('it');
$this->addLanguage('fr');
$this->enableUrlLanguageDetection();
$this->configureVocabulary();
$this->configureContentType();
}
/**
* Makes the "Tags" vocabulary translatable.
*/
function configureVocabulary() {
$edit = array(
'entity_translation_entity_types[taxonomy_term]' => TRUE,
);
$this->drupalPost('admin/config/regional/entity_translation', $edit, t('Save configuration'));
$edit = array(
'entity_translation_taxonomy' => TRUE,
);
$this->drupalPost('admin/structure/taxonomy/tags/edit', $edit, t('Save'));
$edit = array(
'enabled' => TRUE,
);
$this->drupalPost('admin/structure/taxonomy/tags/fields/replace/name', $edit, t('Save settings'));
$edit = array(
'enabled' => TRUE,
);
$this->drupalPost('admin/structure/taxonomy/tags/fields/replace/description', $edit, t('Save settings'));
}
/**
* {@inheritdoc}
*/
function configureContentType() {
parent::configureContentType();
// Create an untranslatable term reference field with unlimited cardinality.
$edit = array(
'fields[_add_new_field][label]' => 'Test tags',
'fields[_add_new_field][field_name]' => 'test_tags',
'fields[_add_new_field][type]' => 'taxonomy_term_reference',
'fields[_add_new_field][widget_type]' => 'taxonomy_autocomplete',
);
$this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
$edit = array(
'field[settings][allowed_values][0][vocabulary]' => 'tags',
);
$this->drupalPost('admin/structure/types/manage/page/fields/field_test_tags/field-settings', $edit, t('Save field settings'));
// Verify the in-place translation option is available.
$this->drupalGet('admin/structure/types/manage/page/fields/field_test_tags');
$this->assertRaw(t('Enable in-place translation of terms'));
$edit = array(
'field[cardinality]' => FIELD_CARDINALITY_UNLIMITED,
);
$this->drupalPost(NULL, $edit, t('Save settings'));
// Ensure entity info is up-to-date.
drupal_flush_all_caches();
}
/**
* Enables in-place translation.
*/
function enableInPlaceTranslation() {
$edit = array(
'instance[settings][entity_translation_taxonomy_autocomplete_translate]' => TRUE,
);
$this->drupalPost('admin/structure/types/manage/page/fields/field_test_tags', $edit, t('Save settings'));
}
/**
* Tests that in-place translation works as expected.
*/
function testInPlaceTranslation() {
$this->enableInPlaceTranslation();
$this->login($this->getTranslatorUser(array(
'administer taxonomy',
)));
$values = array(
'Red' => 'Rosso',
'Green' => 'Verde',
'Blue' => 'Blu',
);
// Create an English node with a few new tags.
$edit = array(
'title' => 'Test 1',
'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', array_keys($values)),
'language' => 'en',
);
$this->drupalPost('node/add/page', $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($edit['title']);
// Create an Italian translation and translate the English tags.
$this->drupalGet('node/' . $node->nid . '/translate');
$this->clickLink('add', 1);
$edit = array();
foreach (array_values($values) as $delta => $value) {
$edit['field_test_tags[' . LANGUAGE_NONE . '][' . $delta . ']'] = $value;
}
$this->drupalPost(NULL, $edit, t('Save'));
// Verify that the Italian values are correctly stored/displayed.
foreach ($values as $original => $translation) {
$this->assertRaw($translation);
}
// Verify that the original English values were correctly retained.
$this->drupalGet('node/' . $node->nid);
foreach ($values as $original => $translation) {
$this->assertRaw($original);
}
}
/**
* That the autocomplete works with translated terms.
*/
function testTranslatedAutocomplete() {
$this->login($this->getTranslatorUser(array(
'administer taxonomy',
)));
$vocabulary = taxonomy_vocabulary_machine_name_load('tags');
$entity_type = 'taxonomy_term';
$existing_values = array();
$translated_values = array(
'en' => array(
'Red' => 'Rosso',
'Green' => 'Verde',
),
'it' => array(
'Blu' => 'Blue',
),
);
$langcodes = array_keys($translated_values);
// Create a few existing tags with different original language and translate
// them accordingly.
foreach ($translated_values as $langcode => $values) {
title_active_language($langcode);
$translation_langcode = current(array_diff($langcodes, array($langcode)));
foreach ($values as $original => $translation) {
$term = (object) array(
'vid' => $vocabulary->vid,
'vocabulary_machine_name' => $vocabulary->machine_name,
'name' => $original,
'name_field' => array(
$langcode => array(array('value' => $original)),
$translation_langcode => array(array('value' => $translation)),
),
);
$translation = array(
'language' => $translation_langcode,
'source' => $langcode,
'status' => TRUE,
);
$handler = entity_translation_get_handler($entity_type, $term);
$handler->setOriginalLanguage($langcode);
$handler->initTranslations();
$handler->setTranslation($translation);
taxonomy_term_save($term);
$existing_values[$term->name_field['en'][0]['value']] = $term->name_field['it'][0]['value'];
}
}
// Verify that the English autocomplete route returns results for terms
// originally created in English.
$this->autocompleteGet('en', 'Re');
$this->assertRaw('Red');
$this->assertRaw('Green');
// Verify that the English autocomplete route returns results for terms
// translated into English.
$this->autocompleteGet('en', 'Blu');
$this->assertRaw('Blue');
// Verify that the Italian autocomplete route returns results for terms
// originally created in Italian.
$this->autocompleteGet('it', 'Blu');
$this->assertRaw('Blu');
$this->assertNoRaw('Blue');
// Verify that the Italian autocomplete route returns results for terms
// translated into Italian.
$this->autocompleteGet('it', 'R');
$this->assertRaw('Rosso');
$this->assertRaw('Verde');
// Verify that existing tags are correctly referenced and new tags are
// correctly created, when saving an English node.
$new_values = array(
'Cyan' => 'Ciano',
'Magenta' => 'Magenta',
'Yellow' => 'Giallo',
'Black' => 'Nero',
);
$all_values = $existing_values + $new_values;
$edit = array(
'title' => 'Test 1',
'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', array_keys($all_values)),
'language' => 'en',
);
$this->drupalPost('node/add/page', $edit, t('Save'));
foreach ($all_values as $original => $translation) {
$this->assertRaw($original);
}
// Verify that existing translated tags are correctly referenced and new
// tags are correctly created, when translated the node into Italian.
$node = $this->drupalGetNodeByTitle($edit['title']);
$this->drupalGet('node/' . $node->nid . '/translate');
$this->clickLink('add', 1);
$edit = array(
'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', $all_values),
);
$this->drupalPost(NULL, $edit, t('Save'));
foreach ($all_values as $original => $translation) {
$this->assertRaw($translation);
}
// Verify that existing (translated) tags were preserved, while new Italian
// tags replaced the corresponding English versions.
$this->drupalGet('node/' . $node->nid);
foreach ($existing_values as $original => $translation) {
$this->assertRaw($original);
}
foreach ($new_values as $original => $translation) {
$this->assertRaw($translation);
}
}
/**
* Performs a GET request to the autocomplete path.
*
* @param string $langcode
* The language to use to query results.
* @param string $query
* The search query string.
*/
protected function autocompleteGet($langcode, $query) {
$path = 'entity_translation/taxonomy_term/autocomplete/' . $langcode . '/field_test_tags/' . $query;
$languages = language_list();
$this->drupalGet($path, array('language' => $languages[$langcode]));
}
}

View File

@@ -4,11 +4,11 @@ core = 7.x
package = Testing
hidden = TRUE
dependencies[] = entity_translation
files[] = entity_translation_test.module
; Information added by Drupal.org packaging script on 2016-09-28
version = "7.x-1.0-beta5+15-dev"
; Information added by Drupal.org packaging script on 2019-01-20
version = "7.x-1.0+5-dev"
core = "7.x"
project = "entity_translation"
datestamp = "1475057941"
datestamp = "1548022384"

View File

@@ -5,3 +5,34 @@
* Installation functionality for Entity Translation testing module.
*/
/**
* Implements hook_install().
*/
function entity_translation_test_install() {
// Create a simple text field, attached to taxonomy_terms.
field_info_cache_clear();
$field = array(
'field_name' => 'field_simple_text',
'type' => 'text',
'cardinality' => 1,
);
field_create_field($field);
$instance = array(
'field_name' => $field['field_name'],
'label' => ucfirst(str_replace('_', ' ', $field['field_name'])),
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'widget' => array(
'type' => 'text_textfield',
),
'display' => array(
'default' => array(
'type' => 'text_default',
),
),
);
field_create_instance($instance);
}

View File

@@ -1,7 +1,8 @@
<?php
/**
* @file
* Contains the relationship plugin for relating entities to translation metadata.
* Contains a views plugin for relating entities to translation metadata.
*/
/**
@@ -27,7 +28,10 @@ class entity_translation_handler_relationship extends views_handler_relationship
$alias = $def['table'] . '_' . $this->table;
// We need to add a condition on entity type to the join to avoid getting
// relationships to entities with other types.
$join->extra = "$alias.entity_type = '{$def['entity type']}'";
$join->extra = array(
array('field' => 'entity_type', 'value' => $def['entity type']),
);
$this->alias = $this->query->add_relationship($alias, $join, 'entity_translation', $this->relationship);
}
}