diff --git a/core/modules/media_library/config/install/views.view.media_library.yml b/core/modules/media_library/config/install/views.view.media_library.yml index b298e31c5b44f3c59677a01e630b17cc776ba01f..e931f107c7b4c71c671e2955714db4cff4f7648f 100644 --- a/core/modules/media_library/config/install/views.view.media_library.yml +++ b/core/modules/media_library/config/install/views.view.media_library.yml @@ -364,6 +364,49 @@ display: group_items: { } entity_type: media plugin_id: media_status + langcode: + id: langcode + table: media_field_data + field: langcode + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: langcode_op + label: Language + description: '' + use_operator: false + operator: langcode_op + identifier: langcode + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: media + entity_field: langcode + plugin_id: language sorts: created: id: created @@ -941,6 +984,46 @@ display: entity_type: media entity_field: name plugin_id: string + default_langcode: + id: default_langcode + table: media_field_data + field: default_langcode + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: media + entity_field: default_langcode + plugin_id: boolean filter_groups: operator: AND groups: @@ -1005,6 +1088,7 @@ display: plugin_id: display_link empty: true css_class: 'media-library-view js-media-library-view media-library-view--widget' + rendering_language: '***LANGUAGE_language_interface***' cache_metadata: max-age: -1 contexts: @@ -1188,6 +1272,46 @@ display: entity_type: media entity_field: name plugin_id: string + default_langcode: + id: default_langcode + table: media_field_data + field: default_langcode + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: media + entity_field: default_langcode + plugin_id: boolean filter_groups: operator: AND groups: @@ -1252,10 +1376,10 @@ display: plugin_id: display_link empty: true css_class: 'media-library-view js-media-library-view media-library-view--widget' + rendering_language: '***LANGUAGE_language_interface***' cache_metadata: max-age: -1 contexts: - - 'languages:language_content' - 'languages:language_interface' - url - url.query_args diff --git a/core/modules/media_library/media_library.post_update.php b/core/modules/media_library/media_library.post_update.php index 34728a89e862655737f924e1572742818089db2f..876fde8298aa8dcf9a66329a4a5d3dc5dd67c78f 100644 --- a/core/modules/media_library/media_library.post_update.php +++ b/core/modules/media_library/media_library.post_update.php @@ -176,6 +176,7 @@ function media_library_post_update_table_display() { $table_display->overrideOption('access', $grid_display->getOption('access')); $table_display->overrideOption('filters', $grid_display->getOption('filters')); $table_display->overrideOption('arguments', $grid_display->getOption('arguments')); + $table_display->overrideOption('rendering_language', $grid_display->getOption('rendering_language')); // Also override the sorts and pager if the grid display has overrides. $defaults = $grid_display->getOption('defaults'); @@ -613,3 +614,163 @@ function media_library_post_update_default_administrative_list_to_table_display( $view->storage->save(); } } + +/** + * Add langcode filters to media library view displays. + */ +function media_library_post_update_add_langcode_filters() { + $view = Views::getView('media_library'); + + if (!$view) { + return; + } + + // Fetch the filters from the default display and add the new 'langcode' + // filter if it does not yet exist. + $default_display = $view->getDisplay(); + $filters = $default_display->getOption('filters'); + + $added_langcode = FALSE; + if (!isset($filters['langcode'])) { + $filters['langcode'] = [ + 'id' => 'langcode', + 'table' => 'media_field_data', + 'field' => 'langcode', + 'relationship' => 'none', + 'group_type' => 'group', + 'admin_label' => '', + 'operator' => 'in', + 'value' => [], + 'group' => 1, + 'exposed' => TRUE, + 'expose' => [ + 'use_operator' => FALSE, + 'remember' => FALSE, + 'operator_id' => 'langcode_op', + 'multiple' => FALSE, + 'description' => '', + 'required' => FALSE, + 'reduce' => FALSE, + 'label' => 'Language', + 'operator_limit_selection' => FALSE, + 'operator' => 'langcode_op', + 'identifier' => 'langcode', + 'operator_list' => [], + 'remember_roles' => [ + 'administrator' => '0', + 'authenticated' => 'authenticated', + 'anonymous' => '0', + ], + ], + 'is_grouped' => FALSE, + 'group_info' => [ + 'widget' => 'select', + 'group_items' => [], + 'multiple' => FALSE, + 'description' => '', + 'default_group_multiple' => [], + 'default_group' => 'All', + 'label' => '', + 'identifier' => '', + 'optional' => TRUE, + 'remember' => FALSE, + ], + 'entity_type' => 'media', + 'entity_field' => 'langcode', + 'plugin_id' => 'language', + ]; + $default_display->setOption('filters', $filters); + $added_langcode = TRUE; + } + + $added_default_langcode_displays = []; + foreach (['widget', 'widget_table'] as $display_id) { + // Check if the display still exists, or else skip it. + if (!$view->displayHandlers->has($display_id)) { + continue; + } + + $view->setDisplay($display_id); + $display = $view->getDisplay(); + + // Fetch the filters from the display and add the 'default_langcode' filter + // if it does not yet exist. + $filters = $display->getOption('filters'); + if (!isset($filters['default_langcode'])) { + $filters['default_langcode'] = [ + 'id' => 'default_langcode', + 'table' => 'media_field_data', + 'field' => 'default_langcode', + 'relationship' => 'none', + 'group_type' => 'group', + 'admin_label' => '', + 'operator' => '=', + 'value' => '1', + 'group' => 1, + 'exposed' => FALSE, + 'expose' => [ + 'use_operator' => FALSE, + 'remember' => FALSE, + 'operator_id' => '', + 'multiple' => FALSE, + 'description' => '', + 'required' => FALSE, + 'label' => '', + 'operator_limit_selection' => FALSE, + 'operator' => '', + 'identifier' => '', + 'operator_list' => [], + 'remember_roles' => [ + RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID, + ], + ], + 'is_grouped' => FALSE, + 'group_info' => [ + 'widget' => 'select', + 'group_items' => [], + 'multiple' => FALSE, + 'description' => '', + 'default_group_multiple' => [], + 'default_group' => 'All', + 'label' => '', + 'identifier' => '', + 'optional' => TRUE, + 'remember' => FALSE, + ], + 'entity_type' => 'media', + 'entity_field' => 'default_langcode', + 'plugin_id' => 'boolean', + ]; + $display->setOption('filters', $filters); + + // Change the rendering language of the rows to the interface language. + $display->setOption('rendering_language', '***LANGUAGE_language_interface***'); + + $added_default_langcode_displays[] = $view->storage->get('display')[$display_id]['display_title']; + } + } + + if ($added_langcode && $added_default_langcode_displays) { + $view->save(); + return t("The 'Language' filter was added to the default display of the %label view and the 'Default translation' filter was added to the following displays: %displays", [ + '%label' => $view->storage->label(), + '%displays' => implode(', ', $added_default_langcode_displays), + ]); + } + + if ($added_langcode) { + $view->save(); + return t("The 'Language' filter was added to the default display of the %label view.", [ + '%label' => $view->storage->label(), + '%displays' => implode(', ', $added_default_langcode_displays), + ]); + } + + if ($added_default_langcode_displays) { + $view->save(); + return t("The 'Default translation' filter was added to the following %label view displays: %displays", [ + '%label' => $view->storage->label(), + '%displays' => implode(', ', $added_default_langcode_displays), + ]); + } +} diff --git a/core/modules/media_library/tests/src/Functional/Update/MediaLibraryUpdateViewLangcodeFiltersTest.php b/core/modules/media_library/tests/src/Functional/Update/MediaLibraryUpdateViewLangcodeFiltersTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bec98b28f162ab4cc0c03d0a9f88e7bd0000f3cb --- /dev/null +++ b/core/modules/media_library/tests/src/Functional/Update/MediaLibraryUpdateViewLangcodeFiltersTest.php @@ -0,0 +1,82 @@ +<?php + +namespace Drupal\Tests\media_library\Functional\Update; + +use Drupal\FunctionalTests\Update\UpdatePathTestBase; + +/** + * Tests the media library module updates for the langcode filters. + * + * @group media_library + * @group legacy + */ +class MediaLibraryUpdateViewLangcodeFiltersTest extends UpdatePathTestBase { + + /** + * {@inheritdoc} + */ + protected function setDatabaseDumpFiles() { + $this->databaseDumpFiles = [ + __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz', + __DIR__ . '/../../../../../media/tests/fixtures/update/drupal-8.4.0-media_installed.php', + __DIR__ . '/../../../fixtures/update/drupal-8.7.2-media_library_installed.php', + ]; + } + + /** + * Tests that the langcode filters are added to the media library view. + * + * @see media_library_post_update_add_langcode_filters() + */ + public function testMediaLibraryViewStatusExtraFilter() { + $config = $this->config('views.view.media_library'); + // We don't have any language filters yet for all displays. + $this->assertNull($config->get('display.default.display_options.filters.langcode')); + $this->assertNull($config->get('display.default.display_options.filters.default_langcode')); + $this->assertNull($config->get('display.widget.display_options.filters.langcode')); + $this->assertNull($config->get('display.widget.display_options.filters.default_langcode')); + $this->assertNull($config->get('display.widget_table.display_options.filters.langcode')); + $this->assertNull($config->get('display.widget_table.display_options.filters.default_langcode')); + // The rendering language should not be set for the displays. + $this->assertNull($config->get('display.default.display_options.rendering_language')); + $this->assertNull($config->get('display.widget.display_options.rendering_language')); + $this->assertNull($config->get('display.widget_table.display_options.rendering_language')); + + $this->runUpdates(); + + $config = $this->config('views.view.media_library'); + + // The update should add the langcode filter to the default display only. + $this->assertNull($config->get('display.widget.display_options.filters.langcode')); + $this->assertNull($config->get('display.widget_table.display_options.filters.langcode')); + $default_langcode_filter = $config->get('display.default.display_options.filters.langcode'); + $this->assertInternalType('array', $default_langcode_filter); + $this->assertSame('langcode', $default_langcode_filter['field']); + $this->assertSame('media', $default_langcode_filter['entity_type']); + $this->assertSame('language', $default_langcode_filter['plugin_id']); + $this->assertSame('langcode', $default_langcode_filter['id']); + $this->assertTrue($default_langcode_filter['exposed']); + + // The update should add the default_langcode filter to the widget displays + // only. + $this->assertNull($config->get('display.default.display_options.filters.default_langcode')); + foreach (['widget', 'widget_table'] as $display_id) { + $filter = $config->get('display.' . $display_id . '.display_options.filters.default_langcode'); + $this->assertInternalType('array', $filter); + $this->assertSame('default_langcode', $filter['field']); + $this->assertSame('media', $filter['entity_type']); + $this->assertSame('boolean', $filter['plugin_id']); + $this->assertSame('default_langcode', $filter['id']); + $this->assertFalse($filter['exposed']); + } + + // The default display should use the default rendering language, which is + // the language of the content. + $this->assertNull($config->get('display.default.display_options.rendering_language')); + // The rendering language of the row should be set to the interface + // language. + $this->assertSame('***LANGUAGE_language_interface***', $config->get('display.widget.display_options.rendering_language')); + $this->assertSame('***LANGUAGE_language_interface***', $config->get('display.widget_table.display_options.rendering_language')); + } + +} diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/TranslationsTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/TranslationsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2696fca6318c9e4daa7da89abe4bc2b42ada7679 --- /dev/null +++ b/core/modules/media_library/tests/src/FunctionalJavascript/TranslationsTest.php @@ -0,0 +1,168 @@ +<?php + +namespace Drupal\Tests\media_library\FunctionalJavascript; + +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\file\Entity\File; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; +use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\media\Entity\Media; +use Drupal\Tests\field\Traits\EntityReferenceTestTrait; +use Drupal\Tests\media\Traits\MediaTypeCreationTrait; +use Drupal\Tests\TestFileCreationTrait; + +/** + * Tests media library for translatable media. + * + * @group media_library + */ +class TranslationsTest extends WebDriverTestBase { + + use EntityReferenceTestTrait; + use MediaTypeCreationTrait; + use TestFileCreationTrait; + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'content_translation', + 'field', + 'media', + 'media_library', + 'node', + 'views', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Create some languages. + foreach (['nl', 'es'] as $langcode) { + ConfigurableLanguage::createFromLangcode($langcode)->save(); + } + + // Create an image media type and article node type. + $this->createMediaType('image', ['id' => 'image']); + $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']); + + // Make the media translatable and ensure the change is picked up. + \Drupal::service('content_translation.manager')->setEnabled('media', 'image', TRUE); + + // Create a media reference field on articles. + $this->createEntityReferenceField( + 'node', + 'article', + 'field_media', + 'Media', + 'media', + 'default', + ['target_bundles' => ['image']], + FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED + ); + // Add the media field to the form display. + \Drupal::service('entity_display.repository')->getFormDisplay('node', 'article') + ->setComponent('field_media', ['type' => 'media_library_widget']) + ->save(); + + // Create a file to user for our images. + $image = File::create([ + 'uri' => $this->getTestFiles('image')[0]->uri, + ]); + $image->setPermanent(); + $image->save(); + + // Create a translated and untranslated media item in each language. + $media_items = [ + ['nl' => 'Eekhoorn', 'es' => 'Ardilla'], + ['es' => 'Zorro', 'nl' => 'Vos'], + ['nl' => 'Hert'], + ['es' => 'Tejón'], + ]; + foreach ($media_items as $translations) { + $default_langcode = key($translations); + $default_name = array_shift($translations); + + $media = Media::create([ + 'name' => $default_name, + 'bundle' => 'image', + 'field_media_image' => $image, + 'langcode' => $default_langcode, + ]); + foreach ($translations as $langcode => $name) { + $media->addTranslation($langcode, ['name' => $name]); + } + $media->save(); + } + + $user = $this->drupalCreateUser([ + 'access administration pages', + 'access content', + 'access media overview', + 'edit own article content', + 'create article content', + 'administer media', + ]); + $this->drupalLogin($user); + } + + /** + * Tests the media library widget shows all media only once. + */ + public function testMediaLibraryTranslations() { + $assert_session = $this->assertSession(); + $page = $this->getSession()->getPage(); + + // All translations should be shown in the administration overview, + // regardless of the interface language. + $this->drupalGet('nl/admin/content/media-grid'); + $assert_session->elementsCount('css', '.media-library-item', 6); + $media_items = $page->findAll('css', '.media-library-item__name'); + $media_names = []; + foreach ($media_items as $media_item) { + $media_names[] = $media_item->getText(); + } + sort($media_names); + $this->assertSame(['Ardilla', 'Eekhoorn', 'Hert', 'Tejón', 'Vos', 'Zorro'], $media_names); + + $this->drupalGet('es/admin/content/media-grid'); + $assert_session->elementsCount('css', '.media-library-item', 6); + $media_items = $page->findAll('css', '.media-library-item__name'); + $media_names = []; + foreach ($media_items as $media_item) { + $media_names[] = $media_item->getText(); + } + sort($media_names); + $this->assertSame(['Ardilla', 'Eekhoorn', 'Hert', 'Tejón', 'Vos', 'Zorro'], $media_names); + + // All media should only be shown once, and should be shown in the interface + // language. + $this->drupalGet('nl/node/add/article'); + $assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click(); + $assert_session->waitForText('Add or select media'); + $assert_session->elementsCount('css', '.media-library-item', 4); + $media_items = $page->findAll('css', '.media-library-item__name'); + $media_names = []; + foreach ($media_items as $media_item) { + $media_names[] = $media_item->getText(); + } + sort($media_names); + $this->assertSame(['Eekhoorn', 'Hert', 'Tejón', 'Vos'], $media_names); + + $this->drupalGet('es/node/add/article'); + $assert_session->elementExists('css', '.media-library-open-button[name^="field_media"]')->click(); + $assert_session->waitForText('Add or select media'); + $assert_session->elementsCount('css', '.media-library-item', 4); + $media_items = $page->findAll('css', '.media-library-item__name'); + $media_names = []; + foreach ($media_items as $media_item) { + $media_names[] = $media_item->getText(); + } + sort($media_names); + $this->assertSame(['Ardilla', 'Hert', 'Tejón', 'Zorro'], $media_names); + } + +}