diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index 36557cd..ac092b0 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -14,6 +14,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\StringTranslation\TranslatableString; +use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentLanguage; /** * Implements hook_help(). @@ -53,7 +54,7 @@ function content_translation_help($route_name, RouteMatchInterface $route_match) */ function content_translation_module_implements_alter(&$implementations, $hook) { switch ($hook) { - // Move some of our hook implementations to the end of the list. + // Move our entity_type_alter hook implementation to the end of the list. case 'entity_type_alter': $group = $implementations['content_translation']; unset($implementations['content_translation']); @@ -69,7 +70,6 @@ function content_translation_language_types_info_alter(array &$language_types) { // Make content language negotiation configurable by removing the 'locked' // flag. $language_types[LanguageInterface::TYPE_CONTENT]['locked'] = FALSE; - unset($language_types[LanguageInterface::TYPE_CONTENT]['fixed']); } /** @@ -580,3 +580,25 @@ function content_translation_page_attachments(&$page) { return; } } + +/** + * Implements hook_menu_local_tasks_alter(). + * + * Marks the local tasks urls to be overwritten by LanguageNegotiationContentLanguage. + * + * @param $data + * @param $route_name + */ +function content_translation_menu_local_tasks_alter(&$data, $route_name) { + if (\Drupal::request()->get(LanguageNegotiationContentLanguage::QUERY_PARAMETER)) { + foreach ($data as &$tabs) { + foreach ($tabs as &$tab) { + foreach ($tab as $local_task_route_name => &$local_task_tab) { + /** @var \Drupal\Core\Url $url*/ + $url = $local_task_tab['#link']['url']; + $url->setOption(LanguageNegotiationContentLanguage::OVERWRITE_OPTION, TRUE); + } + } + } + } +} \ No newline at end of file diff --git a/core/modules/content_translation/src/Controller/ContentTranslationController.php b/core/modules/content_translation/src/Controller/ContentTranslationController.php index 9c6879a..e6a1340 100644 --- a/core/modules/content_translation/src/Controller/ContentTranslationController.php +++ b/core/modules/content_translation/src/Controller/ContentTranslationController.php @@ -14,6 +14,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; +use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentLanguage; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -135,6 +136,8 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL ), array( 'language' => $language, + LanguageNegotiationContentLanguage::OVERWRITE_OPTION => FALSE, + 'query' => ['content_language' => $langcode], ) ); $edit_url = new Url( @@ -175,6 +178,11 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL $link = isset($links->links[$langcode]['url']) ? $links->links[$langcode] : array('url' => $entity->urlInfo()); if (!empty($link['url'])) { $link['url']->setOption('language', $language); + + // Turn off content language propagation and set it explicitly. + $link['url']->setOption(LanguageNegotiationContentLanguage::OVERWRITE_OPTION, FALSE); + $link['url']->setOption('query', ['content_language' => $langcode]); + $row_title = $this->l($label, $link['url']); } @@ -198,6 +206,10 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL $links['edit']['url'] = $edit_url; } + // Turn off content language propagation and set it explicitly. + $links['edit']['url']->setOption(LanguageNegotiationContentLanguage::OVERWRITE_OPTION, FALSE); + $links['edit']['url']->setOption('query', ['content_language' => $langcode]); + if (isset($links['edit'])) { $links['edit']['title'] = $this->t('Edit'); } @@ -234,6 +246,10 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL 'url' => $delete_url, ); } + + // Turn off content language propagation and set it explicitly. + $links['delete']['url']->setOption(LanguageNegotiationContentLanguage::OVERWRITE_OPTION, FALSE); + $links['delete']['url']->setOption('query', ['content_language' => $langcode]); } } else { diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php index a5d6d09..7dcc954 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php @@ -14,6 +14,7 @@ use Drupal\Core\Url; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\Component\Utility\SafeMarkup; +use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentLanguage; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; /** @@ -64,6 +65,7 @@ function testTranslationUI() { $this->doTestPublishedStatus(); $this->doTestAuthoringInfo(); $this->doTestTranslationEdit(); + $this->doTestFormLanguageSwitch(); $this->doTestTranslationChanged(); $this->doTestTranslationDeletion(); } @@ -206,16 +208,19 @@ protected function doTestBasicTranslation() { */ protected function doTestTranslationOverview() { $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $this->drupalGet($entity->urlInfo('drupal:content-translation-overview')); + $translate_url = $entity->urlInfo('drupal:content-translation-overview'); + $this->drupalGet($translate_url); + $translate_url->setAbsolute(FALSE); foreach ($this->langcodes as $langcode) { if ($entity->hasTranslation($langcode)) { $language = new Language(array('id' => $langcode)); - $view_path = $entity->url('canonical', array('language' => $language)); - $elements = $this->xpath('//table//a[@href=:href]', array(':href' => $view_path)); + $view_url = $entity->url('canonical', ['language' => $language]); + $elements = $this->xpath('//table//a[@href=:href]', array(':href' => $view_url)); $this->assertEqual((string) $elements[0], $entity->getTranslation($langcode)->label(), format_string('Label correctly shown for %language translation.', array('%language' => $langcode))); - $edit_path = $entity->url('edit-form', array('language' => $language)); - $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', array(':href' => $edit_path)); + $query = [LanguageNegotiationContentLanguage::QUERY_PARAMETER => $langcode, 'destination' => $translate_url->toString()]; + $edit_url = $entity->url('edit-form', ['query' => $query]); + $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', array(':href' => $edit_url)); $this->assertEqual((string) $elements[0], t('Edit'), format_string('Edit link correct for %language translation.', array('%language' => $langcode))); } } @@ -323,6 +328,20 @@ protected function doTestAuthoringInfo() { } /** + * Tests the form language switch functionality. + */ + protected function doTestFormLanguageSwitch() { + $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); + + $message = 'The form language can be switched to @langcode through a query string parameter'; + foreach ($entity->getTranslationLanguages() as $langcode => $language) { + $url = $entity->urlInfo('edit-form', ['query' => ['content_translation_target' => $langcode]]); + $this->drupalGet($url); + $this->assertRaw($entity->getTranslation($langcode)->{$this->fieldName}->value, format_string($message, array('@langcode' => $langcode))); + } + } + + /** * Tests translation deletion. */ protected function doTestTranslationDeletion() { diff --git a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php index b602be0..e35330e 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Url; +use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentLanguage; use Drupal\user\UserInterface; /** @@ -202,8 +203,10 @@ protected function doTestWorkflows(UserInterface $user, $expected_status) { $this->clickLink('Edit', 2); // An editor should be pointed to the entity form in multilingual mode. // We need a new expected edit path with a new language. - $expected_edit_path = $this->entity->url('edit-form', $options); - $this->assertUrl($expected_edit_path, [], 'The translation overview points to the edit form for editors when editing translations.'); + $translate_url = $this->entity->url('drupal:content-translation-overview', ['language' => $languages[$this->langcodes[1]], 'absolute' => FALSE]); + $options = ['query' => [LanguageNegotiationContentLanguage::QUERY_PARAMETER => $langcode, 'destination' => $translate_url]]; + $expected_edit_url = $this->entity->url('edit-form', $options); + $this->assertUrl($expected_edit_url, [], 'The translation overview points to the edit form for editors when editing translations.'); } else { $this->clickLink('Edit'); diff --git a/core/modules/language/config/install/language.types.yml b/core/modules/language/config/install/language.types.yml index 4d48251..c854580 100644 --- a/core/modules/language/config/install/language.types.yml +++ b/core/modules/language/config/install/language.types.yml @@ -4,10 +4,12 @@ all: - language_url configurable: - language_interface + - language_content negotiation: language_content: enabled: - language-interface: 0 + language-content: 0 + language-interface: 1 language_url: enabled: language-url: 0 diff --git a/core/modules/language/language.module b/core/modules/language/language.module index 28609eb..45634c9 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -20,6 +20,7 @@ use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrlFallback; +use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentLanguage; /** * Implements hook_help(). @@ -502,6 +503,6 @@ function language_tour_tips_alter(array &$tour_tips, EntityInterface $entity) { * enabled and we can't be sure of that in the LanguageManager. */ function language_language_types_info_alter(array &$language_types) { - $language_types[LanguageInterface::TYPE_CONTENT]['fixed'] = [LanguageNegotiationUI::METHOD_ID]; + $language_types[LanguageInterface::TYPE_CONTENT]['fixed'] = [LanguageNegotiationContentLanguage::METHOD_ID, LanguageNegotiationUI::METHOD_ID]; $language_types[LanguageInterface::TYPE_URL]['fixed'] = [LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationUrlFallback::METHOD_ID]; } diff --git a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationContentLanguage.php b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationContentLanguage.php new file mode 100644 index 0000000..abb5b72 --- /dev/null +++ b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationContentLanguage.php @@ -0,0 +1,78 @@ +get(static::QUERY_PARAMETER); + + $language_enabled = array_key_exists($langcode, $this->languageManager->getLanguages()); + return $language_enabled ? $langcode : NULL; + } + + /** + * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processOutbound(). + */ + public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) { + if (isset($options[static::OVERWRITE_OPTION]) && $options[static::OVERWRITE_OPTION] && $request && ($langcode = $this->getLangcode($request))) { + if (isset($options['query']) && is_string($options['query'])) { + $query = array(); + parse_str($options['query'], $query); + $options['query'] = $query; + } + else { + $options['query'] = []; + } + if (!isset($options['query'][static::QUERY_PARAMETER])) { + $query_addon = [static::QUERY_PARAMETER => $this->getLangcode($request)]; + $options['query'] += $query_addon; + $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($query_addon); + } + } + + return $path; + } + +}