Commit 8ae055fb authored by alexpott's avatar alexpott

Issue #2230637 by plach, fran seva, yched, swentel: Create a Language field...

Issue #2230637 by plach, fran seva, yched, swentel: Create a Language field widget and the related formatter
parent eb9e9e3c
......@@ -51,6 +51,8 @@ public static function create(ContainerInterface $container) {
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$this->getFormDisplay($form_state)->buildForm($this->entity, $form, $form_state);
// Allow modules to act before and after form language is updated.
$form['#entity_builders']['update_form_langcode'] = [$this, 'updateFormLangcode'];
return $form;
}
......@@ -58,7 +60,6 @@ public function form(array $form, FormStateInterface $form_state) {
* {@inheritdoc}
*/
public function validate(array $form, FormStateInterface $form_state) {
$this->updateFormLangcode($form_state);
$entity = $this->buildEntity($form, $form_state);
$this->getFormDisplay($form_state)->validateFormValues($entity, $form, $form_state);
......@@ -69,11 +70,15 @@ public function validate(array $form, FormStateInterface $form_state) {
}
/**
* Initialize the form state and the entity before the first form build.
* Initializes the form state and the entity before the first form build.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
protected function init(FormStateInterface $form_state) {
// Ensure we act on the translation object corresponding to the current form
// language.
$this->initFormLangcodes($form_state);
$langcode = $this->getFormLangcode($form_state);
$this->entity = $this->entity->getTranslation($langcode);
......@@ -84,15 +89,33 @@ protected function init(FormStateInterface $form_state) {
}
/**
* {@inheritdoc}
* Initializes form language code values.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function getFormLangcode(FormStateInterface $form_state) {
protected function initFormLangcodes(FormStateInterface $form_state) {
// Store the entity default language to allow checking whether the form is
// dealing with the original entity or a translation.
if (!$form_state->has('entity_default_langcode')) {
$form_state->set('entity_default_langcode', $this->entity->getUntranslated()->language()->getId());
}
// This value might have been explicitly populated to work with a particular
// entity translation. If not we fall back to the most proper language based
// on contextual information.
if (!$form_state->has('langcode')) {
// Imply a 'view' operation to ensure users edit entities in the same
// language they are displayed. This allows to keep contextual editing
// working also for multilingual entities.
$form_state->set('langcode', $this->entityManager->getTranslationFromContext($this->entity)->language()->getId());
}
}
/**
* {@inheritdoc}
*/
public function getFormLangcode(FormStateInterface $form_state) {
$this->initFormLangcodes($form_state);
return $form_state->get('langcode');
}
......@@ -100,7 +123,8 @@ public function getFormLangcode(FormStateInterface $form_state) {
* {@inheritdoc}
*/
public function isDefaultFormLangcode(FormStateInterface $form_state) {
return $this->getFormLangcode($form_state) == $this->entity->getUntranslated()->language()->getId();
$this->initFormLangcodes($form_state);
return $form_state->get('langcode') == $form_state->get('entity_default_langcode');
}
/**
......@@ -138,13 +162,26 @@ public function setFormDisplay(EntityFormDisplayInterface $form_display, FormSta
/**
* Updates the form language to reflect any change to the entity language.
*
* There are use cases for modules to act both before and after form language
* being updated, thus the update is performed through an entity builder
* callback, which allows to support both cases.
*
* @param string $entity_type_id
* The entity type identifier.
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity updated with the submitted values.
* @param array $form
* The complete form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @see \Drupal\Core\Entity\ContentEntityForm::form()
*/
protected function updateFormLangcode(FormStateInterface $form_state) {
public function updateFormLangcode($entity_type_id, EntityInterface $entity, array $form, FormStateInterface $form_state) {
// Update the form language as it might have changed.
if ($form_state->hasValue('langcode') && $this->isDefaultFormLangcode($form_state)) {
$form_state->set('langcode', $form_state->getValue('langcode'));
if ($this->isDefaultFormLangcode($form_state)) {
$langcode = $entity->language()->getId();
$form_state->set('langcode', $langcode);
}
}
......
<?php
/**
* @file
* Contains \Drupal\Core\Field\Plugin\Field\FieldFormatter\LanguageFormatter.
*/
namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
use Drupal\Component\Utility\String;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
/**
* Plugin implementation of the 'language' formatter.
*
* @FieldFormatter(
* id = "language",
* label = @Translation("Language"),
* field_types = {
* "language"
* }
* )
*/
class LanguageFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
$elements = array();
foreach ($items as $delta => $item) {
$elements[$delta] = array('#markup' => $item->language ? String::checkPlain($item->language->getName()) : '');
}
return $elements;
}
}
......@@ -20,6 +20,8 @@
* id = "language",
* label = @Translation("Language"),
* description = @Translation("An entity field referencing a language."),
* default_widget = "language_select",
* default_formatter = "language",
* no_ui = TRUE,
* constraints = {
* "ComplexData" = {
......
<?php
/**
* @file
* Contains \Drupal\Core\Field\Plugin\Field\FieldWidget\LanguageSelectWidget.
*/
namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
/**
* Plugin implementation of the 'Language' widget.
*
* @FieldWidget(
* id = "language_select",
* label = @Translation("Language select"),
* field_types = {
* "language"
* }
* )
*/
class LanguageSelectWidget extends WidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['value'] = $element + array(
'#type' => 'language_select',
'#default_value' => $items[$delta]->value,
'#languages' => LanguageInterface::STATE_ALL,
);
return $element;
}
}
......@@ -153,7 +153,14 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields['langcode'] = BaseFieldDefinition::create('language')
->setLabel(t('Language code'))
->setDescription(t('The feed language code.'));
->setDescription(t('The feed language code.'))
->setDisplayOptions('view', array(
'type' => 'hidden',
))
->setDisplayOptions('form', array(
'type' => 'language_select',
'weight' => 2,
));
$fields['url'] = BaseFieldDefinition::create('uri')
->setLabel(t('URL'))
......
......@@ -7,13 +7,9 @@
namespace Drupal\aggregator;
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form controller for the aggregator feed edit forms.
......@@ -24,21 +20,13 @@ class FeedForm extends ContentEntityForm {
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$feed = $this->entity;
// @todo: convert to a language selection widget defined in the base field.
// Blocked on https://drupal.org/node/2226493 which adds a generic
// language widget.
// Language module may expose or hide this element, see language_form_alter().
$form['langcode'] = array(
'#title' => $this->t('Language'),
'#type' => 'language_select',
'#default_value' => $feed->language()->getId(),
'#languages' => LanguageInterface::STATE_ALL,
'#weight' => -4,
);
$form = parent::form($form, $form_state);
// @todo Allow non translatable entity types having language support to be
// configured in the content language setting.
return parent::form($form, $form_state, $feed);
// Ensure the language widget is displayed.
$form['langcode']['#access'] = TRUE;
return $form;
}
/**
......
......@@ -52,8 +52,8 @@ public function testFeedLanguage() {
/** @var \Drupal\aggregator\FeedInterface[] $feeds */
$feeds = array();
// Create feeds.
$feeds[1] = $this->createFeed(NULL, array('langcode' => $this->langcodes[1]));
$feeds[2] = $this->createFeed(NULL, array('langcode' => $this->langcodes[2]));
$feeds[1] = $this->createFeed(NULL, array('langcode[0][value]' => $this->langcodes[1]));
$feeds[2] = $this->createFeed(NULL, array('langcode[0][value]' => $this->langcodes[2]));
// Make sure that the language has been assigned.
$this->assertEqual($feeds[1]->language()->getId(), $this->langcodes[1]);
......
......@@ -12,9 +12,7 @@
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\language\Entity\ContentLanguageSettings;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -105,15 +103,6 @@ public function form(array $form, FormStateInterface $form_state) {
// names.
$form['#attributes']['class'][0] = 'block-' . Html::getClass($block->bundle()) . '-form';
$form['langcode'] = array(
'#title' => $this->t('Language'),
'#type' => 'language_select',
'#default_value' => $block->getUntranslated()->language()->getId(),
'#languages' => LanguageInterface::STATE_ALL,
// Language module may expose or hide this element, see language_form_alter().
'#access' => FALSE,
);
$form['advanced'] = array(
'#type' => 'vertical_tabs',
'#weight' => 99,
......
......@@ -156,9 +156,16 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setSetting('unsigned', TRUE);
$fields['langcode'] = BaseFieldDefinition::create('language')
->setLabel(t('Language code'))
->setLabel(t('Language'))
->setDescription(t('The custom block language code.'))
->setRevisionable(TRUE);
->setRevisionable(TRUE)
->setDisplayOptions('view', array(
'type' => 'hidden',
))
->setDisplayOptions('form', array(
'type' => 'language_select',
'weight' => 2,
));
$fields['info'] = BaseFieldDefinition::create('string')
->setLabel(t('Block description'))
......
......@@ -14,10 +14,8 @@
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\language\Entity\ContentLanguageSettings;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -162,15 +160,6 @@ public function form(array $form, FormStateInterface $form_state) {
$form['author']['name']['#attributes']['data-drupal-default-value'] = $this->config('user.settings')->get('anonymous');
}
$form['langcode'] = array(
'#title' => t('Language'),
'#type' => 'language_select',
'#default_value' => $comment->getUntranslated()->language()->getId(),
'#languages' => Language::STATE_ALL,
// Language module may expose or hide this element, see language_form_alter().
'#access' => FALSE,
);
// Add author email and homepage fields depending on the current user.
$form['author']['mail'] = array(
'#type' => 'email',
......
......@@ -221,8 +221,15 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setRequired(TRUE);
$fields['langcode'] = BaseFieldDefinition::create('language')
->setLabel(t('Language code'))
->setDescription(t('The comment language code.'));
->setLabel(t('Language'))
->setDescription(t('The comment language code.'))
->setDisplayOptions('view', array(
'type' => 'hidden',
))
->setDisplayOptions('form', array(
'type' => 'language_select',
'weight' => 2,
));
$fields['subject'] = BaseFieldDefinition::create('string')
->setLabel(t('Subject'))
......
......@@ -93,7 +93,7 @@ function testCommentLanguage() {
$edit = array(
'title[0][value]' => $title,
'body[0][value]' => $this->randomMachineName(),
'langcode' => $node_langcode,
'langcode[0][value]' => $node_langcode,
'comment[0][status]' => CommentItemInterface::OPEN,
);
$this->drupalPostForm("node/add/article", $edit, t('Save'));
......
......@@ -144,8 +144,12 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setReadOnly(TRUE);
$fields['langcode'] = BaseFieldDefinition::create('language')
->setLabel(t('Language code'))
->setDescription(t('The comment language code.'));
->setLabel(t('Language'))
->setDescription(t('The message language code.'))
->setDisplayOptions('form', array(
'type' => 'language_select',
'weight' => 2,
));
$fields['name'] = BaseFieldDefinition::create('string')
->setLabel(t("The sender's name"))
......
......@@ -12,7 +12,6 @@
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Flood\FloodInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -98,15 +97,6 @@ public function form(array $form, FormStateInterface $form_state) {
$form['preview']['message'] = $this->entityManager->getViewBuilder('contact_message')->view($message, 'full');
}
$form['langcode'] = array(
'#title' => $this->t('Language'),
'#type' => 'language_select',
'#default_value' => $message->getUntranslated()->language()->getId(),
'#languages' => Language::STATE_ALL,
// Language module may expose or hide this element, see language_form_alter().
'#access' => FALSE,
);
$form['name'] = array(
'#type' => 'textfield',
'#title' => $this->t('Your name'),
......
......@@ -291,9 +291,10 @@ function content_translation_form_alter(array &$form, FormStateInterface $form_s
// Handle fields shared between translations when there is at least one
// translation available or a new one is being created.
if (!$entity->isNew() && (!isset($translations[$form_langcode]) || count($translations) > 1)) {
foreach ($entity->getFieldDefinitions() as $property_name => $definition) {
if (isset($form[$property_name])) {
$form[$property_name]['#multilingual'] = $definition->isTranslatable();
$langcode_key = $entity->getEntityType()->getKey('langcode') ?: 'langcode';
foreach ($entity->getFieldDefinitions() as $field_name => $definition) {
if (isset($form[$field_name]) && $field_name != $langcode_key) {
$form[$field_name]['#multilingual'] = $definition->isTranslatable();
}
}
}
......
......@@ -144,22 +144,33 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En
}
}
// Disable languages for existing translations, so it is not possible to
// switch this node to some language which is already in the translation
// set.
$language_widget = isset($form['langcode']) && $form['langcode']['#type'] == 'language_select';
if ($language_widget && $has_translations) {
$form['langcode']['#options'] = array();
foreach (language_list(LanguageInterface::STATE_CONFIGURABLE) as $language) {
if (empty($translations[$language->getId()]) || $language->getId() == $entity_langcode) {
$form['langcode']['#options'][$language->getId()] = $language->getName();
// Locate the language widget.
$language_field = $this->entityType->getKey('langcode') ?: 'langcode';
if (isset($form[$language_field])) {
$language_widget = &$form[$language_field];
}
// If we are editing the source entity, limit the list of languages so that
// it is not possible to switch to a language for which a translation
// already exists. Note that this will only work if the widget is structured
// like \Drupal\Core\Field\Plugin\Field\FieldWidget\LanguageSelectWidget.
if (isset($language_widget['widget'][0]['value']) && !$is_translation && $has_translations) {
$language_select = &$language_widget['widget'][0]['value'];
if ($language_select['#type'] == 'language_select') {
$options = array();
foreach (\Drupal::languageManager()->getLanguages() as $language) {
// Show the current language, and the languages for which no
// translation already exists.
if (empty($translations[$language->getId()]) || $language->getId() == $entity_langcode) {
$options[$language->getId()] = $language->getName();
}
}
$language_select['#options'] = $options;
}
}
if ($is_translation) {
if ($language_widget) {
$form['langcode']['#access'] = FALSE;
if (isset($language_widget)) {
$language_widget['widget']['#access'] = FALSE;
}
// Replace the delete button with the delete translation one.
......@@ -271,8 +282,8 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En
'#default_value' => $new_translation ? '' : format_date($date, 'custom', 'Y-m-d H:i:s O'),
);
if ($language_widget) {
$form['langcode']['#multilingual'] = TRUE;
if (isset($language_widget)) {
$language_widget['#multilingual'] = TRUE;
}
$form['#process'][] = array($this, 'entityFormSharedElements');
......
......@@ -8,7 +8,6 @@
namespace Drupal\content_translation\Tests;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
......@@ -74,7 +73,7 @@ protected function doTestBasicTranslation() {
$path = $langcode . '/' . $content_translation_path . '/add/' . $default_langcode . '/' . $langcode;
$this->drupalPostForm($path, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode));
if ($this->testLanguageSelector) {
$this->assertNoFieldByXPath('//select[@id="edit-langcode"]', NULL, 'Language selector correctly disabled on translations.');
$this->assertNoFieldByXPath('//select[@id="edit-langcode-0-value"]', NULL, 'Language selector correctly disabled on translations.');
}
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
$this->drupalGet($entity->getSystemPath('drupal:content-translation-overview'));
......@@ -137,20 +136,19 @@ protected function doTestTranslationOverview() {
protected function doTestOutdatedStatus() {
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
$langcode = 'fr';
$default_langcode = $this->langcodes[0];
$languages = \Drupal::languageManager()->getLanguages();
// Mark translations as outdated.
$edit = array('content_translation[retranslate]' => TRUE);
$edit_path = $entity->getSystemPath('edit-form');
$this->drupalPostForm($langcode . '/' . $edit_path, $edit, $this->getFormSubmitAction($entity, $langcode));
$path = $entity->getSystemPath('edit-form');
$this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode), array('language' => $languages[$langcode]));
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
// Check that every translation has the correct "outdated" status, and that
// the Translation fieldset is open if the translation is "outdated".
foreach ($this->langcodes as $added_langcode) {
$prefix = $added_langcode != $default_langcode ? $added_langcode . '/' : '';
$path = $prefix . $edit_path;
$this->drupalGet($path);
$options = array('language' => $languages[$added_langcode]);
$this->drupalGet($path, $options);
if ($added_langcode == $langcode) {
$this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is not checked by default.');
$this->assertFalse($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab should be collapsed by default.');
......@@ -159,8 +157,8 @@ protected function doTestOutdatedStatus() {
$this->assertFieldByXPath('//input[@name="content_translation[outdated]"]', TRUE, 'The translate flag is checked by default.');
$this->assertTrue($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab is correctly expanded when the translation is outdated.');
$edit = array('content_translation[outdated]' => FALSE);
$this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $added_langcode));
$this->drupalGet($path);
$this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $added_langcode), $options);
$this->drupalGet($path, $options);
$this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is now shown.');
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
$this->assertFalse($entity->translation[$added_langcode]['outdated'], 'The "outdated" status has been correctly stored.');
......
......@@ -5,12 +5,15 @@
* Add language handling functionality to Drupal.
*/
use Drupal\Component\Utility\String;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\language\ConfigurableLanguageInterface;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
......@@ -173,6 +176,24 @@ function language_process_language_select($element) {
return $element;
}
/**
* Implements hook_entity_base_field_info_alter().
*/
function language_entity_base_field_info_alter(&$fields) {
foreach ($fields as $definition) {
// Set configurable form display for language fields with display options.
if ($definition->getType() == 'language') {
foreach (array('form', 'view') as $type) {
if ($definition->getDisplayOptions($type)) {
// The related configurations will be purged manually on Language
// module uninstallation. @see language_modules_uninstalled().
$definition->setDisplayConfigurable($type, TRUE);
}
}
}
}
}
/**
* Submit handler for the forms that have a language_configuration element.
*/
......@@ -348,6 +369,19 @@ function language_modules_installed($modules) {
$negotiator->updateConfiguration(array());
$negotiator->purgeConfiguration();
}
else {
// In language_entity_base_field_info_alter() we are altering view/form
// display definitions to make language fields display configurable. Since
// this is not a hard dependency, and thus is not detected by the config
// system, we have to clean up the related values manually.
foreach (array('entity_view_display', 'entity_form_display') as $key) {
$displays = \Drupal::entityManager()->getStorage($key)->loadMultiple();
/** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
foreach ($displays as $display) {
$display->save();
}
}
}
}
/**
......@@ -481,3 +515,16 @@ function language_field_info_alter(&$info) {
// Change the default behavior of language field.
$info['language']['class'] = '\Drupal\language\DefaultLanguageItem';
}
/**
* Implements hook_entity_field_access()
*/
function language_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
if ($field_definition->getName() == 'langcode') {
$entity = $items->getEntity();
$config = ContentLanguageSettings::loadByEntityTypeBundle($entity->getEntityTypeId(), $entity->bundle());
return AccessResult::forbiddenIf(!$config->isLanguageAlterable());
}
return AccessResult::neutral();
}
......@@ -95,12 +95,12 @@ public function testContentTypeLanguageConfiguration() {
$this->drupalLogin($web_user);
$this->drupalGet("node/add/{$type1->type}");
// Verify language select list is not present.
$this->assertNoFieldByName('language', NULL, 'Language select not present on the node add form.');
$this->assertNoFieldByName('langcode[0][value]', NULL, 'Language select not present on the node add form.');
// Verify language selection appears on the node add form.
$this->drupalGet("node/add/{$type2->type}");
// Verify language select list is present.
$this->assertFieldByName('langcode', NULL, 'Language select present on the node add form.');
$this->assertFieldByName('langcode[0][value]', NULL, 'Language select present on the node add form.');
// Ensure language appears.
$this->assertText($name, 'Language present.');
......@@ -120,7 +120,7 @@ public function testContentTypeLanguageConfiguration() {
$this->assertRaw('<option value="' . $langcode . '" selected="selected">' . $name . '</option>', 'Correct language selected.');
// Ensure we can change the node language.
$edit = array(
'langcode' => 'en',
'langcode[0][value]' => 'en',
);
$this->drupalPostForm($path, $edit, t('Save'));
$this->assertRaw(t('%title has been updated.', array('%title' => $node_title)));
......
......@@ -392,8 +392,15 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
));
$fields['langcode'] = BaseFieldDefinition::create('language')
->setLabel(t('Language code'))
->setDescription(t('The node language code.'));
->setLabel(t('Language'))
->setDescription(t('The menu link language code.'))
->setDisplayOptions('view', array(
'type' => 'hidden',
))
->setDisplayOptions('form', array(
'type' => 'language_select',
'weight' => 2,
));
$fields['parent'] = BaseFieldDefinition::create('string')
->setLabel(t('Parent plugin ID'))
......
......@@ -13,7 +13,6 @@
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Menu\Form\MenuLinkFormInterface;
use Drupal\Core\Menu\MenuLinkInterface;
......@@ -257,15 +256,6 @@ public function form(array $form, FormStateInterface $form_state) {
'#weight' => -2,
);
$form['langcode'] = array(
'#title' => t('Language'),
'#type' => 'language_select',
'#default_value' => $this->entity->getUntranslated()->language()->getId(),
'#languages' => Language::STATE_ALL,
// Language module may expose or hide this element, see language_form_alter().
'#access' => FALSE,
);
$default = $this->entity->getMenuName() . ':' . $this->entity->getParentId();
$form['menu_parent'] = $this->menuParentSelector->parentSelectElement($default, $this->entity->getPluginId());
$form['menu_parent']['#weight'] = 10;
......
......@@ -112,7 +112,7 @@ function testMenuLanguage() {
// Now change the language of the new link to 'bb'.