From 8d87a928425f9aaf89b95516db5d9238c875f9bf Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Fri, 13 Mar 2015 10:06:30 +0000
Subject: [PATCH] =?UTF-8?q?Issue=20#2384863=20by=20G=C3=A1bor=20Hojtsy,=20?=
 =?UTF-8?q?vijaycs85,=20rodrigoaguilera:=20Translation=20language=20base?=
 =?UTF-8?q?=20field=20handler=20should=20use=20views=20field=20handler,=20?=
 =?UTF-8?q?provide=20unified=20options?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 core/config/schema/core.entity.schema.yml     |   7 ++
 .../FieldFormatter/LanguageFormatter.php      | 109 ++++++++++++++++--
 .../Field/FieldFormatter/StringFormatter.php  |  26 ++++-
 .../Core/Language/LanguageInterface.php       |   3 +-
 core/modules/language/language.module         |   8 +-
 .../node/config/schema/node.views.schema.yml  |   8 --
 core/modules/node/src/NodeViewsData.php       |   3 -
 .../node/src/Plugin/views/field/Language.php  |  52 ---------
 .../node/src/Tests/Views/NodeLanguageTest.php |  54 ++++++++-
 .../node_test_views/node_test_views.info.yml  |   1 +
 .../node_test_views/node_test_views.views.inc |  16 +++
 .../test_views/views.view.test_language.yml   |   7 +-
 .../config/schema/taxonomy.views.schema.yml   |   4 -
 .../src/Plugin/views/field/Language.php       |  30 -----
 core/modules/taxonomy/src/TermViewsData.php   |   2 -
 .../user/config/schema/user.views.schema.yml  |   4 -
 .../user/src/Plugin/views/field/Language.php  |  52 ---------
 core/modules/user/src/UserViewsData.php       |   1 -
 .../config/schema/views.field.schema.yml      |   4 +
 core/modules/views/src/EntityViewsData.php    |   2 +-
 .../src/Plugin/views/field/LanguageField.php  |   9 +-
 .../tests/src/Unit/EntityViewsDataTest.php    |   2 +-
 22 files changed, 213 insertions(+), 191 deletions(-)
 delete mode 100644 core/modules/node/src/Plugin/views/field/Language.php
 create mode 100644 core/modules/node/tests/modules/node_test_views/node_test_views.views.inc
 delete mode 100644 core/modules/taxonomy/src/Plugin/views/field/Language.php
 delete mode 100644 core/modules/user/src/Plugin/views/field/Language.php

diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index 423acb737fc1..9e8ecd3a0ade 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -248,6 +248,13 @@ field.formatter.settings.string:
       type: boolean
       label: 'Link to the entity'
 
+field.formatter.settings.language:
+  type: field.formatter.settings.string
+  mapping:
+    native_language:
+      type: boolean
+      label: 'Display in native language'
+
 field.formatter.settings.number_decimal:
   type: mapping
   label: 'Number decimal display format settings'
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/LanguageFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/LanguageFormatter.php
index 98d1d765d21e..d142872136be 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/LanguageFormatter.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/LanguageFormatter.php
@@ -8,8 +8,12 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
 
 use Drupal\Component\Utility\String;
-use Drupal\Core\Field\FormatterBase;
-use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Plugin implementation of the 'language' formatter.
@@ -22,22 +26,103 @@
  *   }
  * )
  */
-class LanguageFormatter extends FormatterBase {
+class LanguageFormatter extends StringFormatter {
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
+  /**
+   * Constructs a LanguageFormatter instance.
+   *
+   * @param string $plugin_id
+   *   The plugin_id for the formatter.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The definition of the field to which the formatter is associated.
+   * @param array $settings
+   *   The formatter settings.
+   * @param string $label
+   *   The formatter label display setting.
+   * @param string $view_mode
+   *   The view mode.
+   * @param array $third_party_settings
+   *   Any third party settings settings.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
+   */
+  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
+    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings, $entity_manager);
+
+    $this->languageManager = $language_manager;
+  }
 
   /**
    * {@inheritdoc}
    */
-  public function viewElements(FieldItemListInterface $items) {
-    $elements = array();
-
-    // The 'language' cache context is not necessary, because what is printed
-    // here is the language's name in English, not in the language of the
-    // response.
-    foreach ($items as $delta => $item) {
-      $elements[$delta] = array('#markup' => $item->language ? String::checkPlain($item->language->getName()) : '');
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $plugin_id,
+      $plugin_definition,
+      $configuration['field_definition'],
+      $configuration['settings'],
+      $configuration['label'],
+      $configuration['view_mode'],
+      $configuration['third_party_settings'],
+      $container->get('entity.manager'),
+      $container->get('language_manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    $settings = parent::defaultSettings();
+    $settings['native_language'] = FALSE;
+    return $settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form = parent::settingsForm($form, $form_state);
+    $form['native_language'] = array(
+      '#title' => $this->t('Display in native language'),
+      '#type' => 'checkbox',
+      '#default_value' => $this->getSetting('native_language'),
+    );
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsSummary() {
+    $summary = parent::settingsSummary();
+    if ($this->getSetting('native_language')) {
+      $summary[] = $this->t('Displayed in native language');
     }
+    return $summary;
+  }
 
-    return $elements;
+  /**
+   * {@inheritdoc}
+   */
+  protected function viewValue(FieldItemInterface $item) {
+    // The language cache context is not necessary because the language is
+    // either displayed in its configured form (loaded directly from config
+    // storage by LanguageManager::getLanguages()) or in its native language
+    // name. That only depends on formatter settings and no language condition.
+    $languages = $this->getSetting('native_language') ? $this->languageManager->getNativeLanguages() : $this->languageManager->getLanguages();
+    return $item->language ? String::checkPlain($languages[$item->language->getId()]->getName()) : '';
   }
 
 }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php
index ec9b79d7ae2a..56c0ef7a5548 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemInterface;
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -104,12 +105,12 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $build = [];
+    $summary = [];
     if ($this->getSetting('link_to_entity')) {
       $entity_type = $this->entityManager->getDefinition($this->fieldDefinition->getTargetEntityTypeId());
-      $build['#markup'] = $this->t('Linked to the @entity_label', ['@entity_label' => $entity_type->getLabel()]);
+      $summary[] = $this->t('Linked to the @entity_label', ['@entity_label' => $entity_type->getLabel()]);
     }
-    return $build;
+    return $summary;
   }
 
   /**
@@ -125,9 +126,7 @@ public function viewElements(FieldItemListInterface $items) {
     }
 
     foreach ($items as $delta => $item) {
-      // The text value has no text format assigned to it, so the user input
-      // should equal the output, including newlines.
-      $string = nl2br(String::checkPlain($item->value));
+      $string = $this->viewValue($item);
 
       if ($url) {
         $elements[$delta] = [
@@ -144,4 +143,19 @@ public function viewElements(FieldItemListInterface $items) {
     return $elements;
   }
 
+  /**
+   * Generate the output appropriate for one field item.
+   *
+   * @param \Drupal\Core\Field\FieldItemInterface $item
+   *   One field item.
+   *
+   * @return string
+   *   The textual output generated.
+   */
+  protected function viewValue(FieldItemInterface $item) {
+    // The text value has no text format assigned to it, so the user input
+    // should equal the output, including newlines.
+    return nl2br(String::checkPlain($item->value));
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Language/LanguageInterface.php b/core/lib/Drupal/Core/Language/LanguageInterface.php
index c3e39a7137d9..2a1ac1b7c419 100644
--- a/core/lib/Drupal/Core/Language/LanguageInterface.php
+++ b/core/lib/Drupal/Core/Language/LanguageInterface.php
@@ -105,7 +105,8 @@ interface LanguageInterface {
    * Gets the name of the language.
    *
    * @return string
-   *   The human-readable English name of the language.
+   *   The human-readable name of the language (in the language that was
+   *   used to construct this object).
    */
   public function getName();
 
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 11d7d6dcdf71..f66bff29a970 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -497,10 +497,10 @@ function language_field_info_alter(&$info) {
  * Implements hook_entity_field_access()
  */
 function language_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
-  // Only allow access to a langcode field if the entity it is attached to is
-  // configured to have an alterable language.
-  // Without items we can not decide whether or not to allow access.
-  if ($items) {
+  // Only allow edit access on a langcode field if the entity it is attached to
+  // is configured to have an alterable language. Also without items we can not
+  // decide whether or not to allow access.
+  if ($items && $operation == 'edit') {
     // Check if we are dealing with a langcode field.
     $langcode_key = $items->getEntity()->getEntityType()->getKey('langcode');
     if ($field_definition->getName() == $langcode_key) {
diff --git a/core/modules/node/config/schema/node.views.schema.yml b/core/modules/node/config/schema/node.views.schema.yml
index f8fd8c7a1870..42e60d01c4d3 100644
--- a/core/modules/node/config/schema/node.views.schema.yml
+++ b/core/modules/node/config/schema/node.views.schema.yml
@@ -93,14 +93,6 @@ views.argument_validator.node:
       type: string
       label: 'Filter value format'
 
-views.field.node_language:
-  type: views.field.node
-  label: 'Node language'
-  mapping:
-    native_language:
-      type: boolean
-      label: 'Native language'
-
 views.field.node:
   type: views_field
   label: 'Node'
diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php
index 57654b2188e2..79b048122f10 100644
--- a/core/modules/node/src/NodeViewsData.php
+++ b/core/modules/node/src/NodeViewsData.php
@@ -39,7 +39,6 @@ public function getViewsData() {
     $data['node_field_data']['type']['argument']['id'] = 'node_type';
 
     $data['node_field_data']['langcode']['help'] = t('The language of the content or translation.');
-    $data['node_field_data']['langcode']['field']['id'] = 'node_language';
 
     $data['node_field_data']['status']['field']['output formats'] = [
       'published-notpublished' => array(t('Published'), t('Not published')),
@@ -289,7 +288,6 @@ public function getViewsData() {
     ) + $data['node_revision']['vid'];
 
     $data['node_field_revision']['langcode']['help'] = t('The language the original content is in.');
-    $data['node_field_revision']['langcode']['field']['id'] = 'node_language';
 
     $data['node_revision']['revision_log']['field']['id'] = 'xss';
 
@@ -311,7 +309,6 @@ public function getViewsData() {
     $data['node_field_revision']['title']['field']['id'] = 'node_revision';
 
     $data['node_field_revision']['langcode']['help'] = t('The language of the content or translation.');
-    $data['node_field_revision']['langcode']['field']['id'] = 'node_language';
 
     $data['node_revision']['link_to_revision'] = array(
       'field' => array(
diff --git a/core/modules/node/src/Plugin/views/field/Language.php b/core/modules/node/src/Plugin/views/field/Language.php
deleted file mode 100644
index 10acf520e44e..000000000000
--- a/core/modules/node/src/Plugin/views/field/Language.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\node\Plugin\views\field\Language.
- */
-
-namespace Drupal\node\Plugin\views\field;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\node\Plugin\views\field\Node;
-use Drupal\views\ResultRow;
-
-/**
- * Field handler to translate a language into its readable form.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("node_language")
- */
-class Language extends Node {
-
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-    $options['native_language'] = array('default' => FALSE);
-
-    return $options;
-  }
-
-  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
-    parent::buildOptionsForm($form, $form_state);
-    $form['native_language'] = array(
-      '#title' => $this->t('Native language'),
-      '#type' => 'checkbox',
-      '#default_value' => $this->options['native_language'],
-      '#description' => $this->t('If enabled, the native name of the language will be displayed'),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render(ResultRow $values) {
-    // @todo: Drupal Core dropped native language until config translation is
-    // ready, see http://drupal.org/node/1616594.
-    $value = $this->getValue($values);
-    $language = \Drupal::languageManager()->getLanguage($value);
-    $value = $language ? $language->getName() : '';
-    return $this->renderLink($value, $values);
-  }
-
-}
diff --git a/core/modules/node/src/Tests/Views/NodeLanguageTest.php b/core/modules/node/src/Tests/Views/NodeLanguageTest.php
index 4ced144692a4..d2101abaa053 100644
--- a/core/modules/node/src/Tests/Views/NodeLanguageTest.php
+++ b/core/modules/node/src/Tests/Views/NodeLanguageTest.php
@@ -11,6 +11,7 @@
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\Tests\ViewTestData;
+use Drupal\views\Views;
 
 /**
  * Tests node language fields, filters, and sorting.
@@ -22,7 +23,7 @@ class NodeLanguageTest extends NodeTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = array('language');
+  public static $modules = array('language', 'node_test_views');
 
   /**
    * Views used by this test.
@@ -226,4 +227,55 @@ public function testLanguages() {
       }
     }
   }
+
+  /**
+   * Tests native name display in language field.
+   */
+  public function testNativeLanguageField() {
+    $this->assertLanguageNames();
+
+    // Modify test view to display native language names and set translations.
+    $config = $this->config('views.view.test_language');
+    $config->set('display.default.display_options.fields.langcode.settings.native_language', TRUE);
+    $config->save();
+    \Drupal::languageManager()->getLanguageConfigOverride('fr', 'language.entity.fr')->set('label', 'Français')->save();
+    \Drupal::languageManager()->getLanguageConfigOverride('es', 'language.entity.es')->set('label', 'Español')->save();
+    $this->assertLanguageNames(TRUE);
+
+    // Modify test view to use the views built-in language field and test that.
+    \Drupal::state()->set('node_test_views.use_basic_handler', TRUE);
+    Views::viewsData()->clear();
+    $config = $this->config('views.view.test_language');
+    $config->set('display.default.display_options.fields.langcode.native_language', FALSE);
+    $config->clear('display.default.display_options.fields.langcode.settings');
+    $config->clear('display.default.display_options.fields.langcode.type');
+    $config->set('display.default.display_options.fields.langcode.plugin_id', 'language');
+    $config->save();
+    $this->assertLanguageNames();
+    $config->set('display.default.display_options.fields.langcode.native_language', TRUE)->save();
+    $this->assertLanguageNames(TRUE);
+  }
+
+  /**
+   * Asserts the presence of language names in their English or native forms.
+   *
+   * @param bool $native
+   *   (optional) Whether to assert the language name in its native form.
+   */
+  protected function assertLanguageNames($native = FALSE) {
+    $this->drupalGet('test-language');
+    if ($native) {
+      $this->assertText('Français', 'French language shown in native form.');
+      $this->assertText('Español', 'Spanish language shown in native form.');
+      $this->assertNoText('French', 'French language not shown in English.');
+      $this->assertNoText('Spanish', 'Spanish language not shown in English.');
+    }
+    else {
+      $this->assertNoText('Français', 'French language not shown in native form.');
+      $this->assertNoText('Español', 'Spanish language not shown in native form.');
+      $this->assertText('French', 'French language shown in English.');
+      $this->assertText('Spanish', 'Spanish language shown in English.');
+    }
+  }
+
 }
diff --git a/core/modules/node/tests/modules/node_test_views/node_test_views.info.yml b/core/modules/node/tests/modules/node_test_views/node_test_views.info.yml
index 194168fa49a2..27f8b58c6354 100644
--- a/core/modules/node/tests/modules/node_test_views/node_test_views.info.yml
+++ b/core/modules/node/tests/modules/node_test_views/node_test_views.info.yml
@@ -7,3 +7,4 @@ core: 8.x
 dependencies:
   - node
   - views
+  - language
diff --git a/core/modules/node/tests/modules/node_test_views/node_test_views.views.inc b/core/modules/node/tests/modules/node_test_views/node_test_views.views.inc
new file mode 100644
index 000000000000..8882d506da47
--- /dev/null
+++ b/core/modules/node/tests/modules/node_test_views/node_test_views.views.inc
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Provides views data and hooks for node_test_views module.
+ */
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function node_test_views_views_data_alter(array &$data) {
+  // Make node language use the basic field handler if requested.
+  if (\Drupal::state()->get('node_test_views.use_basic_handler')) {
+    $data['node_field_data']['langcode']['field']['id'] = 'language';
+  }
+}
diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml
index 581680fc09a9..088b003cfb90 100644
--- a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml
@@ -159,11 +159,12 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
-          link_to_node: false
-          native_language: false
-          plugin_id: node_language
+          plugin_id: field
           entity_type: node
           entity_field: langcode
+          settings:
+            native_language: false
+          type: language
       filters:
         status:
           value: true
diff --git a/core/modules/taxonomy/config/schema/taxonomy.views.schema.yml b/core/modules/taxonomy/config/schema/taxonomy.views.schema.yml
index 9bda7887e5fb..f4125ab7764f 100644
--- a/core/modules/taxonomy/config/schema/taxonomy.views.schema.yml
+++ b/core/modules/taxonomy/config/schema/taxonomy.views.schema.yml
@@ -83,10 +83,6 @@ views.argument_default.taxonomy_tid:
       type: string
       label: 'Multiple-value handling'
 
-views.field.taxonomy_term_language:
-  type: views.field.taxonomy
-  label: 'Taxonomy language'
-
 views.field.term_link_edit:
   type: views_field
   label: 'Taxonomy language'
diff --git a/core/modules/taxonomy/src/Plugin/views/field/Language.php b/core/modules/taxonomy/src/Plugin/views/field/Language.php
deleted file mode 100644
index 3fbc0b839542..000000000000
--- a/core/modules/taxonomy/src/Plugin/views/field/Language.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\taxonomy\Plugin\views\field\Language.
- */
-
-namespace Drupal\taxonomy\Plugin\views\field;
-
-use Drupal\views\ResultRow;
-
-/**
- * Field handler to show the language of a taxonomy term.
- *
- * @ViewsField("taxonomy_term_language")
- */
-class Language extends Taxonomy {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render(ResultRow $values) {
-    $value = $this->getValue($values);
-    $language = \Drupal::languageManager()->getLanguage($value);
-    $value = $language ? $language->getName() : '';
-
-    return $this->renderLink($this->sanitizeValue($value), $values);
-  }
-
-}
diff --git a/core/modules/taxonomy/src/TermViewsData.php b/core/modules/taxonomy/src/TermViewsData.php
index f65b4997fe5a..d101f84ba0c1 100644
--- a/core/modules/taxonomy/src/TermViewsData.php
+++ b/core/modules/taxonomy/src/TermViewsData.php
@@ -100,8 +100,6 @@ public function getViewsData() {
 
     $data['taxonomy_term_field_data']['description__value']['field']['click sortable'] = FALSE;
 
-    $data['taxonomy_term_field_data']['langcode']['field']['id'] = 'taxonomy_term_language';
-
     $data['taxonomy_term_field_data']['changed']['title'] = t('Updated date');
     $data['taxonomy_term_field_data']['changed']['help'] = t('The date the term was last updated.');
 
diff --git a/core/modules/user/config/schema/user.views.schema.yml b/core/modules/user/config/schema/user.views.schema.yml
index 6a84b185191b..16573f43642e 100644
--- a/core/modules/user/config/schema/user.views.schema.yml
+++ b/core/modules/user/config/schema/user.views.schema.yml
@@ -67,10 +67,6 @@ views_field_user:
       type: boolean
       label: 'Link this field to its user'
 
-views.field.user_language:
-  type: views_field_user
-  label: 'User language'
-
 views.field.user_link:
   type: views_field
   label: 'User link'
diff --git a/core/modules/user/src/Plugin/views/field/Language.php b/core/modules/user/src/Plugin/views/field/Language.php
deleted file mode 100644
index 708747d9ed3d..000000000000
--- a/core/modules/user/src/Plugin/views/field/Language.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\user\Plugin\views\field\Language.
- */
-
-namespace Drupal\user\Plugin\views\field;
-
-use Drupal\Core\Url;
-use Drupal\views\ResultRow;
-
-/**
- * Views field handler for user language.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("user_language")
- */
-class Language extends User {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function renderLink($data, ResultRow $values) {
-    if (!empty($this->options['link_to_user'])) {
-      $uid = $this->getValue($values, 'uid');
-      if ($this->view->getUser()->hasPermission('access user profiles') && $uid) {
-        $this->options['alter']['make_link'] = TRUE;
-        $this->options['alter']['url'] = Url::fromRoute('entity.user.canonical', ['user' => $uid]);
-      }
-    }
-    if (empty($data)) {
-      $lang = \Drupal::languageManager()->getDefaultLanguage();
-    }
-    else {
-      $lang = \Drupal::languageManager()->getLanguages();
-      $lang = $lang[$data];
-    }
-
-    return $this->sanitizeValue($lang->getName());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render(ResultRow $values) {
-    $value = $this->getValue($values);
-    return $this->renderLink($this->sanitizeValue($value), $values);
-  }
-
-}
diff --git a/core/modules/user/src/UserViewsData.php b/core/modules/user/src/UserViewsData.php
index b44345e57892..00222cba1cab 100644
--- a/core/modules/user/src/UserViewsData.php
+++ b/core/modules/user/src/UserViewsData.php
@@ -88,7 +88,6 @@ public function getViewsData() {
     $data['users_field_data']['mail']['help'] = t('Email address for a given user. This field is normally not shown to users, so be cautious when using it.');
     $data['users_field_data']['mail']['field']['id'] = 'user_mail';
 
-    $data['users_field_data']['langcode']['id'] = 'user_language';
     $data['users_field_data']['langcode']['help'] = t('Original language of the user information');
     $data['users_field_data']['langcode']['help'] = t('Language of the translation of user information');
 
diff --git a/core/modules/views/config/schema/views.field.schema.yml b/core/modules/views/config/schema/views.field.schema.yml
index b12c53412a8d..ba25176d3b28 100644
--- a/core/modules/views/config/schema/views.field.schema.yml
+++ b/core/modules/views/config/schema/views.field.schema.yml
@@ -178,6 +178,10 @@ views.field.xss:
 views.field.language:
   type: views_field
   label: 'Language'
+  mapping:
+    native_language:
+      type: boolean
+      label: 'Display in native language'
 
 views.field.bulk_form:
   type: views_field_bulk_form
diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php
index 88b0fcebc4a2..45bfb04ed29b 100644
--- a/core/modules/views/src/EntityViewsData.php
+++ b/core/modules/views/src/EntityViewsData.php
@@ -319,7 +319,7 @@ protected function mapSingleFieldViewsData($table, $field_name, $field_type, $co
         break;
 
       case 'language':
-        $views_field['field']['id'] = 'language';
+        $views_field['field']['id'] = 'field';
         $views_field['argument']['id'] = 'language';
         $views_field['filter']['id'] = 'language';
         $views_field['sort']['id'] = 'standard';
diff --git a/core/modules/views/src/Plugin/views/field/LanguageField.php b/core/modules/views/src/Plugin/views/field/LanguageField.php
index 7c13e947d6fb..bbc28ef3767d 100644
--- a/core/modules/views/src/Plugin/views/field/LanguageField.php
+++ b/core/modules/views/src/Plugin/views/field/LanguageField.php
@@ -35,10 +35,9 @@ protected function defineOptions() {
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['native_language'] = array(
-      '#title' => $this->t('Native language'),
+      '#title' => $this->t('Display in native language'),
       '#type' => 'checkbox',
       '#default_value' => $this->options['native_language'],
-      '#description' => $this->t('If enabled, the native name of the language will be displayed'),
     );
   }
 
@@ -46,11 +45,9 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    // @todo: Drupal Core dropped native language until config translation is
-    // ready, see http://drupal.org/node/1616594.
     $value = $this->getValue($values);
-    $language = \Drupal::languageManager()->getLanguage($value);
-    return $language ? $language->getName() : '';
+    $languages = $this->options['native_language'] ? \Drupal::languageManager()->getNativeLanguages() : \Drupal::languageManager()->getLanguages();
+    return isset($languages[$value]) ? $languages[$value]->getName() : '';
   }
 
 }
diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
index 5822fe113f39..8e519c442d8f 100644
--- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
+++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
@@ -783,7 +783,7 @@ protected function assertNumericField($data) {
    *   The views data to check.
    */
   protected function assertLanguageField($data) {
-    $this->assertEquals('language', $data['field']['id']);
+    $this->assertEquals('field', $data['field']['id']);
     $this->assertEquals('language', $data['filter']['id']);
     $this->assertEquals('language', $data['argument']['id']);
     $this->assertEquals('standard', $data['sort']['id']);
-- 
GitLab