Issue #1498874 by peximo, plach, Gábor Hojtsy, attiks: Provide language awareness to entity forms (introduce the form language concept).

8.0.x
catch 2012-09-06 13:11:03 +01:00
parent e904f789fb
commit 267eb43804
7 changed files with 168 additions and 16 deletions

View File

@ -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);
}

View File

@ -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 @@ class Entity implements EntityInterface {
* 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));
}
/**

View File

@ -207,12 +207,27 @@ 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;
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;
}
/**

View File

@ -49,7 +49,7 @@ interface EntityFormControllerInterface {
* @return string
* The form language code.
*/
public function getFormLangcode($form_state);
public function getFormLangcode(array $form_state);
/**
* Returns the operation identifying the form controller.

View File

@ -0,0 +1,122 @@
<?php
/**
* @file
* Definition of Drupal\entity\Tests\EntityTranslationFormTest.
*/
namespace Drupal\entity\Tests;
use Exception;
use InvalidArgumentException;
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Language\Language;
/**
* Tests entity translation form.
*/
class EntityTranslationFormTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('entity_test', 'locale', 'node');
protected $langcodes;
public static function getInfo() {
return array(
'name' => '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.");
}
}

View File

@ -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);
}

View File

@ -337,7 +337,14 @@ 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'];
$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 @@ 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();
}
}