diff --git a/entity_translation.module b/entity_translation.module index 053d39d..3c4645e 100644 --- a/entity_translation.module +++ b/entity_translation.module @@ -190,10 +190,34 @@ function entity_translation_menu() { 'file' => 'entity_translation.admin.inc', ); + // $items['entity_translation/warning'] = array( + // 'title' => 'Change translatability', + // 'description' => 'Force user confirm before converting/deleting field data.', + // 'page callback' => 'drupal_get_form', + // 'page arguments' => array('entity_translation_translatable_warn'), + // 'access arguments' => array('administer entity translation'), + // 'type' => MENU_CALLBACK, + // ); return $items; } /** + * Warning page for translatability conversion. + */ +// function entity_translation_translatable_warn(&$form, &$form_state) { +// $question = t('Making a field untranslatable will result in all translations of that field being deleted. Only the original content will be preserved. Are you sure you want to continue?'); +// $description = t('This action cannot be undone'); +// $path = ''; +// $yes = t('Convert'); +// $no = t('Cancel'); +// $form = confirm_form($form, $question, '', $description, $yes, $no); +// +// $form['#submit'] = 'entity_translation_translatable_submit'; +// +// return $form; +// } + +/** * Implements hook_admin_paths(). */ function entity_translation_admin_paths() { @@ -465,11 +489,164 @@ function entity_translation_edit_form_submit($form, &$form_state) { function entity_translation_form_field_ui_field_settings_form_alter(&$form, $form_state) { $instance = $form_state['build_info']['args'][0]; $field = field_info_field($instance['field_name']); + $form['field']['translatable'] = array( '#type' => 'checkbox', '#title' => t('Users may translate this field.'), '#default_value' => $field['translatable'], ); + + $form['field']['warning'] = array( + '#type' => 'container', + '#states' => array( + 'visible' => array( + ':input[name="field[translatable]"]' => array('checked' => !$field['translatable']), + ), + ), + ); + + $warning = t('By submitting this form you will trigger a batch operation.'); + if ($field['translatable']) { + // Once the confirm page is finished, we can drop the extra warning text. + // $form_state['redirect'][] = 'entity_translation/warning'; + $warning .= ' ' . t(' All translations of this field will be deleted. . Please backup your data before proceeding.'); + } + $form['field']['warning']['warning'] = array( + '#markup' => '
' . $warning . '
', + ); + + // Make sure translations are removed before the field is made untranslatable. + if (!isset($form['#submit'])) { + $form['#submit'] = array(); + } + if ($field['translatable']) { + array_unshift($form['#submit'], 'entity_translation_translatable_submit'); + } + else { + $form['#submit'][] = 'entity_translation_translatable_submit'; + } +} + +/** + * Submit handler for the field settings form. + * + * This submit handler maintains consistency between the translatability of an + * entity and the language under which the field data is stored. When a field is + * marked as translatable, all the data in $entity->{field_name}[LANGUAGE_NONE] + * is moved to $entity->{field_name}[$entity_language]. When a field is marked + * as untranslatable the opposite process occurs. Note that marking a field as + * untranslatable will cause all of its translations to be permanently removed, + * with the exception of the one corresponding to the entity language. + */ +function entity_translation_form_translatable_submit($form, &$form_state) { + $translatable = $form_state['values']['field']['translatable']; + $previous = $form['field']['translatable']['#default_value']; + + if ($previous == $translatable) { + // Nothing to do. + return; + } + + $field_name = $form_state['values']['field']['field_name']; + + $batch = array( + 'title' => t('Converting'), + 'operations' => array( + array('entity_translation_translatable_batch', array($translatable, $field_name)), + ), + 'finished' => 'entity_translation_translatable_batch_done', + ); + + batch_set($batch); +} + +/** + * Batch operation. Switch the translatability of the given field. + */ +function entity_translation_translatable_batch($make_translatable, $field_name, &$context) { + if (empty($context['sandbox'])) { + $context['sandbox']['progress'] = 0; + + // How many entities will need processing? + $query = new EntityFieldQuery(); + $count = $query + ->fieldCondition($field_name) + ->count() + ->execute(); + + if ($count === 0) { + // Nothing to do. + $context['finished'] = 1; + return; + } + + $context['sandbox']['max'] = $count; + } + + // Number of entities to be processed for each step. + $limit = 10; + + $query = new EntityFieldQuery(); + $result = $query + ->fieldCondition($field_name) + ->range($context['sandbox']['progress'], $limit) + ->execute(); + + foreach ($result as $entity_type => $entities) { + foreach (entity_load($entity_type, array_keys($entities)) as $id => $entity) { + $context['sandbox']['progress']++; + $langcode = entity_translation_get_handler($entity_type, $entity)->getLanguage(); + + if ($make_translatable && isset($entity->{$field_name}[LANGUAGE_NONE])) { + // If the field being switched to translatable and has data for + // LANGUAGE_NONE, setting this to an empty array() will cause the item + // to be deleted. + $entity->{$field_name}[$langcode] = $entity->{$field_name}[LANGUAGE_NONE]; + $entity->{$field_name}[LANGUAGE_NONE] = array(); + } + elseif (!$make_translatable && isset($entity->{$field_name}[$langcode])) { + // The field has been marked untranslatable and has data in the entity + // language: we need to move it to LANGUAGE_NONE and drop the other + // translations. + $data = $entity->{$field_name}[$langcode]; + // Remove all translations of the field data. + foreach ($entity->{$field_name} as $langcode => $items) { + $entity->{$field_name}[$langcode] = array(); + } + // Move the original field data to LANGUAGE_NONE + $entity->{$field_name}[LANGUAGE_NONE] = $data; + } + else { + // Nno need to save unchanged entities. + continue; + } + + // Save field data. + field_attach_update($entity_type, $entity); + } + } + + $context['finished'] = $context['sandbox']['progress']/$context['sandbox']['max']; + + // Workaround for http://drupal.org/node/1300928. + // If the batch op runs first, then by the time the core field submit handler + // gets called, its code is out of scope. + if ($context['finished'] >= 1) { + module_load_include('inc', 'field_ui', 'field_ui.admin'); + } +} + +/** + * Check the exit status of the batch operation, and possibly resubmit the changed translatable status. + */ +function entity_translation_translatable_batch_done($success, $results, $operations) { + if ($success) { + drupal_set_message(t("Data successfully converted.")); + } + else { + // TODO: Do something about this case. + drupal_set_message(t("Something went wrong when converting the data. Some nodes may appear to have lost fields.")); + } } /**