diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module index 74f2fcf..c63b2f8 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/EntityFormController.php b/core/modules/entity/lib/Drupal/entity/EntityFormController.php index 4f1263c..e9601b7 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityFormController.php +++ b/core/modules/entity/lib/Drupal/entity/EntityFormController.php @@ -208,11 +208,26 @@ class EntityFormController implements EntityFormControllerInterface { * 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; + $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/StorableBase.php b/core/modules/entity/lib/Drupal/entity/StorableBase.php index 57bf352..da308f9 100644 --- a/core/modules/entity/lib/Drupal/entity/StorableBase.php +++ b/core/modules/entity/lib/Drupal/entity/StorableBase.php @@ -148,9 +148,7 @@ abstract class StorableBase implements StorableInterface { * Implements StorableInterface::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 language_load($this->langcode); } /** diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php index 252e048..077cc45 100644 --- a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php +++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php @@ -22,7 +22,7 @@ class EntityTranslationTest extends WebTestBase { * * @var array */ - public static $modules = array('entity_test', 'locale'); + public static $modules = array('entity_test', 'locale', 'node'); protected $langcodes; @@ -231,4 +231,73 @@ class EntityTranslationTest extends WebTestBase { $entities = entity_load_multiple_by_properties('entity_test', array('uid' => $properties[$langcode]['uid'], 'default_langcode' => NULL)); $this->assertEqual(count($entities), 2, 'Two entities loaded by uid without caring about property translatability.'); } + + /** + * 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 02ec108..9b1b224 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 51f4308..ade0a4c 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -337,7 +337,7 @@ class NodeFormController extends EntityFormController { 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']; + $current_langcode = $this->getFormLangcode($form_state); foreach (field_info_instances('node', $bundle) as $instance) { $field_name = $instance['field_name']; @@ -346,8 +346,8 @@ class NodeFormController extends EntityFormController { // 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(); } } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php