diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php index b85737f..4c9c79c 100644 --- a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php +++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php @@ -32,7 +32,7 @@ public function __construct(AliasManagerInterface $alias_manager) { * {@inheritdoc} */ public function processInbound($path, Request $request) { - $path = $this->aliasManager->getPathByAlias($path); + $path = $this->aliasManager->getPathByAlias($path, $request->getLocale()); return $path; } diff --git a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php index 7436a3f..35c5dc7 100644 --- a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php +++ b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php @@ -110,6 +110,7 @@ public function processInbound($path, Request $request) { if (isset($config['prefixes'][$language->getId()]) && $config['prefixes'][$language->getId()] == $prefix) { // Rebuild $path with the language removed. $path = '/' . implode('/', $parts); + $request->setLocale($prefix); break; } } diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php index b0928b0..47fffd4 100644 --- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php +++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php @@ -173,10 +173,14 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $element = []; $entity = $items->getEntity(); $settings = $this->getSettings(); + $language = \Drupal::languageManager()->getLanguage($langcode); foreach ($items as $delta => $item) { // By default use the full URL as the link text. $url = $this->buildUrl($item); + if (!$item->getFieldDefinition()->get('translatable')) { + $url->setOption('language', $language); + } $link_title = $url->toString(); // If the title field value is available, use it for the link text. diff --git a/core/tests/Drupal/FunctionalTests/Core/Path/AliasManagerTest.php b/core/tests/Drupal/FunctionalTests/Core/Path/AliasManagerTest.php new file mode 100644 index 0000000..ee2ac77 --- /dev/null +++ b/core/tests/Drupal/FunctionalTests/Core/Path/AliasManagerTest.php @@ -0,0 +1,115 @@ +loginAdmin(); + $this->createContentType(['type' => 'page']); + ConfigurableLanguage::createFromLangcode('ro')->save(); + + // Confirm that the additional language was created. + $this->assertEquals(2, count(\Drupal::languageManager()->getLanguages()), 'There are two languages.'); + + $node = $this->createAliasedNode('/test-page', 'en'); + + // Confirm that alias was created and saved. + $path = $this->container->get('path.alias_storage') + ->load(['alias' => '/test-page']); + $this->assertTrue($path, 'Alias was created.'); + + // Confirm that the node default route exists. + $request = Request::create('/node/' . $node->id()); + $routes = $this->container->get('router.route_provider') + ->getRouteCollectionForRequest($request); + $this->assertEquals(1, $routes->count()); + + // Confirm that the route for the aliased path is found in default language. + $routes = $this->container->get('router.route_provider') + ->getRouteCollectionForRequest(Request::create('/test-page')); + $this->assertEquals(1, $routes->count()); + + // Confirm that the page can be reached through alias. + $this->drupalGet('/test-page'); + $this->assertSession()->statusCodeEquals(200); + + // Begin proving the issue. + // Ensure that the current request is on the language on which the test page + // is not translated. + $this->resetAll(); + $this->createAliasedNode('/ro-page', 'ro'); + \Drupal::requestStack()->push(Request::create('/ro/ro-page')); + \Drupal::languageManager()->reset(); + $this->assertEquals('ro', \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId()); + + // Prove that the route won't be found in the current language. This happens + // because the alias manager won't find the alias in the current language + // context. In this step the route provider will cache that there are no + // routes for this request. With link rendering this happens right after the + // processInbound call in the PathValidator::getPathAttributes. + $routes = $this->container->get('router.route_provider') + ->getRouteCollectionForRequest(Request::create('/test-page')); + $this->assertEquals(1, $routes->count(), 'Route for the alias in ro language was not found.'); + + // Remove the manually added request. + \Drupal::requestStack()->pop(); + \Drupal::languageManager()->reset(); + + // Prove that the aliased page is not found. + $this->drupalGet('/test-page'); + $this->assertSession()->statusCodeEquals(200); + } + + /** + * Creates and aliased node. + * + * @param string $alias + * The path alias. + * @param string $langcode + * The language code of the node. + * + * @return \Drupal\node\NodeInterface + * Created node. + */ + protected function createAliasedNode($alias, $langcode) { + return $this->drupalCreateNode([ + 'type' => 'page', + 'title' => 'Test page', + 'path' => [ + 'alias' => $alias + ], + 'langcode' => $langcode, + ]); + } + + /** + * Creates an admin user and logs it in. + */ + protected function loginAdmin() { + $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'access content')); + $this->drupalLogin($admin_user); + } + +} diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php index 0473d79..449f9a0 100644 --- a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php +++ b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php @@ -42,8 +42,8 @@ public function testProcessInbound() { $this->aliasManager->expects($this->exactly(2)) ->method('getPathByAlias') ->will($this->returnValueMap([ - ['urlalias', NULL, 'internal-url'], - ['url', NULL, 'url'], + ['urlalias', 'en', 'internal-url'], + ['url', 'en', 'url'], ])); $request = Request::create('/urlalias'); diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php index 57dfbfa..f973e37 100644 --- a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php +++ b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php @@ -98,12 +98,17 @@ public function testProcessInbound() { ->getMock(); $system_path_map = [ - // Set up one proper alias that can be resolved to a system path. - ['/foo', NULL, '/user/1'], + // Set up one proper alias for each language that can be resolved to a + // system path. + ['/foo', 'en', '/user/1'], + ['/foo', 'fr', '/user/1'], // Passing in anything else should return the same string. - ['/fr/foo', NULL, '/fr/foo'], - ['/fr', NULL, '/fr'], - ['/user/login', NULL, '/user/login'], + ['/fr/foo', 'en', '/fr/foo'], + ['/fr/foo', 'fr', '/fr/foo'], + ['/fr', 'en', '/fr'], + ['/fr', 'fr', '/fr'], + ['/user/login', 'en', '/user/login'], + ['/user/login', 'fr', '/user/login'], ]; $alias_manager->expects($this->any())