diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module index 2c54daa8748c412f80cf909ff074a39742d02671..8bd2fc198dfc40beaead25bfa9fab8dbb94dc74c 100644 --- a/core/modules/entity/entity.module +++ b/core/modules/entity/entity.module @@ -467,12 +467,13 @@ function entity_form_id(EntityInterface $entity, $operation = 'default') { * @return * A $form_state array already filled the entity form controller. */ -function entity_form_state_defaults(EntityInterface $entity, $operation = 'default') { +function entity_form_state_defaults(EntityInterface $entity, $operation = 'default', $langcode = NULL) { $form_state = array(); $controller = entity_form_controller($entity->entityType(), $operation); $form_state['build_info']['callback'] = array($controller, 'build'); $form_state['build_info']['base_form_id'] = $entity->entityType() . '_form'; $form_state['build_info']['args'] = array($entity); + $form_state['langcode'] = $langcode; return $form_state; } @@ -506,8 +507,8 @@ function entity_form_submit(EntityInterface $entity, $operation = 'default', &$f * @return * The processed form for the given entity and operation. */ -function entity_get_form(EntityInterface $entity, $operation = 'default') { - $form_state = entity_form_state_defaults($entity, $operation); +function entity_get_form(EntityInterface $entity, $operation = 'default', $langcode = NULL) { + $form_state = entity_form_state_defaults($entity, $operation, $langcode); $form_id = entity_form_id($entity, $operation); return drupal_build_form($form_id, $form_state); } diff --git a/core/modules/entity/lib/Drupal/entity/Entity.php b/core/modules/entity/lib/Drupal/entity/Entity.php index 9701d281e40c427e9aebfe2600e099c87f27f371..e63185d919320c58f3a67b0d3b291615fa7f9ff0 100644 --- a/core/modules/entity/lib/Drupal/entity/Entity.php +++ b/core/modules/entity/lib/Drupal/entity/Entity.php @@ -8,6 +8,7 @@ namespace Drupal\entity; use Drupal\Component\Uuid\Uuid; +use Drupal\Core\Language\Language; /** * Defines a base entity class. @@ -148,9 +149,7 @@ public function uri() { * Implements EntityInterface::language(). */ public function language() { - // @todo: Check for language.module instead, once Field API language - // handling depends upon it too. - return module_exists('locale') ? language_load($this->langcode) : FALSE; + return !empty($this->langcode) ? language_load($this->langcode) : new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED)); } /** diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormController.php b/core/modules/entity/lib/Drupal/entity/EntityFormController.php index 4f1263c7ebfb54e1bbe81b7ef5d3884654110453..dabb33026c7dbddf9404f005eb6cec4a129dbae5 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityFormController.php +++ b/core/modules/entity/lib/Drupal/entity/EntityFormController.php @@ -207,12 +207,27 @@ public function delete(array $form, array &$form_state) { /** * Implements Drupal\entity\EntityFormControllerInterface::getFormLangcode(). */ - public function getFormLangcode($form_state) { - // @todo Introduce a new form language type (see hook_language_types_info()) - // to be used as the default active form language, should it be missing, so - // that entity forms can be used to submit multilingual values. - $language = $this->getEntity($form_state)->language(); - return !empty($language->langcode) ? $language->langcode : NULL; + public function getFormLangcode(array $form_state) { + $entity = $this->getEntity($form_state); + $translations = $entity->translations(); + + if (!empty($form_state['langcode'])) { + $langcode = $form_state['langcode']; + } + else { + // If no form langcode was provided we default to the current content + // language and inspect existing translations to find a valid fallback, + // if any. + $langcode = language(LANGUAGE_TYPE_CONTENT)->langcode; + $fallback = language_multilingual() ? language_fallback_get_candidates() : array(); + while (!empty($langcode) && !isset($translations[$langcode])) { + $langcode = array_shift($fallback); + } + } + + // If the site is not multilingual or no translation for the given form + // language is available, fall back to the entity language. + return !empty($langcode) ? $langcode : $entity->language()->langcode; } /** diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php b/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php index 6765d856f92a5c7e6cd3532e55682818db66f012..95fb2fcd34c153ff426bb61365b6ce584058c402 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php +++ b/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php @@ -49,7 +49,7 @@ public function build(array $form, array &$form_state, EntityInterface $entity); * @return string * The form language code. */ - public function getFormLangcode($form_state); + public function getFormLangcode(array $form_state); /** * Returns the operation identifying the form controller. diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationFormTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationFormTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3908184b2c01034a565f6185a0f576058831d7fb --- /dev/null +++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationFormTest.php @@ -0,0 +1,122 @@ + 'Entity translation form', + 'description' => 'Tests entity translation form functionality.', + 'group' => 'Entity API', + ); + } + + function setUp() { + parent::setUp(); + // Enable translations for the test entity type. + variable_set('entity_test_translation', TRUE); + + // Create test languages. + $this->langcodes = array(); + for ($i = 0; $i < 2; ++$i) { + $language = new Language(array( + 'langcode' => 'l' . $i, + 'name' => $this->randomString(), + )); + $this->langcodes[$i] = $language->langcode; + language_save($language); + } + } + + /** + * Tests entity form language. + */ + function testEntityFormLanguage() { + $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); + + $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'administer content types')); + $this->drupalLogin($web_user); + + // Create a node with language LANGUAGE_NOT_SPECIFIED. + $edit = array(); + $langcode = LANGUAGE_NOT_SPECIFIED; + $edit["title"] = $this->randomName(8); + $edit["body[$langcode][0][value]"] = $this->randomName(16); + + $this->drupalGet('node/add/page'); + $form_langcode = variable_get('entity_form_langcode', FALSE); + $this->drupalPost(NULL, $edit, t('Save')); + + $node = $this->drupalGetNodeByTitle($edit["title"]); + $this->assertTrue($node->langcode == $form_langcode, 'Form language is the same as the entity language.'); + + // Edit the node and test the form language. + $this->drupalGet($this->langcodes[0] . '/node/' . $node->nid . '/edit'); + $form_langcode = variable_get('entity_form_langcode', FALSE); + $this->assertTrue($node->langcode == $form_langcode, 'Form language is the same as the entity language.'); + + // Explicitly set form langcode. + $langcode = $this->langcodes[0]; + entity_get_form($node, 'default', $langcode); + $form_langcode = variable_get('entity_form_langcode', FALSE); + $this->assertTrue($langcode == $form_langcode, 'Form language is the same as the language parameter.'); + + // Enable language selector. + $this->drupalGet('admin/structure/types/manage/page'); + $edit = array('node_type_language_hidden' => FALSE, 'node_type_language_default' => LANGUAGE_NOT_SPECIFIED); + $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 node with language. + $edit = array(); + $langcode = $this->langcodes[0]; + $field_langcode = LANGUAGE_NOT_SPECIFIED; + $edit["title"] = $this->randomName(8); + $edit["body[$field_langcode][0][value]"] = $this->randomName(16); + $edit['langcode'] = $langcode; + $this->drupalPost('node/add/page', $edit, t('Save')); + $this->assertRaw(t('Basic page %title has been created.', array('%title' => $edit["title"])), t('Basic page created.')); + + // Check to make sure the node was created. + $node = $this->drupalGetNodeByTitle($edit["title"]); + $this->assertTrue($node, t('Node found in database.')); + + // Make body translatable. + $field = field_info_field('body'); + $field['translatable'] = TRUE; + field_update_field($field); + $field = field_info_field('body'); + $this->assertTrue($field['translatable'], "Field body is translatable."); + + // Create a body translation and check the form language. + $langcode2 = $this->langcodes[1]; + $node->set('body', array(array('value' => $this->randomName(16))), $langcode2); + $node->save(); + $this->drupalGet($langcode2 . '/node/' . $node->nid . '/edit'); + $form_langcode = variable_get('entity_form_langcode', FALSE); + $this->assertTrue($langcode2 == $form_langcode, "Node edit form language is $langcode2."); + } +} diff --git a/core/modules/entity/tests/modules/entity_test/entity_test.module b/core/modules/entity/tests/modules/entity_test/entity_test.module index 02ec108bfc7b0d91612ee5576e36453fb6df8f61..9b1b2243e8c3986c334dc18735840657d05b972c 100644 --- a/core/modules/entity/tests/modules/entity_test/entity_test.module +++ b/core/modules/entity/tests/modules/entity_test/entity_test.module @@ -66,3 +66,11 @@ function entity_test_load_multiple(array $ids = NULL, $reset = FALSE) { function entity_test_delete_multiple(array $ids) { entity_get_controller('entity_test')->delete($ids); } + +/** + * Implements hook_form_BASE_FORM_ID_alter(). + */ +function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) { + $langcode = $form_state['controller']->getFormLangcode($form_state); + variable_set('entity_form_langcode', $langcode); +} diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index b99547e6bf2fd18d185a975d24460621048df812..b27e1a646ad0abe7316c7305b69bb3e5281edf21 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -337,7 +337,14 @@ public function submit(array $form, array &$form_state) { protected function submitNodeLanguage(array $form, array &$form_state) { if (field_has_translation_handler('node', 'node')) { $bundle = $form_state['values']['type']; - $node_language = $form_state['values']['langcode']; + $entity = $this->getEntity($form_state); + $form_langcode = $this->getFormLangcode($form_state); + + // If we are editing the default language values, we use the submitted + // entity language as the new language for fields to handle any language + // change. Otherwise the current form language is the proper value, since + // in this case it is not supposed to change. + $current_langcode = $entity->language()->langcode == $form_langcode ? $form_state['values']['langcode'] : $form_langcode; foreach (field_info_instances('node', $bundle) as $instance) { $field_name = $instance['field_name']; @@ -346,8 +353,8 @@ protected function submitNodeLanguage(array $form, array &$form_state) { // Handle a possible language change: new language values are inserted, // previous ones are deleted. - if ($field['translatable'] && $previous_langcode != $node_language) { - $form_state['values'][$field_name][$node_language] = $form_state['values'][$field_name][$previous_langcode]; + if ($field['translatable'] && $previous_langcode != $current_langcode) { + $form_state['values'][$field_name][$current_langcode] = $form_state['values'][$field_name][$previous_langcode]; $form_state['values'][$field_name][$previous_langcode] = array(); } }