From 8a79e0fe9f716f17992b00c5d3df2a7e251d296d Mon Sep 17 00:00:00 2001 From: catch <catch@35733.no-reply.drupal.org> Date: Thu, 29 Feb 2024 13:30:30 +0000 Subject: [PATCH] =?UTF-8?q?Issue=20#2473989=20by=20srishtiiee,=20narendraR?= =?UTF-8?q?,=20dawehner,=20kunal.sachdev,=20ravi.shankar,=20lauriii,=20Pea?= =?UTF-8?q?cog,=20smustgrave,=20swentel,=20martin107,=20Sonal.Sangale,=20s?= =?UTF-8?q?haal,=20baikho,=20amateescu,=20plach,=20cpj,=20G=C3=A1bor=20Hoj?= =?UTF-8?q?tsy,=20jhodgdon,=20quietone,=20webchick,=20aspilicious,=20catch?= =?UTF-8?q?,=20xjm,=20alexpott:=20Lack=20of=20dynamic=20language=20field?= =?UTF-8?q?=20/=20filter=20makes=20shipping=20core=20views=20hard=20to=20b?= =?UTF-8?q?e=20both=20compatible=20with=20mono=20and=20multilingual?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 74851391d8202aad7d075c149c44104bd655ec9f) --- .../FieldFormatter/LanguageFormatter.php | 12 +++- .../src/Functional/Views/CommentAdminTest.php | 14 ++++ .../src/Functional/MediaOverviewPageTest.php | 8 +++ .../config/optional/views.view.content.yml | 66 +++++++++++++++++++ .../tests/src/Functional/NodeAdminTest.php | 59 +++++++++++++++++ .../Kernel/Views/NodeViewsFieldAccessTest.php | 3 + core/modules/views/src/EntityViewsData.php | 2 +- .../src/Plugin/views/field/FieldLanguage.php | 25 +++++++ .../Plugin/views/filter/LanguageFilter.php | 12 +++- .../PaginationAJAXTest.php | 6 +- .../src/Kernel/Entity/EntityViewsDataTest.php | 2 +- .../EntityTestViewsFieldAccessTest.php | 3 + .../Handler/FieldFieldAccessTestBase.php | 2 +- 13 files changed, 203 insertions(+), 11 deletions(-) create mode 100644 core/modules/views/src/Plugin/views/field/FieldLanguage.php 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 6acabfa69602..23a0085367ba 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/LanguageFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/LanguageFormatter.php @@ -117,9 +117,15 @@ protected function viewValue(FieldItemInterface $item) { // 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(LanguageInterface::STATE_ALL) : $this->languageManager->getLanguages(LanguageInterface::STATE_ALL); - return [ - '#plain_text' => $item->language && isset($languages[$item->language->getId()]) ? $languages[$item->language->getId()]->getName() : '', - ]; + // \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED + // and \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_APPLICABLE are + // not returned from the language manager above. + $value = []; + if (isset($item->language)) { + $name = isset($languages[$item->language->getId()]) ? $languages[$item->language->getId()]->getName() : $item->language->getId(); + $value = ['#plain_text' => $name]; + } + return $value; } } diff --git a/core/modules/comment/tests/src/Functional/Views/CommentAdminTest.php b/core/modules/comment/tests/src/Functional/Views/CommentAdminTest.php index 68124ab88023..2676189c1208 100644 --- a/core/modules/comment/tests/src/Functional/Views/CommentAdminTest.php +++ b/core/modules/comment/tests/src/Functional/Views/CommentAdminTest.php @@ -9,6 +9,7 @@ use Drupal\comment\CommentInterface; use Drupal\comment\Entity\Comment; use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; +use Drupal\language\Entity\ConfigurableLanguage; use Drupal\Tests\comment\Functional\CommentTestBase as CommentBrowserTestBase; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Unicode; @@ -27,11 +28,24 @@ class CommentAdminTest extends CommentBrowserTestBase { */ protected $defaultTheme = 'stark'; + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'language', + ]; + /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); + // Make the site multilingual to have a working language field handler. + ConfigurableLanguage::create([ + 'id' => 'es', + 'title' => 'Spanish title', + 'label' => 'Spanish label', + ])->save(); \Drupal::service('module_installer')->install(['views']); $view = Views::getView('comment'); $view->storage->enable()->save(); diff --git a/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php b/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php index a0fcb6c726b9..7d1f63e38c1f 100644 --- a/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php +++ b/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\media\Functional; +use Drupal\language\Entity\ConfigurableLanguage; use Drupal\media\Entity\Media; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; @@ -20,11 +21,18 @@ class MediaOverviewPageTest extends MediaFunctionalTestBase { */ protected $defaultTheme = 'stark'; + /** + * {@inheritdoc} + */ + protected static $modules = ['language']; + /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); + // Make the site multilingual to have a working language field handler. + ConfigurableLanguage::create(['id' => 'es', 'title' => 'Spanish title', 'label' => 'Spanish label'])->save(); $this->drupalLogin($this->nonAdminUser); } diff --git a/core/modules/node/config/optional/views.view.content.yml b/core/modules/node/config/optional/views.view.content.yml index cde82e51e396..20d6dad58a75 100644 --- a/core/modules/node/config/optional/views.view.content.yml +++ b/core/modules/node/config/optional/views.view.content.yml @@ -193,6 +193,72 @@ display: past_format: '@interval ago' granularity: 2 refresh: 60 + langcode: + id: langcode + table: node_field_data + field: langcode + relationship: none + group_type: group + admin_label: '' + entity_type: node + entity_field: langcode + plugin_id: field + label: 'Language' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: language + settings: + link_to_entity: false + native_language: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false operations: id: operations table: node diff --git a/core/modules/node/tests/src/Functional/NodeAdminTest.php b/core/modules/node/tests/src/Functional/NodeAdminTest.php index fddd7fa3ff32..f0e4c5bca546 100644 --- a/core/modules/node/tests/src/Functional/NodeAdminTest.php +++ b/core/modules/node/tests/src/Functional/NodeAdminTest.php @@ -5,6 +5,7 @@ namespace Drupal\Tests\node\Functional; use Drupal\Core\Database\Database; +use Drupal\language\Entity\ConfigurableLanguage; use Drupal\user\RoleInterface; /** @@ -229,6 +230,64 @@ public function testContentAdminPages() { $this->assertSession()->linkByHrefExists('node/' . $node->id() . '/edit'); $this->assertSession()->linkByHrefExists('node/' . $node->id() . '/delete'); } + // Ensure that the language table column and the language exposed filter are + // not visible on monolingual sites. + $this->assertSession()->fieldNotExists('langcode'); + $this->assertEquals(0, count($this->cssSelect('td.views-field-langcode'))); + $this->assertEquals(0, count($this->cssSelect('td.views-field-langcode'))); + } + + /** + * Tests content overview for a multilingual site. + */ + public function testContentAdminPageMultilingual() { + $this->drupalLogin($this->adminUser); + + \Drupal::service('module_installer')->install(['language']); + ConfigurableLanguage::create([ + 'id' => 'es', + 'label' => 'Spanish', + ])->save(); + + $this->drupalCreateNode(['type' => 'page', 'title' => 'English title']) + ->addTranslation('es') + ->setTitle('Spanish title') + ->save(); + + $this->drupalGet('admin/content'); + + // Ensure that both the language table column as well as the language + // exposed filter are visible on multilingual sites. + $this->assertSession()->fieldExists('langcode'); + $this->assertEquals(2, count($this->cssSelect('td.views-field-langcode'))); + $this->assertEquals(2, count($this->cssSelect('td.views-field-langcode'))); + + $this->assertSession()->pageTextContains('English title'); + $this->assertSession()->pageTextContains('Spanish title'); + + $this->drupalGet('admin/content', ['query' => ['langcode' => '***LANGUAGE_site_default***']]); + $this->assertSession()->pageTextContains('English title'); + $this->assertSession()->pageTextNotContains('Spanish title'); + + $this->drupalGet('admin/content', ['query' => ['langcode' => 'en']]); + $this->assertSession()->pageTextContains('English title'); + $this->assertSession()->pageTextNotContains('Spanish title'); + + $this->drupalGet('admin/content', ['query' => ['langcode' => 'und']]); + $this->assertSession()->pageTextNotContains('English title'); + $this->assertSession()->pageTextNotContains('Spanish title'); + + $this->drupalGet('admin/content', ['query' => ['langcode' => 'zxx']]); + $this->assertSession()->pageTextNotContains('English title'); + $this->assertSession()->pageTextNotContains('Spanish title'); + + $this->drupalGet('admin/content', ['query' => ['langcode' => html_entity_decode('***LANGUAGE_language_interface***')]]); + $this->assertSession()->pageTextContains('English title'); + $this->assertSession()->pageTextNotContains('Spanish title'); + + $this->drupalGet('es/admin/content', ['query' => ['langcode' => html_entity_decode('***LANGUAGE_language_interface***')]]); + $this->assertSession()->pageTextNotContains('English title'); + $this->assertSession()->pageTextContains('Spanish title'); } } diff --git a/core/modules/node/tests/src/Kernel/Views/NodeViewsFieldAccessTest.php b/core/modules/node/tests/src/Kernel/Views/NodeViewsFieldAccessTest.php index a4b6a0e2b988..8c09c23a4b49 100644 --- a/core/modules/node/tests/src/Kernel/Views/NodeViewsFieldAccessTest.php +++ b/core/modules/node/tests/src/Kernel/Views/NodeViewsFieldAccessTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\node\Kernel\Views; +use Drupal\language\Entity\ConfigurableLanguage; use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\user\Entity\User; @@ -26,6 +27,8 @@ protected function setUp($import_test_views = TRUE): void { parent::setUp($import_test_views); $this->installEntitySchema('node'); + // Make the site multilingual to have a working language field handler. + ConfigurableLanguage::create(['id' => 'es', 'title' => 'Spanish title', 'label' => 'Spanish label'])->save(); } /** diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index eb964521afab..8acb1ad2979f 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -509,7 +509,7 @@ protected function mapSingleFieldViewsData($table, $field_name, $field_type, $co break; case 'language': - $views_field['field']['id'] = 'field'; + $views_field['field']['id'] = 'field_language'; $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/FieldLanguage.php b/core/modules/views/src/Plugin/views/field/FieldLanguage.php new file mode 100644 index 000000000000..90ab86dc33ed --- /dev/null +++ b/core/modules/views/src/Plugin/views/field/FieldLanguage.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\views\Plugin\views\field; + +use Drupal\Core\Session\AccountInterface; + +/** + * Displays the language of an entity. + * + * @ingroup views_field_handlers + * + * @ViewsField("field_language") + */ +class FieldLanguage extends EntityField { + + /** + * {@inheritdoc} + */ + public function access(AccountInterface $account): bool { + // No point in displaying the language field on monolingual sites, + // as only one language value is available. + return $this->languageManager->isMultilingual() && parent::access($account); + } + +} diff --git a/core/modules/views/src/Plugin/views/filter/LanguageFilter.php b/core/modules/views/src/Plugin/views/filter/LanguageFilter.php index 69fdc81a1fd1..4c25b4cd4ac6 100644 --- a/core/modules/views/src/Plugin/views/filter/LanguageFilter.php +++ b/core/modules/views/src/Plugin/views/filter/LanguageFilter.php @@ -5,6 +5,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\views\Plugin\views\PluginBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -71,8 +72,8 @@ public function getValueOptions() { * {@inheritdoc} */ public function query() { - // Don't filter by language in case the site is not multilingual, because - // there is no point in doing so. + // No point in displaying the language filter on monolingual sites, + // as only one language value is available. if (!$this->languageManager->isMultilingual()) { return; } @@ -80,4 +81,11 @@ public function query() { parent::query(); } + /** + * {@inheritdoc} + */ + public function access(AccountInterface $account): bool { + return $this->languageManager->isMultilingual() && parent::access($account); + } + } diff --git a/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php b/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php index 6b1b5e360c26..c2019bb8c2d9 100644 --- a/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php +++ b/core/modules/views/tests/src/FunctionalJavascript/PaginationAJAXTest.php @@ -107,7 +107,7 @@ public function testBasicPagination() { $this->assertNoDuplicateAssetsOnPage(); // Test that no unwanted parameters are added to the URL. - $this->assertEquals('?status=All&type=All&title=&langcode=All&items_per_page=5&order=changed&sort=asc&page=2', $link->getAttribute('href')); + $this->assertEquals('?status=All&type=All&title=&items_per_page=5&order=changed&sort=asc&page=2', $link->getAttribute('href')); $this->clickLink('Go to page 3'); $session_assert->assertWaitOnAjaxRequest(); @@ -191,7 +191,7 @@ public function testDefaultFilterPagination() { $this->assertNoDuplicateAssetsOnPage(); // Test that no unwanted parameters are added to the URL. - $this->assertEquals('?status=All&type=All&title=default_value&langcode=All&items_per_page=5&order=changed&sort=asc&page=0', $link->getAttribute('href')); + $this->assertEquals('?status=All&type=All&title=default_value&items_per_page=5&order=changed&sort=asc&page=0', $link->getAttribute('href')); // Set the title filter to empty string using the exposed pager. $page->fillField('title', ''); @@ -211,7 +211,7 @@ public function testDefaultFilterPagination() { $this->assertNoDuplicateAssetsOnPage(); // Test that no unwanted parameters are added to the URL. - $this->assertEquals('?status=All&type=All&title=&langcode=All&items_per_page=5&page=0', $link->getAttribute('href')); + $this->assertEquals('?status=All&type=All&title=&items_per_page=5&page=0', $link->getAttribute('href')); // Navigate back to the first page. $this->clickLink('Go to first page'); diff --git a/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php b/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php index c64a7c150f4a..4b2ae97e81c1 100644 --- a/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php +++ b/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php @@ -771,7 +771,7 @@ protected function assertNumericField(array $data): void { * @internal */ protected function assertLanguageField(array $data): void { - $this->assertEquals('field', $data['field']['id']); + $this->assertEquals('field_language', $data['field']['id']); $this->assertEquals('language', $data['filter']['id']); $this->assertEquals('language', $data['argument']['id']); $this->assertEquals('standard', $data['sort']['id']); diff --git a/core/modules/views/tests/src/Kernel/Handler/EntityTestViewsFieldAccessTest.php b/core/modules/views/tests/src/Kernel/Handler/EntityTestViewsFieldAccessTest.php index e2812f99e692..148bf98e0298 100644 --- a/core/modules/views/tests/src/Kernel/Handler/EntityTestViewsFieldAccessTest.php +++ b/core/modules/views/tests/src/Kernel/Handler/EntityTestViewsFieldAccessTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\views\Kernel\Handler; use Drupal\entity_test\Entity\EntityTest; +use Drupal\language\Entity\ConfigurableLanguage; /** * Tests base field access in Views for the entity_test entity. @@ -23,6 +24,8 @@ protected function setUp($import_test_views = TRUE): void { parent::setUp($import_test_views); $this->installEntitySchema('entity_test'); + // Make the site multilingual to have a working language field handler. + ConfigurableLanguage::create(['id' => 'es', 'title' => 'Spanish title', 'label' => 'Spanish label'])->save(); } public function testEntityTestFields() { diff --git a/core/modules/views/tests/src/Kernel/Handler/FieldFieldAccessTestBase.php b/core/modules/views/tests/src/Kernel/Handler/FieldFieldAccessTestBase.php index 7155b25d8249..bd1051f9446a 100644 --- a/core/modules/views/tests/src/Kernel/Handler/FieldFieldAccessTestBase.php +++ b/core/modules/views/tests/src/Kernel/Handler/FieldFieldAccessTestBase.php @@ -30,7 +30,7 @@ abstract class FieldFieldAccessTestBase extends ViewsKernelTestBase { /** * {@inheritdoc} */ - protected static $modules = ['user']; + protected static $modules = ['user', 'language']; /** * {@inheritdoc} -- GitLab