diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 67e5690..4379f29 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -495,13 +495,20 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) { $hooks = array('entity_field_info', $entity_type . '_field_info'); $this->moduleHandler->alter($hooks, $this->entityFieldInfo[$entity_type], $entity_type); - // Enforce fields to be multiple by default. - foreach ($this->entityFieldInfo[$entity_type]['definitions'] as &$definition) { - $definition['list'] = TRUE; - } - foreach ($this->entityFieldInfo[$entity_type]['optional'] as &$definition) { - $definition['list'] = TRUE; + // Enforce fields to be multiple and untranslatable by default. + $entity_info = $this->getDefinition($entity_type); + $keys = array_intersect_key(array_filter($entity_info['entity_keys']), array_flip(array('id', 'revision', 'uuid', 'bundle'))); + $base_fields = array_flip(array('langcode') + $keys); + foreach (array('definitions', 'optional') as $key) { + foreach ($this->entityFieldInfo[$entity_type][$key] as $name => &$definition) { + $definition['list'] = TRUE; + // Ensure base fields are never made translatable. + if (isset($base_fields[$name]) || !isset($definition['translatable'])) { + $definition['translatable'] = FALSE; + } + } } + $this->cache->set($cid, $this->entityFieldInfo[$entity_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE, 'entity_field_info' => TRUE)); } } diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc index 9904ba0..c2c0926 100644 --- a/core/modules/content_translation/content_translation.admin.inc +++ b/core/modules/content_translation/content_translation.admin.inc @@ -74,6 +74,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$ $form['#attached']['js'][] = array('data' => drupal_get_path('module', 'content_translation') . '/content_translation.admin.js', 'type' => 'file'); $dependent_options_settings = array(); + $entity_manager = Drupal::entityManager(); foreach ($form['#labels'] as $entity_type => $label) { $entity_info = entity_get_info($entity_type); foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) { @@ -85,7 +86,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$ // Only show the checkbox to enable translation if the bundles in the // entity might have fields and if there are fields to translate. if (!empty($entity_info['fieldable'])) { - $fields = field_info_instances($entity_type, $bundle); + $fields = $entity_manager->getFieldDefinitions($entity_type, $bundle); if ($fields) { $form['settings'][$entity_type][$bundle]['translatable'] = array( '#type' => 'checkbox', @@ -93,24 +94,40 @@ function _content_translation_form_language_content_settings_form_alter(array &$ '#default_value' => content_translation_enabled($entity_type, $bundle), ); - // @todo Exploit field definitions once all core entities and field - // types are migrated to the Entity Field API. - foreach ($fields as $field_name => $instance) { - $field = $instance->getField(); - $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array( - '#label' => $instance['label'], - '#type' => 'checkbox', - '#title' => $instance['label'], - '#default_value' => $field['translatable'], - ); - $column_element = content_translation_field_sync_widget($field, $instance); - if ($column_element) { - $form['settings'][$entity_type][$bundle]['columns'][$field_name] = $column_element; - - if (isset($column_element['#options']['file'])) { - $dependent_options_settings["settings[{$entity_type}][{$bundle}][columns][{$field_name}]"] = array('file'); + $field_settings = content_translation_get_config($entity_type, $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. + if (!empty($definition['configurable']) && ($field = field_info_field($entity_type, $field_name))) { + $instance = field_info_instance($entity_type, $field_name, $bundle); + $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array( + '#label' => $instance['label'], + '#type' => 'checkbox', + '#default_value' => $translatable, + ); + $column_element = content_translation_field_sync_widget($field, $instance); + if ($column_element) { + $form['settings'][$entity_type][$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}][{$bundle}][columns][{$field_name}]"] = array('file'); + } } } + // Instead we need to rely on field definitions to determine whether + // they 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]) || !empty($definition['translatable'])) { + $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array( + '#label' => $definition['label'], + '#type' => 'checkbox', + '#default_value' => $translatable, + ); + } } } } @@ -328,11 +345,11 @@ function _content_translation_update_field_translatability($settings) { foreach ($bundle_settings['fields'] as $field_name => $translatable) { // If a field is enabled for translation for at least one instance we // need to mark it as translatable. - $fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]); + if (field_info_field($entity_type, $field_name)) { + $fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]); + } } } - // @todo Store non-configurable field settings to be able to alter their - // definition afterwards. } } diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index a6cf31c..578941d 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -126,6 +126,33 @@ function content_translation_entity_bundle_info_alter(&$bundles) { } /** + * Implements hook_entity_field_info_alter(). + */ +function content_translation_entity_field_info_alter(&$info, $entity_type) { + $translation_settings = config('content_translation.settings')->get($entity_type); + + if ($translation_settings) { + // Currently field translatability is defined per-field but we may want to + // make it per-instance instead, so leaving the possibility open for further + // easier refactoring. + $fields = array(); + foreach ($translation_settings as $bundle => $settings) { + $fields += !empty($settings['content_translation']['fields']) ? $settings['content_translation']['fields'] : array(); + } + + $keys = array('definitions', 'optional'); + foreach ($fields as $name => $translatable) { + foreach ($keys as $key) { + if (isset($info[$key][$name])) { + $info[$key][$name]['translatable'] = (bool) $translatable; + break; + } + } + } + } +} + +/** * Implements hook_menu(). */ function content_translation_menu() { @@ -987,6 +1014,11 @@ function content_translation_save_settings($settings) { // Store whether a bundle has translation enabled or not. content_translation_set_config($entity_type, $bundle, 'enabled', $bundle_settings['translatable']); + // Store whether fields are translatable or not. + if (!empty($bundle_settings['fields'])) { + content_translation_set_config($entity_type, $bundle, 'fields', $bundle_settings['fields']); + } + // Store whether fields have translation enabled or not. if (!empty($bundle_settings['columns'])) { foreach ($bundle_settings['columns'] as $field_name => $column_settings) { diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php index ecab4c4..a10ad27 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php @@ -113,6 +113,17 @@ function testSettingsUI() { $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type')); $this->drupalGet('admin/structure/types/manage/article'); $this->assertFieldChecked('edit-language-configuration-content-translation'); + + // Test that the title field of nodes is available in the settings form. + $edit = array( + 'entity_types[node]' => TRUE, + 'settings[node][article][settings][language][langcode]' => 'current_interface', + 'settings[node][article][settings][language][language_show]' => TRUE, + 'settings[node][article][translatable]' => TRUE, + 'settings[node][article][fields][title]' => TRUE + ); + $this->assertSettings('node', NULL, TRUE, $edit); + } /** diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php index 8367e16..95f164f 100644 --- a/core/modules/node/lib/Drupal/node/Entity/Node.php +++ b/core/modules/node/lib/Drupal/node/Entity/Node.php @@ -360,6 +360,7 @@ public static function baseFieldDefinitions($entity_type) { 'property_constraints' => array( 'value' => array('Length' => array('max' => 255)), ), + 'translatable' => TRUE, ); $properties['uid'] = array( 'label' => t('User ID'),