1<?php 2 3namespace Drupal\Tests\language\Functional; 4 5use Drupal\Component\Render\FormattableMarkup; 6use Drupal\Core\Language\LanguageInterface; 7use Drupal\entity_test\Entity\EntityTest; 8use Drupal\language\Entity\ConfigurableLanguage; 9use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity; 10use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl; 11use Drupal\Tests\BrowserTestBase; 12use Symfony\Cmf\Component\Routing\RouteObjectInterface; 13use Symfony\Component\HttpFoundation\Request; 14use Symfony\Component\Routing\Route; 15 16/** 17 * Tests language negotiation with the language negotiator content entity. 18 * 19 * @group language 20 */ 21class LanguageNegotiationContentEntityTest extends BrowserTestBase { 22 23 /** 24 * Modules to enable. 25 * 26 * @var array 27 */ 28 public static $modules = [ 29 'language', 30 'language_test', 31 'entity_test', 32 'system', 33 ]; 34 35 /** 36 * {@inheritdoc} 37 */ 38 protected $defaultTheme = 'stark'; 39 40 /** 41 * The entity being used for testing. 42 * 43 * @var \Drupal\Core\Entity\ContentEntityInterface 44 */ 45 protected $entity; 46 47 /** 48 * {@inheritdoc} 49 */ 50 protected function setUp() { 51 parent::setUp(); 52 53 ConfigurableLanguage::create(['id' => 'es'])->save(); 54 ConfigurableLanguage::create(['id' => 'fr'])->save(); 55 56 // In order to reflect the changes for a multilingual site in the container 57 // we have to rebuild it. 58 $this->rebuildContainer(); 59 60 $this->createTranslatableEntity(); 61 62 $user = $this->drupalCreateUser(['view test entity']); 63 $this->drupalLogin($user); 64 } 65 66 /** 67 * Tests default with content language remaining same as interface language. 68 */ 69 public function testDefaultConfiguration() { 70 $translation = $this->entity; 71 $this->drupalGet($translation->toUrl()); 72 $last = $this->container->get('state')->get('language_test.language_negotiation_last'); 73 $last_content_language = $last[LanguageInterface::TYPE_CONTENT]; 74 $last_interface_language = $last[LanguageInterface::TYPE_INTERFACE]; 75 $this->assertTrue(($last_interface_language == $last_content_language) && ($last_content_language == $translation->language()->getId()), new FormattableMarkup('Interface language %interface_language and Content language %content_language are the same as the translation language %translation_language of the entity.', ['%interface_language' => $last_interface_language, '%content_language' => $last_content_language, '%translation_language' => $translation->language()->getId()])); 76 77 $translation = $this->entity->getTranslation('es'); 78 $this->drupalGet($translation->toUrl()); 79 $last = $this->container->get('state')->get('language_test.language_negotiation_last'); 80 $last_content_language = $last[LanguageInterface::TYPE_CONTENT]; 81 $last_interface_language = $last[LanguageInterface::TYPE_INTERFACE]; 82 $this->assertTrue(($last_interface_language == $last_content_language) && ($last_content_language == $translation->language()->getId()), new FormattableMarkup('Interface language %interface_language and Content language %content_language are the same as the translation language %translation_language of the entity.', ['%interface_language' => $last_interface_language, '%content_language' => $last_content_language, '%translation_language' => $translation->language()->getId()])); 83 84 $translation = $this->entity->getTranslation('fr'); 85 $this->drupalGet($translation->toUrl()); 86 $last = $this->container->get('state')->get('language_test.language_negotiation_last'); 87 $last_content_language = $last[LanguageInterface::TYPE_CONTENT]; 88 $last_interface_language = $last[LanguageInterface::TYPE_INTERFACE]; 89 $this->assertTrue(($last_interface_language == $last_content_language) && ($last_content_language == $translation->language()->getId()), new FormattableMarkup('Interface language %interface_language and Content language %content_language are the same as the translation language %translation_language of the entity.', ['%interface_language' => $last_interface_language, '%content_language' => $last_content_language, '%translation_language' => $translation->language()->getId()])); 90 } 91 92 /** 93 * Tests enabling the language negotiator language_content_entity. 94 */ 95 public function testEnabledLanguageContentNegotiator() { 96 // Define the method language-url with a higher priority than 97 // language-content-entity. This configuration should match the default one, 98 // where the language-content-entity is turned off. 99 $config = $this->config('language.types'); 100 $config->set('configurable', [LanguageInterface::TYPE_INTERFACE, LanguageInterface::TYPE_CONTENT]); 101 $config->set('negotiation.language_content.enabled', [ 102 LanguageNegotiationUrl::METHOD_ID => 0, 103 LanguageNegotiationContentEntity::METHOD_ID => 1, 104 ]); 105 $config->save(); 106 107 // In order to reflect the changes for a multilingual site in the container 108 // we have to rebuild it. 109 $this->rebuildContainer(); 110 111 // The tests for the default configuration should still pass. 112 $this->testDefaultConfiguration(); 113 114 // Define the method language-content-entity with a higher priority than 115 // language-url. 116 $config->set('negotiation.language_content.enabled', [ 117 LanguageNegotiationContentEntity::METHOD_ID => 0, 118 LanguageNegotiationUrl::METHOD_ID => 1, 119 ]); 120 $config->save(); 121 122 // In order to reflect the changes for a multilingual site in the container 123 // we have to rebuild it. 124 $this->rebuildContainer(); 125 126 // The method language-content-entity should run before language-url and 127 // append query parameter for the content language and prevent language-url 128 // from overwriting the URL. 129 $default_site_langcode = $this->config('system.site')->get('default_langcode'); 130 131 // Now switching to an entity route, so that the URL links are generated 132 // while being on an entity route. 133 $this->setCurrentRequestForRoute('/entity_test/{entity_test}', 'entity.entity_test.canonical'); 134 135 $translation = $this->entity; 136 $this->drupalGet($translation->toUrl()); 137 $last = $this->container->get('state')->get('language_test.language_negotiation_last'); 138 $last_content_language = $last[LanguageInterface::TYPE_CONTENT]; 139 $last_interface_language = $last[LanguageInterface::TYPE_INTERFACE]; 140 $this->assertTrue(($last_interface_language == $default_site_langcode) && ($last_interface_language == $last_content_language) && ($last_content_language == $translation->language()->getId()), 'Interface language and Content language are the same as the default translation language of the entity.'); 141 $this->assertTrue($last_interface_language == $default_site_langcode, 'Interface language did not change from the default site language.'); 142 $this->assertTrue($last_content_language == $translation->language()->getId(), 'Content language matches the current entity translation language.'); 143 144 $translation = $this->entity->getTranslation('es'); 145 $this->drupalGet($translation->toUrl()); 146 $last = $this->container->get('state')->get('language_test.language_negotiation_last'); 147 $last_content_language = $last[LanguageInterface::TYPE_CONTENT]; 148 $last_interface_language = $last[LanguageInterface::TYPE_INTERFACE]; 149 $this->assertTrue($last_interface_language == $default_site_langcode, 'Interface language did not change from the default site language.'); 150 $this->assertTrue($last_content_language == $translation->language()->getId(), 'Content language matches the current entity translation language.'); 151 152 $translation = $this->entity->getTranslation('fr'); 153 $this->drupalGet($translation->toUrl()); 154 $last = $this->container->get('state')->get('language_test.language_negotiation_last'); 155 $last_content_language = $last[LanguageInterface::TYPE_CONTENT]; 156 $last_interface_language = $last[LanguageInterface::TYPE_INTERFACE]; 157 $this->assertTrue($last_interface_language == $default_site_langcode, 'Interface language did not change from the default site language.'); 158 $this->assertTrue($last_content_language == $translation->language()->getId(), 'Content language matches the current entity translation language.'); 159 } 160 161 /** 162 * Creates a translated entity. 163 */ 164 protected function createTranslatableEntity() { 165 $this->entity = EntityTest::create(); 166 $this->entity->addTranslation('es', ['name' => 'name spanish']); 167 $this->entity->addTranslation('fr', ['name' => 'name french']); 168 $this->entity->save(); 169 } 170 171 /** 172 * Sets the current request to a specific path with the corresponding route. 173 * 174 * @param string $path 175 * The path for which the current request should be created. 176 * @param string $route_name 177 * The route name for which the route object for the request should be 178 * created. 179 */ 180 protected function setCurrentRequestForRoute($path, $route_name) { 181 $request = Request::create($path); 182 $request->attributes->set(RouteObjectInterface::ROUTE_NAME, $route_name); 183 $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route($path)); 184 $this->container->get('request_stack')->push($request); 185 } 186 187} 188