Commit 86e432e0 authored by catch's avatar catch

Issue #2143291 by plach, alexpott, xjm, effulgentsia, pwolanin, swentel |...

Issue #2143291 by plach, alexpott, xjm, effulgentsia, pwolanin, swentel | yched: Clarify handling of field translatability.
parent 0f752ca6
......@@ -14,13 +14,12 @@
use Drupal\Core\Entity\Schema\ContentEntitySchemaHandler;
use Drupal\Core\Entity\Sql\DefaultTableMapping;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\field\FieldConfigUpdateForbiddenException;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldConfigInterface;
use Drupal\field\FieldConfigUpdateForbiddenException;
use Drupal\field\FieldInstanceConfigInterface;
use Drupal\field\Entity\FieldConfig;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -239,11 +238,11 @@ protected function schemaHandler() {
public function getTableMapping() {
if (!isset($this->tableMapping)) {
$definitions = array_filter($this->getFieldStorageDefinitions(), function (FieldDefinitionInterface $definition) {
$definitions = array_filter($this->getFieldStorageDefinitions(), function (FieldStorageDefinitionInterface $definition) {
// @todo Remove the check for FieldDefinitionInterface::isMultiple() when
// multiple-value base fields are supported in
// https://drupal.org/node/2248977.
return !$definition->isComputed() && !$definition->hasCustomStorage() && !$definition->isMultiple();
return !$definition->hasCustomStorage() && !$definition->isMultiple();
});
$this->tableMapping = new DefaultTableMapping($definitions);
......@@ -956,10 +955,12 @@ protected function doLoadFieldItems($entities, $age) {
// Collect impacted fields.
$fields = array();
$definitions = array();
foreach ($bundles as $bundle => $v) {
foreach ($this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle) as $field_name => $instance) {
$definitions[$bundle] = $this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle);
foreach ($definitions[$bundle] as $field_name => $instance) {
if ($instance instanceof FieldInstanceConfigInterface) {
$fields[$field_name] = $instance->getField();
$fields[$field_name] = $instance->getFieldStorageDefinition();
}
}
}
......@@ -982,10 +983,11 @@ protected function doLoadFieldItems($entities, $age) {
$delta_count = array();
foreach ($results as $row) {
$bundle = $entities[$row->entity_id]->bundle();
// Ensure that records for non-translatable fields having invalid
// languages are skipped.
if ($row->langcode == $default_langcodes[$row->entity_id] || $field->isTranslatable()) {
if ($row->langcode == $default_langcodes[$row->entity_id] || $definitions[$bundle][$field_name]->isTranslatable()) {
if (!isset($delta_count[$row->entity_id][$row->langcode])) {
$delta_count[$row->entity_id][$row->langcode] = 0;
}
......@@ -1028,7 +1030,7 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) {
if (!($instance instanceof FieldInstanceConfigInterface)) {
continue;
}
$field = $instance->getField();
$field = $instance->getFieldStorageDefinition();
$table_name = static::_fieldTableName($field);
$revision_name = static::_fieldRevisionTableName($field);
......@@ -1105,7 +1107,7 @@ protected function doDeleteFieldItems(EntityInterface $entity) {
if (!($instance instanceof FieldInstanceConfigInterface)) {
continue;
}
$field = $instance->getField();
$field = $instance->getFieldStorageDefinition();
$table_name = static::_fieldTableName($field);
$revision_name = static::_fieldRevisionTableName($field);
$this->database->delete($table_name)
......@@ -1127,7 +1129,7 @@ protected function doDeleteFieldItemsRevision(EntityInterface $entity) {
if (!($instance instanceof FieldInstanceConfigInterface)) {
continue;
}
$revision_name = static::_fieldRevisionTableName($instance->getField());
$revision_name = static::_fieldRevisionTableName($instance->getFieldStorageDefinition());
$this->database->delete($revision_name)
->condition('entity_id', $entity->id())
->condition('revision_id', $vid)
......@@ -1258,7 +1260,7 @@ public function onFieldDelete(FieldConfigInterface $field) {
* {@inheritdoc}
*/
public function onInstanceDelete(FieldInstanceConfigInterface $instance) {
$field = $instance->getField();
$field = $instance->getFieldStorageDefinition();
$table_name = static::_fieldTableName($field);
$revision_name = static::_fieldRevisionTableName($field);
$this->database->update($table_name)
......@@ -1280,7 +1282,7 @@ public function onBundleRename($bundle, $bundle_new) {
// using the old bundle name.
$instances = entity_load_multiple_by_properties('field_instance_config', array('entity_type' => $this->entityTypeId, 'bundle' => $bundle, 'include_deleted' => TRUE));
foreach ($instances as $instance) {
$field = $instance->getField();
$field = $instance->getFieldStorageDefinition();
$table_name = static::_fieldTableName($field);
$revision_name = static::_fieldRevisionTableName($field);
$this->database->update($table_name)
......@@ -1298,7 +1300,7 @@ public function onBundleRename($bundle, $bundle_new) {
* {@inheritdoc}
*/
protected function readFieldItemsToPurge(EntityInterface $entity, FieldInstanceConfigInterface $instance) {
$field = $instance->getField();
$field = $instance->getFieldStorageDefinition();
$table_name = static::_fieldTableName($field);
$query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC))
->condition('entity_id', $entity->id())
......@@ -1313,7 +1315,7 @@ protected function readFieldItemsToPurge(EntityInterface $entity, FieldInstanceC
* {@inheritdoc}
*/
public function purgeFieldItems(EntityInterface $entity, FieldInstanceConfigInterface $instance) {
$field = $instance->getField();
$field = $instance->getFieldStorageDefinition();
$table_name = static::_fieldTableName($field);
$revision_name = static::_fieldRevisionTableName($field);
$this->database->delete($table_name)
......
......@@ -15,7 +15,7 @@
/**
* A class for defining entity fields.
*/
class FieldDefinition extends ListDataDefinition implements FieldDefinitionInterface {
class FieldDefinition extends ListDataDefinition implements FieldDefinitionInterface, FieldStorageDefinitionInterface {
/**
* The field type.
......@@ -253,7 +253,7 @@ public function getCardinality() {
* Sets the maximum number of items allowed for the field.
*
* Possible values are positive integers or
* FieldDefinitionInterface::CARDINALITY_UNLIMITED.
* FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
*
* @param int $cardinality
* The field cardinality.
......@@ -592,4 +592,11 @@ public function setCustomStorage($custom_storage) {
return $this;
}
/**
* {@inheritdoc}
*/
public function getFieldStorageDefinition() {
return $this;
}
}
......@@ -52,7 +52,28 @@
* based on that abstract definition, even though that abstract definition can
* differ from the concrete definition of any particular node's body field.
*/
interface FieldDefinitionInterface extends FieldStorageDefinitionInterface, ListDataDefinitionInterface {
interface FieldDefinitionInterface extends ListDataDefinitionInterface {
/**
* Returns the machine name of the field.
*
* This defines how the field data is accessed from the entity. For example,
* if the field name is "foo", then $entity->foo returns its data.
*
* @return string
* The field name.
*/
public function getName();
/**
* Returns the field type.
*
* @return string
* The field type, i.e. the id of a field type plugin. For example 'text'.
*
* @see \Drupal\Core\Field\FieldTypePluginManagerInterface
*/
public function getType();
/**
* Returns whether the display for the field can be configured.
......@@ -131,4 +152,29 @@ public function isRequired();
*/
public function getDefaultValue(ContentEntityInterface $entity);
/**
* Returns whether the field is translatable.
*
* @return bool
* TRUE if the field is translatable.
*/
public function isTranslatable();
/**
* Sets whether the field is translatable.
*
* @param bool $translatable
* Whether the field is translatable.
*
* @return $this
*/
public function setTranslatable($translatable);
/**
* Returns the field storage definition.
*
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface
* The field storage definition.
*/
public function getFieldStorageDefinition();
}
......@@ -7,12 +7,12 @@
namespace Drupal\Core\Field;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\Core\TypedData\Plugin\DataType\ItemList;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\TypedData\TypedDataInterface;
/**
* Represents an entity field; that is, a list of field item objects.
......@@ -285,8 +285,8 @@ public function getConstraints() {
// Check that the number of values doesn't exceed the field cardinality. For
// form submitted values, this can only happen with 'multiple value'
// widgets.
$cardinality = $this->getFieldDefinition()->getCardinality();
if ($cardinality != FieldDefinitionInterface::CARDINALITY_UNLIMITED) {
$cardinality = $this->getFieldDefinition()->getFieldStorageDefinition()->getCardinality();
if ($cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
$constraints[] = \Drupal::typedDataManager()
->getValidationConstraintManager()
->create('Count', array(
......
......@@ -77,13 +77,23 @@ public function getSettings();
public function getSetting($setting_name);
/**
* Returns whether the field is translatable.
* Returns whether the field supports translation.
*
* @return bool
* TRUE if the field is translatable.
* TRUE if the field supports translation.
*/
public function isTranslatable();
/**
* Sets whether the field supports translation.
*
* @param bool $translatable
* Whether the field supports translation.
*
* @return $this
*/
public function setTranslatable($translatable);
/**
* Returns whether the field is revisionable.
*
......@@ -193,8 +203,8 @@ public function getMainPropertyName();
* This method should not be confused with EntityInterface::entityType()
* (configurable fields are config entities, and thus implement both
* interfaces):
* - FieldDefinitionInterface::getTargetEntityTypeId() answers "as a field,
* which entity type are you attached to?".
* - FieldStorageDefinitionInterface::getTargetEntityTypeId() answers "as a
* field, which entity type are you attached to?".
* - EntityInterface::getEntityTypeId() answers "as a (config) entity, what
* is your own entity type".
*
......@@ -231,7 +241,7 @@ public function getSchema();
* The array of field columns, keyed by column name, in the same format
* returned by getSchema().
*
* @see \Drupal\Core\Field\FieldDefinitionInterface::getSchema()
* @see \Drupal\Core\Field\FieldStorageDefinitionInterface::getSchema()
*/
public function getColumns();
......
......@@ -61,21 +61,21 @@ public static function create($field_definition) {
* {@inheritdoc}
*/
public function getPropertyDefinition($name) {
return $this->fieldDefinition->getPropertyDefinition($name);
return $this->fieldDefinition->getFieldStorageDefinition()->getPropertyDefinition($name);
}
/**
* {@inheritdoc}
*/
public function getPropertyDefinitions() {
return $this->fieldDefinition->getPropertyDefinitions();
return $this->fieldDefinition->getFieldStorageDefinition()->getPropertyDefinitions();
}
/**
* {@inheritdoc}
*/
public function getMainPropertyName() {
return $this->fieldDefinition->getMainPropertyName();
return $this->fieldDefinition->getFieldStorageDefinition()->getMainPropertyName();
}
}
......@@ -142,12 +142,12 @@ public function form(FieldItemListInterface $items, array &$form, array &$form_s
*/
protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
$field_name = $this->fieldDefinition->getName();
$cardinality = $this->fieldDefinition->getCardinality();
$cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
$parents = $form['#parents'];
// Determine the number of widgets to display.
switch ($cardinality) {
case FieldDefinitionInterface::CARDINALITY_UNLIMITED:
case FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED:
$field_state = field_form_get_state($parents, $field_name, $form_state);
$max = $field_state['items_count'];
$is_multiple = TRUE;
......@@ -198,7 +198,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
'#theme' => 'field_multiple_value_form',
'#field_name' => $field_name,
'#cardinality' => $cardinality,
'#cardinality_multiple' => $this->fieldDefinition->isMultiple(),
'#cardinality_multiple' => $this->fieldDefinition->getFieldStorageDefinition()->isMultiple(),
'#required' => $this->fieldDefinition->isRequired(),
'#title' => $title,
'#description' => $description,
......@@ -206,7 +206,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
);
// Add 'add more' button, if not working with a programmed form.
if ($cardinality == FieldDefinitionInterface::CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
$id_prefix = implode('-', array_merge($parents, array($field_name)));
$wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
......@@ -264,7 +264,7 @@ public static function addMoreAjax(array $form, array $form_state) {
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
// Ensure the widget allows adding additional items.
if ($element['#cardinality'] != FieldDefinitionInterface::CARDINALITY_UNLIMITED) {
if ($element['#cardinality'] != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
return;
}
......
......@@ -6,10 +6,10 @@
*/
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Element;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldInstanceConfigInterface;
/**
......@@ -79,7 +79,9 @@ function _content_translation_form_language_content_settings_form_alter(array &$
$dependent_options_settings = array();
$entity_manager = Drupal::entityManager();
foreach ($form['#labels'] as $entity_type_id => $label) {
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
$entity_type = $entity_manager->getDefinition($entity_type_id);
$storage_definitions = $entity_type instanceof ContentEntityTypeInterface ? $entity_manager->getFieldStorageDefinitions($entity_type_id) : array();
foreach (entity_get_bundles($entity_type_id) as $bundle => $bundle_info) {
// Here we do not want the widget to be altered and hold also the "Enable
// translation" checkbox, which would be redundant. Hence we add this key
......@@ -98,44 +100,33 @@ function _content_translation_form_language_content_settings_form_alter(array &$
$field_settings = content_translation_get_config($entity_type_id, $bundle, 'fields');
foreach ($fields as $field_name => $definition) {
$translatable = !empty($field_settings[$field_name]);
// We special case Field API fields as they always natively support
// translation.
// @todo Remove this special casing as soon as configurable and
// base field definitions are "unified".
if ($definition instanceof FieldInstanceConfigInterface) {
// Allow to configure only fields supporting multilingual storage.
if (!empty($storage_definitions[$field_name]) && $storage_definitions[$field_name]->isTranslatable()) {
$form['settings'][$entity_type_id][$bundle]['fields'][$field_name] = array(
'#label' => $definition->getLabel(),
'#type' => 'checkbox',
'#default_value' => $translatable,
'#default_value' => $definition->isTranslatable(),
);
$column_element = content_translation_field_sync_widget($definition);
if ($column_element) {
$form['settings'][$entity_type_id][$bundle]['columns'][$field_name] = $column_element;
// @todo This should not concern only files.
if (isset($column_element['#options']['file'])) {
$dependent_options_settings["settings[{$entity_type_id}][{$bundle}][columns][{$field_name}]"] = array('file');
// Display the column translatability configuration widget.
// @todo Remove this special casing when arbitrary settings can be
// stored for any field. See https://drupal.org/node/2224761.
if ($definition instanceof FieldInstanceConfigInterface) {
$column_element = content_translation_field_sync_widget($definition);
if ($column_element) {
$form['settings'][$entity_type_id][$bundle]['columns'][$field_name] = $column_element;
// @todo This should not concern only files.
if (isset($column_element['#options']['file'])) {
$dependent_options_settings["settings[{$entity_type_id}][{$bundle}][columns][{$field_name}]"] = array('file');
}
}
}
}
// Instead we need to rely on field definitions to determine whether
// fields support translation. Whether they are actually enabled is
// determined through our settings. As a consequence only fields
// that support translation can be enabled or disabled.
elseif (isset($field_settings[$field_name]) || $definition->isTranslatable()) {
$form['settings'][$entity_type_id][$bundle]['fields'][$field_name] = array(
'#label' => $definition->getLabel(),
'#type' => 'checkbox',
'#default_value' => $translatable,
);
}
}
}
}
}
}
$settings = array('dependent_selectors' => $dependent_options_settings);
$form['#attached']['js'][] = array('data' => array('contentTranslationDependentOptions' => $settings), 'type' => 'setting');
$form['#validate'][] = 'content_translation_form_language_content_settings_validate';
......@@ -300,68 +291,40 @@ function content_translation_form_language_content_settings_submit(array $form,
// If an entity type is not translatable all its bundles and fields must be
// marked as non-translatable. Similarly, if a bundle is made non-translatable
// all of its fields will be not translatable.
foreach ($settings as $entity_type => &$entity_settings) {
foreach ($entity_settings as &$bundle_settings) {
foreach ($settings as $entity_type_id => &$entity_settings) {
foreach ($entity_settings as $bundle => &$bundle_settings) {
if (!empty($bundle_settings['translatable'])) {
$bundle_settings['translatable'] = $bundle_settings['translatable'] && $entity_types[$entity_type];
$bundle_settings['translatable'] = $bundle_settings['translatable'] && $entity_types[$entity_type_id];
}
if (!empty($bundle_settings['fields'])) {
$definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type_id, $bundle);
foreach ($bundle_settings['fields'] as $field_name => $translatable) {
$bundle_settings['fields'][$field_name] = $translatable && $bundle_settings['translatable'];
$translatable = $translatable && $bundle_settings['translatable'];
// If we have column settings and no column is translatable, no point
// in making the field translatable.
if (isset($bundle_settings['columns'][$field_name]) && !array_filter($bundle_settings['columns'][$field_name])) {
$bundle_settings['fields'][$field_name] = FALSE;
$translatable = FALSE;
}
}
}
}
}
_content_translation_update_field_translatability($settings);
drupal_set_message(t('Settings successfully updated.'));
}
/**
* Stores content translation settings.
*
* @param array $settings
* An associative array of settings keyed by entity type and bundle. At bundle
* level the following keys are available:
* - translatable: The bundle translatability status, which is a bool.
* - settings: An array of language configuration settings as defined by
* language_save_default_configuration().
* - fields: An associative array with field names as keys and a boolean as
* value, indicating field translatability.
*/
function _content_translation_update_field_translatability($settings) {
// Update translatability for configurable fields.
// @todo Remove this once configurable fields rely on entity field info to
// track translatability. See https://drupal.org/node/2018685.
foreach ($settings as $entity_type => $entity_settings) {
$fields = array();
foreach ($entity_settings as $bundle_settings) {
// Collapse field settings since here we have per instance settings, but
// translatability has per-field scope. We assume that all the field
// instances have the same value.
if (!empty($bundle_settings['fields'])) {
foreach ($bundle_settings['fields'] as $field_name => $translatable) {
// If translatability changes for at least one field instance we need
// to switch field translatability.
$field = FieldConfig::loadByName($entity_type, $field_name);
if ($field && $field->isTranslatable() !== $translatable) {
$fields[$field_name] = $translatable;
// If we have a storable field definition we directly persist any
// change to translatability, otherwise we store changes in our config
// so we can properly alter field definitions later.
// @todo Remove this special casing when any field definition can have
// a configurable bundle override. See
// https://drupal.org/node/2224761.
$definition = $definitions[$field_name];
if ($definition instanceof FieldInstanceConfigInterface) {
if ($definition->isTranslatable() != $translatable) {
$definition->setTranslatable($translatable);
$definition->save();
}
// Do not save configurable fields unnecessarily.
unset($bundle_settings['fields'][$field_name]);
}
}
}
}
// Store updated fields.
foreach ($fields as $field_name => $translatable) {
$field = FieldConfig::loadByName($entity_type, $field_name);
$field->translatable = $translatable;
$field->save();
}
}
content_translation_save_settings($settings);
drupal_set_message(t('Settings successfully updated.'));
}
......@@ -5,16 +5,13 @@
* Allows entities to be translated into different languages.
*/
use Drupal\content_translation\Plugin\Derivative\ContentTranslationLocalTasks;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\FieldDefinition;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\field\Entity\FieldInstanceConfig;
use Drupal\field\FieldInstanceConfigInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpFoundation\Request;
......@@ -145,23 +142,28 @@ function content_translation_entity_bundle_info_alter(&$bundles) {
}
/**
* Implements hook_entity_base_field_info_alter().
* Implements hook_entity_bundle_field_info_alter().
*
* @todo Remove this when any field supports per-bundle configurable overrides.
* See https://drupal.org/node/2224761.
*/
function content_translation_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
$translation_settings = \Drupal::config('content_translation.settings')->get($entity_type->id());
if ($translation_settings) {
// Currently field translatability is defined per-field but we may want to
// make it per-instance instead. In that case, we will need to implement
// hook_bundle_field_info_alter() instead.
$field_settings = array();
foreach ($translation_settings as $settings) {
$field_settings += !empty($settings['content_translation']['fields']) ? $settings['content_translation']['fields'] : array();
}
foreach ($field_settings as $name => $translatable) {
if (isset($fields[$name]) && $fields[$name] instanceof FieldDefinition) {
$fields[$name]->setTranslatable((bool) $translatable);
function content_translation_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
$settings = content_translation_get_config($entity_type->id(), $bundle, 'fields');
if (!empty($settings)) {
$base_field_definitions = \Drupal::entityManager()->getBaseFieldDefinitions($entity_type->id());
foreach ($settings as $name => $translatable) {
// Skip storable field definitions as those are supposed to have already
// been changed.
if (!isset($fields[$name]) || !$fields[$name] instanceof FieldInstanceConfigInterface) {
// If we do not have a bundle definition for the current field and we
// have to override its translatability, we need to instantiate a new
// bundle field definition from the base one.
if (!isset($fields[$name]) && isset($base_field_definitions[$name]) && $base_field_definitions[$name]->isTranslatable() != $translatable) {
$fields[$name] = clone $base_field_definitions[$name];
}
if (isset($fields[$name])) {
$fields[$name]->setTranslatable((bool) $translatable);
}
}
}
}
......@@ -636,58 +638,37 @@ function content_translation_entity_extra_field_info() {
}
/**
* Implements hook_form_FORM_ID_alter() for 'field_ui_field_edit_form'.
* Implements hook_form_FORM_ID_alter() for 'field_ui_instance_edit_form'.
*/
function content_translation_form_field_ui_field_edit_form_alter(array &$form, array &$form_state, $form_id) {
$field = $form['#field'];
$bundle = $form['#bundle'];
$bundle_is_translatable = content_translation_enabled($field->entity_type, $bundle);
$form['field']['translatable'] = array(
function content_translation_form_field_ui_field_instance_edit_form_alter(array &$form, array &$form_state) {
$instance = $form_state['instance'];
$bundle_is_translatable = content_translation_enabled($instance->entity_type, $instance->bundle);
$form['instance']['translatable'] = array(
'#type' => 'checkbox',
'#title' => t('Users may translate this field.'),
'#default_value' => $field->isTranslatable(),
'#weight' => 20,
'#default_value' => $instance->isTranslatable(),
'#weight' => -1,
'#disabled' => !$bundle_is_translatable,
'#access' => $instance->getFieldStorageDefinition()->isTranslatable(),
);
$form['#submit'][] = 'content_translation_form_field_ui_field_edit_form_submit';
// Provide helpful pointers for administrators.
if (\Drupal::currentUser()->hasPermission('administer content translation') && !$bundle_is_translatable) {
$toggle_url = url('admin/config/regional/content-language', array(
'query' => drupal_get_destination(),
));
$form['field']['translatable']['#description'] = t('To enable translation of this field, <a href="@language-settings-url">enable language support</a> for this type.', array(
$form['instance']['translatable']['#description'] = t('To configure translation for this field, <a href="@language-settings-url">enable language support</a> for this type.', array(
'@language-settings-url' => $toggle_url,
));
}
}
/**
* Form submission handler for 'field_ui_field_edit_form'.
*/
function content_translation_form_field_ui_field_edit_form_submit($form, array &$form_state) {
$instance = $form_state['instance'];
$value = content_translation_get_config($instance->entity_type, $instance->bundle, 'fields');
if (!isset($value)) {
$value = array();
}
$value[$instance->getField()->getName()] = $form_state['values']['field']['translatable'];
// Store the same value for all bundles as translatability is tracked per
// field.
foreach (entity_get_bundles($instance->entity_type) as $bundle => $info) {
content_translation_set_config($instance->entity_type, $bundle, 'fields', $value);
}
}
/**
* Implements hook_form_FORM_ID_alter() for 'field_ui_field_instance_edit_form'.
*/
function content_translation_form_field_ui_field_instance_edit_form_alter(array &$form, array &$form_state, $form_id) {
if ($form_state['instance']->isTranslatable()) {
if ($instance->isTranslatable()) {
module_load_include('inc', 'content_translation', 'content_translation.admin');
$element = content_translation_field_sync_widget($form_state['instance']);
$element = content_translation_field_sync_widget($instance);
if ($element) {
$form['instance']['settings']['translation_sync'] = $element;
$form['instance']['settings']['translation_sync']['#weight'] = -10;
}
}
}
......
......@@ -9,7 +9,7 @@
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\Core\Language\Language;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldInstanceConfig;
use Drupal\simpletest\WebTestBase;
/**
......@@ -22,7 +22,7 @@ class ContentTranslationSettingsTest extends WebTestBase {
*
* @var array
*/