View source
<?php
namespace Drupal\language\Tests;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSession;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin;
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\language\LanguageNegotiatorInterface;
use Drupal\block\Entity\Block;
class LanguageUILanguageNegotiationTest extends WebTestBase {
public static $modules = array(
'locale',
'language_test',
'block',
'user',
'content_translation',
);
protected function setUp() {
parent::setUp();
$admin_user = $this
->drupalCreateUser(array(
'administer languages',
'translate interface',
'access administration pages',
'administer blocks',
));
$this
->drupalLogin($admin_user);
}
function testUILanguageNegotiation() {
$langcode_unknown = 'blah-blah';
$langcode_browser_fallback = 'vi';
$langcode = 'zh-hans';
$http_header_browser_fallback = array(
"Accept-Language: {$langcode_browser_fallback};q=1",
);
$http_header_blah = array(
"Accept-Language: blah;q=1",
);
$default_language = \Drupal::languageManager()
->getDefaultLanguage();
ConfigurableLanguage::createFromLangcode($langcode_browser_fallback)
->save();
$this
->config('system.site')
->set('default_langcode', $langcode_browser_fallback)
->save();
ConfigurableLanguage::createFromLangcode($langcode)
->save();
$default_string = 'Hide descriptions';
$this
->drupalGet('admin/config');
$this
->config('system.site')
->set('default_langcode', $default_language
->getId())
->save();
$this
->config('language.negotiation')
->set('url.prefixes.en', '')
->save();
$this
->rebuildContainer();
$language_browser_fallback_string = "In {$langcode_browser_fallback} In {$langcode_browser_fallback} In {$langcode_browser_fallback}";
$language_string = "In {$langcode} In {$langcode} In {$langcode}";
$search = array(
'string' => $default_string,
'langcode' => $langcode_browser_fallback,
);
$this
->drupalPostForm('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this
->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $language_browser_fallback_string,
);
$this
->drupalPostForm('admin/config/regional/translate', $edit, t('Save translations'));
$search = array(
'string' => $default_string,
'langcode' => $langcode,
);
$this
->drupalPostForm('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this
->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $language_string,
);
$this
->drupalPostForm('admin/config/regional/translate', $edit, t('Save translations'));
$edit = array(
'selected_langcode' => $langcode,
);
$this
->drupalPostForm('admin/config/regional/language/detection/selected', $edit, t('Save configuration'));
$test = array(
'language_negotiation' => array(
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $language_string,
'expected_method_id' => LanguageNegotiationSelected::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SELECTED: UI language is switched based on selected language.',
);
$this
->runTest($test);
$this
->config('language.negotiation')
->set('selected_langcode', NULL)
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SELECTED > DEFAULT: UI language is switched based on selected language.',
);
$this
->runTest($test);
$this
->config('language.negotiation')
->set('selected_langcode', $langcode_unknown)
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SELECTED > DEFAULT: UI language is switched based on selected language.',
);
$this
->runTest($test);
$tests = array(
array(
'language_negotiation' => array(
LanguageNegotiationUrl::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > DEFAULT: no language prefix, UI language is default and the browser language preference setting is not used.',
),
array(
'language_negotiation' => array(
LanguageNegotiationUrl::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => "{$langcode}/admin/config",
'expect' => $language_string,
'expected_method_id' => LanguageNegotiationUrl::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
),
array(
'language_negotiation' => array(
LanguageNegotiationUrl::METHOD_ID,
LanguageNegotiationBrowser::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $language_browser_fallback_string,
'expected_method_id' => LanguageNegotiationBrowser::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > BROWSER: no language prefix, UI language is determined by browser language preference',
),
array(
'language_negotiation' => array(
LanguageNegotiationUrl::METHOD_ID,
LanguageNegotiationBrowser::METHOD_ID,
),
'path' => "{$langcode}/admin/config",
'expect' => $language_string,
'expected_method_id' => LanguageNegotiationUrl::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > BROWSER: with language prefix, UI language is based on path prefix',
),
array(
'language_negotiation' => array(
LanguageNegotiationUrl::METHOD_ID,
LanguageNegotiationBrowser::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_blah,
'message' => 'URL (PATH) > BROWSER > DEFAULT: no language prefix and browser language preference set to unknown language should use default language',
),
);
foreach ($tests as $test) {
$this
->runTest($test);
}
$definitions = \Drupal::languageManager()
->getNegotiator()
->getNegotiationMethods();
$language_interface_method_definitions = array_filter($definitions, function ($method_definition) {
return !isset($method_definition['types']) || isset($method_definition['types']) && in_array(LanguageInterface::TYPE_INTERFACE, $method_definition['types']);
});
$this
->config('language.types')
->set('negotiation.' . LanguageInterface::TYPE_INTERFACE . '.enabled', array_flip(array_keys($language_interface_method_definitions)))
->save();
$this
->drupalGet("{$langcode_unknown}/admin/config", array(), $http_header_browser_fallback);
$this
->assertResponse(404, "Unknown language path prefix should return 404");
$account = $this->loggedInUser;
$account->preferred_langcode = NULL;
$account
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationUser::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER > DEFAULT: no preferred user language setting, the UI language is default',
);
$this
->runTest($test);
$account = $this->loggedInUser;
$account->preferred_langcode = $langcode_unknown;
$account
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationUser::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER > DEFAULT: invalid preferred user language setting, the UI language is default',
);
$this
->runTest($test);
$account->preferred_langcode = $langcode;
$account
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationUser::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $language_string,
'expected_method_id' => LanguageNegotiationUser::METHOD_ID,
'http_header' => array(),
'message' => 'USER > DEFAULT: defined preferred user language setting, the UI language is based on user setting',
);
$this
->runTest($test);
$account->preferred_admin_langcode = NULL;
$account
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationUserAdmin::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER ADMIN > DEFAULT: no preferred user admin language setting, the UI language is default',
);
$this
->runTest($test);
$account->preferred_admin_langcode = $langcode_unknown;
$account
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationUserAdmin::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER ADMIN > DEFAULT: invalid preferred user admin language setting, the UI language is default',
);
$this
->runTest($test);
$account->preferred_admin_langcode = $langcode;
$account
->save();
$test = array(
'language_negotiation' => array(
LanguageNegotiationUserAdmin::METHOD_ID,
LanguageNegotiationSelected::METHOD_ID,
),
'path' => 'admin/config',
'expect' => $language_string,
'expected_method_id' => LanguageNegotiationUserAdmin::METHOD_ID,
'http_header' => array(),
'message' => 'USER ADMIN > DEFAULT: defined preferred user admin language setting, the UI language is based on user setting',
);
$this
->runTest($test);
$language_negotiation_session_param = $this
->randomMachineName();
$edit = array(
'language_negotiation_session_param' => $language_negotiation_session_param,
);
$this
->drupalPostForm('admin/config/regional/language/detection/session', $edit, t('Save configuration'));
$tests = array(
array(
'language_negotiation' => array(
LanguageNegotiationSession::METHOD_ID,
),
'path' => "admin/config",
'expect' => $default_string,
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SESSION > DEFAULT: no language given, the UI language is default',
),
array(
'language_negotiation' => array(
LanguageNegotiationSession::METHOD_ID,
),
'path' => 'admin/config',
'path_options' => [
'query' => [
$language_negotiation_session_param => $langcode,
],
],
'expect' => $language_string,
'expected_method_id' => LanguageNegotiationSession::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SESSION > DEFAULT: language given, UI language is determined by session language preference',
),
);
foreach ($tests as $test) {
$this
->runTest($test);
}
}
protected function runTest($test) {
$test += array(
'path_options' => [],
);
if (!empty($test['language_negotiation'])) {
$method_weights = array_flip($test['language_negotiation']);
$this->container
->get('language_negotiator')
->saveConfiguration(LanguageInterface::TYPE_INTERFACE, $method_weights);
}
if (!empty($test['language_negotiation_url_part'])) {
$this
->config('language.negotiation')
->set('url.source', $test['language_negotiation_url_part'])
->save();
}
if (!empty($test['language_test_domain'])) {
\Drupal::state()
->set('language_test.domain', $test['language_test_domain']);
}
$this->container
->get('language_manager')
->reset();
$this
->drupalGet($test['path'], $test['path_options'], $test['http_header']);
$this
->assertText($test['expect'], $test['message']);
$this
->assertText(t('Language negotiation method: @name', array(
'@name' => $test['expected_method_id'],
)));
}
function testUrlLanguageFallback() {
$langcode_browser_fallback = 'it';
ConfigurableLanguage::createFromLangcode($langcode_browser_fallback)
->save();
$languages = $this->container
->get('language_manager')
->getLanguages();
$edit = array(
'prefix[en]' => 'en',
);
$this
->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
$edit = array(
'language_interface[enabled][language-browser]' => TRUE,
'language_interface[enabled][language-url]' => TRUE,
'language_interface[weight][language-browser]' => -8,
'language_interface[weight][language-url]' => -10,
);
$this
->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
$this
->drupalGet('admin/config/regional/language/detection');
$this
->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, array(
'id' => 'test_language_block',
));
$this
->drupalLogout();
$this
->drupalPlaceBlock('system_branding_block', [
'region' => 'header',
]);
$http_header = array(
"Accept-Language: {$langcode_browser_fallback};q=1",
);
$language = new Language(array(
'id' => '',
));
$this
->drupalGet('', array(
'language' => $language,
), $http_header);
$args = array(
':id' => 'block-test-language-block',
':url' => \Drupal::url('<front>') . $langcode_browser_fallback,
);
$fields = $this
->xpath('//div[@id=:id]//a[@class="language-link is-active" and starts-with(@href, :url)]', $args);
$this
->assertTrue($fields[0] == $languages[$langcode_browser_fallback]
->getName(), 'The browser language is the URL active language');
$fields = $this
->xpath('//div[@class="site-name"]/a[@rel="home" and @href=:url]', $args);
$this
->assertTrue($fields[0] == 'Drupal', 'URLs are rewritten using the browser language.');
}
function testLanguageDomain() {
global $base_url;
$base_url_host = parse_url($base_url, PHP_URL_HOST);
ConfigurableLanguage::createFromLangcode('it')
->save();
$languages = $this->container
->get('language_manager')
->getLanguages();
$edit = array(
'language_interface[enabled][language-url]' => TRUE,
'language_interface[weight][language-url]' => -10,
);
$this
->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
$edit = array(
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
'domain[en]' => '',
);
$this
->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
$this
->assertText('The domain may not be left blank for English', 'The form does not allow blank domains.');
$this
->rebuildContainer();
$edit = array(
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
'domain[en]' => $base_url_host,
'domain[it]' => 'it.example.com',
);
$this
->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
$this
->assertText('The configuration options have been saved', 'Domain configuration is saved.');
$this
->rebuildContainer();
$edit = [
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
'domain[en]' => $base_url_host,
'domain[it]' => 'it.example.com/',
];
$this
->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
$this
->assertRaw(t('The domain for %language may only contain the domain name, not a trailing slash, protocol and/or port.', [
'%language' => 'Italian',
]));
$link = 'it.example.com' . rtrim(base_path(), '/') . '/admin';
$italian_url = Url::fromRoute('system.admin', [], [
'language' => $languages['it'],
])
->toString();
$url_scheme = \Drupal::request()
->isSecure() ? 'https://' : 'http://';
$correct_link = $url_scheme . $link;
$this
->assertEqual($italian_url, $correct_link, format_string('The right URL (@url) in accordance with the chosen language', array(
'@url' => $italian_url,
)));
$italian_url = Url::fromRoute('system.admin', [], [
'https' => TRUE,
'language' => $languages['it'],
])
->toString();
$correct_link = 'https://' . $link;
$this
->assertTrue($italian_url == $correct_link, format_string('The right HTTPS URL (via options) (@url) in accordance with the chosen language', array(
'@url' => $italian_url,
)));
$request = Request::create('', 'GET', array(), array(), array(), array(
'HTTPS' => 'on',
));
$this->container
->get('request_stack')
->push($request);
$italian_url = Url::fromRoute('system.admin', [], [
'language' => $languages['it'],
])
->toString();
$correct_link = 'https://' . $link;
$this
->assertTrue($italian_url == $correct_link, format_string('The right URL (via current URL scheme) (@url) in accordance with the chosen language', array(
'@url' => $italian_url,
)));
}
public function testContentCustomization() {
$edit = array(
'language_content[configurable]' => TRUE,
'language_content[enabled][language-url]' => FALSE,
'language_content[enabled][language-session]' => TRUE,
);
$this
->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
$config = $this
->config('language.types');
$this
->assertTrue(in_array('language_interface', $config
->get('configurable')), 'Interface language is configurable.');
$this
->assertTrue(in_array('language_content', $config
->get('configurable')), 'Content language is configurable.');
$this
->assertFalse(array_key_exists('language-url', $config
->get('negotiation.language_content.enabled')), 'URL negotiation is not enabled for content.');
$this
->assertTrue(array_key_exists('language-session', $config
->get('negotiation.language_content.enabled')), 'Session negotiation is enabled for content.');
}
public function testDisableLanguageSwitcher() {
$block_id = 'test_language_block';
$this
->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_CONTENT, array(
'id' => $block_id,
));
$block = Block::load($block_id);
$this
->assertTrue($block, 'Language switcher block was created.');
$edit = array(
'language_content[configurable]' => FALSE,
);
$this
->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
$this
->assertResponse(200);
$block = Block::load($block_id);
$this
->assertFalse($block, 'Language switcher block was removed.');
}
}