Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Test administration path based conversion of entities.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class AdminPathEntityConverterLanguageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'language_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$permissions = [
|
||||
'access administration pages',
|
||||
'administer site configuration',
|
||||
];
|
||||
$this->drupalLogin($this->drupalCreateUser($permissions));
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the translated and untranslated config entities are loaded properly.
|
||||
*/
|
||||
public function testConfigUsingCurrentLanguage(): void {
|
||||
\Drupal::languageManager()
|
||||
->getLanguageConfigOverride('es', 'language.entity.es')
|
||||
->set('label', 'Español')
|
||||
->save();
|
||||
|
||||
$this->drupalGet('es/admin/language_test/entity_using_current_language/es');
|
||||
$this->assertSession()->pageTextNotContains('Loaded Spanish.');
|
||||
$this->assertSession()->pageTextContains('Loaded Español.');
|
||||
|
||||
$this->drupalGet('es/admin/language_test/entity_using_original_language/es');
|
||||
$this->assertSession()->pageTextContains('Loaded Spanish.');
|
||||
$this->assertSession()->pageTextNotContains('Loaded Español.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\WaitTerminateTestTrait;
|
||||
|
||||
// cspell:ignore funciona
|
||||
|
||||
/**
|
||||
* Tests Language Negotiation.
|
||||
*
|
||||
* Uses different negotiators for content and interface.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class ConfigurableLanguageManagerTest extends BrowserTestBase {
|
||||
|
||||
use WaitTerminateTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'content_translation',
|
||||
'node',
|
||||
'locale',
|
||||
'block',
|
||||
'system',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// The \Drupal\locale\LocaleTranslation service clears caches after the
|
||||
// response is flushed to the client. We use WaitTerminateTestTrait to wait
|
||||
// for Drupal to perform its termination work before continuing.
|
||||
$this->setWaitForTerminate();
|
||||
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->createUser([], '', TRUE);
|
||||
$this->drupalLogin($user);
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
|
||||
// Create a page node type and make it translatable.
|
||||
NodeType::create([
|
||||
'type' => 'page',
|
||||
'name' => 'Page',
|
||||
])->save();
|
||||
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'page');
|
||||
$config->setDefaultLangcode('en')
|
||||
->setLanguageAlterable(TRUE)
|
||||
->save();
|
||||
|
||||
// Create a Node with title 'English' and translate it to Spanish.
|
||||
$node = Node::create([
|
||||
'type' => 'page',
|
||||
'title' => 'English',
|
||||
]);
|
||||
$node->save();
|
||||
$node->addTranslation('es', ['title' => 'Español']);
|
||||
$node->save();
|
||||
|
||||
// Enable both language_interface and language_content language negotiation.
|
||||
\Drupal::getContainer()->get('language_negotiator')->updateConfiguration([
|
||||
'language_interface',
|
||||
'language_content',
|
||||
]);
|
||||
|
||||
// Set the preferred language of the user for admin pages to English.
|
||||
$user->set('preferred_admin_langcode', 'en')->save();
|
||||
|
||||
// Place a Block with a translatable string on the page.
|
||||
$this->placeBlock('system_powered_by_block', ['region' => 'content']);
|
||||
|
||||
// Load the Spanish Node page once, to register the translatable string.
|
||||
$this->drupalGet('/es/node/1');
|
||||
|
||||
// Translate the Powered by string.
|
||||
/** @var \Drupal\locale\StringStorageInterface $string_storage */
|
||||
$string_storage = \Drupal::getContainer()->get('locale.storage');
|
||||
$source = $string_storage->findString(['source' => 'Powered by <a href=":poweredby">Drupal</a>']);
|
||||
$string_storage->createTranslation([
|
||||
'lid' => $source->lid,
|
||||
'language' => 'es',
|
||||
'translation' => 'Funciona con ...',
|
||||
])->save();
|
||||
// Invalidate caches so that the new translation will be used.
|
||||
Cache::invalidateTags(['rendered', 'locale']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation with URL and Preferred Admin Language negotiators.
|
||||
*
|
||||
* The interface language uses the preferred language for admin pages of the
|
||||
* user and after that the URL. The Content uses just the URL.
|
||||
*/
|
||||
public function testUrlContentTranslationWithPreferredAdminLanguage(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
// Set the interface language to use the preferred administration language
|
||||
// and then the URL.
|
||||
/** @var \Drupal\language\LanguageNegotiatorInterface $language_negotiator */
|
||||
$language_negotiator = \Drupal::getContainer()->get('language_negotiator');
|
||||
$language_negotiator->saveConfiguration('language_interface', [
|
||||
'language-user-admin' => 1,
|
||||
'language-url' => 2,
|
||||
'language-selected' => 3,
|
||||
]);
|
||||
// Set Content Language Negotiator to use just the URL.
|
||||
$language_negotiator->saveConfiguration('language_content', [
|
||||
'language-url' => 4,
|
||||
'language-selected' => 5,
|
||||
]);
|
||||
|
||||
// See if the full view of the node in english is present and the
|
||||
// string in the Powered By Block is in English.
|
||||
$this->drupalGet('/node/1');
|
||||
$assert_session->pageTextContains('English');
|
||||
$assert_session->pageTextContains('Powered by');
|
||||
|
||||
// Load the spanish node page again and see if both the node and the string
|
||||
// are translated.
|
||||
$this->drupalGet('/es/node/1');
|
||||
$assert_session->pageTextContains('Español');
|
||||
$assert_session->pageTextContains('Funciona con');
|
||||
$assert_session->pageTextNotContains('Powered by');
|
||||
|
||||
// Check if the Powered by string is shown in English on an
|
||||
// administration page, and the node content is shown in Spanish.
|
||||
$this->drupalGet('/es/node/1/edit');
|
||||
$assert_session->pageTextContains('Español');
|
||||
$assert_session->pageTextContains('Powered by');
|
||||
$assert_session->pageTextNotContains('Funciona con');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation with URL and Session Language Negotiators.
|
||||
*/
|
||||
public function testUrlContentTranslationWithSessionLanguage(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
/** @var \Drupal\language\LanguageNegotiatorInterface $language_negotiator */
|
||||
$language_negotiator = \Drupal::getContainer()->get('language_negotiator');
|
||||
// Set Interface Language Negotiator to Session.
|
||||
$language_negotiator->saveConfiguration('language_interface', [
|
||||
'language-session' => 1,
|
||||
'language-url' => 2,
|
||||
'language-selected' => 3,
|
||||
]);
|
||||
|
||||
// Set Content Language Negotiator to URL.
|
||||
$language_negotiator->saveConfiguration('language_content', [
|
||||
'language-url' => 4,
|
||||
'language-selected' => 5,
|
||||
]);
|
||||
|
||||
// See if the full view of the node in english is present and the
|
||||
// string in the Powered By Block is in English.
|
||||
$this->drupalGet('/node/1');
|
||||
$assert_session->pageTextContains('English');
|
||||
$assert_session->pageTextContains('Powered by');
|
||||
|
||||
// The language session variable has not been set yet, so
|
||||
// The string should be in Spanish.
|
||||
$this->drupalGet('/es/node/1');
|
||||
$assert_session->pageTextContains('Español');
|
||||
$assert_session->pageTextNotContains('Powered by');
|
||||
$assert_session->pageTextContains('Funciona con');
|
||||
|
||||
// Set the session language to Spanish but load the English node page.
|
||||
$this->drupalGet('/node/1', ['query' => ['language' => 'es']]);
|
||||
$assert_session->pageTextContains('English');
|
||||
$assert_session->pageTextNotContains('Español');
|
||||
$assert_session->pageTextContains('Funciona con');
|
||||
$assert_session->pageTextNotContains('Powered by');
|
||||
|
||||
// Set the session language to English but load the node page in Spanish.
|
||||
$this->drupalGet('/es/node/1', ['query' => ['language' => 'en']]);
|
||||
$assert_session->pageTextNotContains('English');
|
||||
$assert_session->pageTextContains('Español');
|
||||
$assert_session->pageTextNotContains('Funciona con');
|
||||
$assert_session->pageTextContains('Powered by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation of the user profile edit form.
|
||||
*
|
||||
* The user profile edit form is a special case when used with the preferred
|
||||
* admin language negotiator because of the recursive way that the negotiator
|
||||
* is called.
|
||||
*/
|
||||
public function testUserProfileTranslationWithPreferredAdminLanguage(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
// Set the interface language to use the preferred administration language.
|
||||
/** @var \Drupal\language\LanguageNegotiatorInterface $language_negotiator */
|
||||
$language_negotiator = \Drupal::getContainer()->get('language_negotiator');
|
||||
$language_negotiator->saveConfiguration('language_interface', [
|
||||
'language-user-admin' => 1,
|
||||
'language-selected' => 2,
|
||||
]);
|
||||
|
||||
// Create a field on the user entity.
|
||||
$field_name = $this->randomMachineName();
|
||||
$label = $this->randomMachineName();
|
||||
$field_label_en = "English $label";
|
||||
$field_label_es = "Español $label";
|
||||
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'user',
|
||||
'type' => 'string',
|
||||
]);
|
||||
$field_storage->save();
|
||||
|
||||
$instance = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'user',
|
||||
'label' => $field_label_en,
|
||||
]);
|
||||
$instance->save();
|
||||
|
||||
// Add a Spanish translation.
|
||||
\Drupal::languageManager()
|
||||
->getLanguageConfigOverride('es', "field.field.user.user.$field_name")
|
||||
->set('label', $field_label_es)
|
||||
->save();
|
||||
|
||||
// Add the new field to the edit form.
|
||||
EntityFormDisplay::create([
|
||||
'targetEntityType' => 'user',
|
||||
'bundle' => 'user',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
])
|
||||
->setComponent($field_name, [
|
||||
'type' => 'string_textfield',
|
||||
])
|
||||
->save();
|
||||
|
||||
$user_id = \Drupal::currentUser()->id();
|
||||
$this->drupalGet("/user/$user_id/edit");
|
||||
// Admin language choice is "No preference" so we should get the default.
|
||||
$assert_session->pageTextContains($field_label_en);
|
||||
$assert_session->pageTextNotContains($field_label_es);
|
||||
|
||||
// Set admin language to Spanish.
|
||||
$this->submitForm(['edit-preferred-admin-langcode' => 'es'], 'edit-submit');
|
||||
$assert_session->pageTextContains($field_label_es);
|
||||
$assert_session->pageTextNotContains($field_label_en);
|
||||
|
||||
// Set admin language to English.
|
||||
$this->submitForm(['edit-preferred-admin-langcode' => 'en'], 'edit-submit');
|
||||
$assert_session->pageTextContains($field_label_en);
|
||||
$assert_session->pageTextNotContains($field_label_es);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests entity type without language support.
|
||||
*
|
||||
* This is to ensure that an entity type without language support can not
|
||||
* enable the language select from the content language settings page.
|
||||
*
|
||||
* @covers \Drupal\language\Form\ContentLanguageSettingsForm
|
||||
* @group language
|
||||
*/
|
||||
class EntityTypeWithoutLanguageFormTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'language_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create and log in administrative user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests configuration options with an entity without language definition.
|
||||
*/
|
||||
public function testEmptyLangcode(): void {
|
||||
// Assert that we can not enable language select from
|
||||
// content language settings page.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$this->assertSession()->fieldNotExists('entity_types[no_language_entity_test]');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
|
||||
|
||||
/**
|
||||
* Generic module test for language.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class GenericTest extends GenericModuleTestBase {}
|
||||
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that the language settings on block config appears correctly.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageBlockSettingsVisibilityTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests languages displayed in the language switcher.
|
||||
*/
|
||||
public function testUnnecessaryLanguageSettingsVisibility(): void {
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
'administer blocks',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm(['predefined_langcode' => 'hu'], 'Add language');
|
||||
$this->drupalGet('admin/structure/block/add/system_menu_block:admin/stark');
|
||||
$this->assertSession()->fieldNotExists("edit-visibility-language-langcodes-und");
|
||||
$this->assertSession()->fieldNotExists("edit-visibility-language-langcodes-zxx");
|
||||
$this->assertSession()->fieldExists("edit-visibility-language-langcodes-en");
|
||||
$this->assertSession()->fieldExists("edit-visibility-language-langcodes-hu");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\system\Functional\Menu\AssertBreadcrumbTrait;
|
||||
|
||||
/**
|
||||
* Tests breadcrumbs functionality.
|
||||
*
|
||||
* @group Menu
|
||||
*/
|
||||
class LanguageBreadcrumbTest extends BrowserTestBase {
|
||||
|
||||
use AssertBreadcrumbTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'block', 'filter'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_block');
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
ConfigurableLanguage::createFromLangcode('gsw-berne')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests breadcrumbs with URL prefixes.
|
||||
*/
|
||||
public function testBreadCrumbs(): void {
|
||||
// /user/login is the default frontpage which only works for an anonymous
|
||||
// user. Access the frontpage in different languages, ensure that no
|
||||
// breadcrumb is displayed.
|
||||
$this->assertBreadcrumb('user/login', []);
|
||||
$this->assertBreadcrumb('de/user/login', []);
|
||||
$this->assertBreadcrumb('gsw-berne/user/login', []);
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['access administration pages', 'administer blocks']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Use administration routes to assert that breadcrumb is displayed
|
||||
// correctly on pages other than the frontpage.
|
||||
$this->assertBreadcrumb('admin', [
|
||||
'' => 'Home',
|
||||
]);
|
||||
$this->assertBreadcrumb('de/admin', [
|
||||
'de' => 'Home',
|
||||
]);
|
||||
|
||||
$this->assertBreadcrumb('admin/structure', [
|
||||
'' => 'Home',
|
||||
'admin' => 'Administration',
|
||||
]);
|
||||
$this->assertBreadcrumb('de/admin/structure', [
|
||||
'de' => 'Home',
|
||||
'de/admin' => 'Administration',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests browser language detection with different accept-language headers.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageBrowserDetectionAcceptLanguageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'locale',
|
||||
'content_translation',
|
||||
'system_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// User to manage languages.
|
||||
$admin = $this->drupalCreateUser([], NULL, TRUE);
|
||||
$this->drupalLogin($admin);
|
||||
|
||||
// Create FR.
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
// Set language detection to URL and browser detection.
|
||||
$this->drupalGet('/admin/config/regional/language/detection');
|
||||
$this->submitForm([
|
||||
'language_interface[enabled][language-url]' => TRUE,
|
||||
'language_interface[enabled][language-browser]' => TRUE,
|
||||
'language_interface[enabled][language-selected]' => TRUE,
|
||||
], 'Save settings');
|
||||
|
||||
// Set prefixes to en and fr.
|
||||
$this->drupalGet('/admin/config/regional/language/detection/url');
|
||||
$this->submitForm([
|
||||
'prefix[en]' => 'en',
|
||||
'prefix[fr]' => 'fr',
|
||||
], 'Save configuration');
|
||||
// Add language codes to browser detection.
|
||||
$this->drupalGet('/admin/config/regional/language/detection/browser');
|
||||
$this->submitForm([
|
||||
'new_mapping[browser_langcode]' => 'fr',
|
||||
'new_mapping[drupal_langcode]' => 'fr',
|
||||
], 'Save configuration');
|
||||
$this->drupalGet('/admin/config/regional/language/detection/browser');
|
||||
$this->submitForm([
|
||||
'new_mapping[browser_langcode]' => 'en',
|
||||
'new_mapping[drupal_langcode]' => 'en',
|
||||
], 'Save configuration');
|
||||
$this->drupalGet('/admin/config/regional/language/detection/selected');
|
||||
$this->submitForm(['edit-selected-langcode' => 'en'], 'Save configuration');
|
||||
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with browsers with and without Accept-Language header.
|
||||
*/
|
||||
public function testAcceptLanguageEmptyDefault(): void {
|
||||
|
||||
// Check correct headers.
|
||||
$this->drupalGet('/en/system-test/echo/language test', [], ['Accept-Language' => 'en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'en');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
|
||||
$this->drupalGet('/fr/system-test/echo/language test', [], ['Accept-Language' => 'en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'fr');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
|
||||
$this->drupalGet('/system-test/echo/language test', [], ['Accept-Language' => 'en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'en');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'UNCACHEABLE (response policy)');
|
||||
|
||||
// Check with UK browser.
|
||||
$this->drupalGet('/system-test/echo/language test', [], ['Accept-Language' => 'en-UK,en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'en');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'UNCACHEABLE (response policy)');
|
||||
|
||||
// Check with french browser.
|
||||
$this->drupalGet('/system-test/echo/language test', [], ['Accept-Language' => 'fr-FR,fr']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'fr');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'UNCACHEABLE (response policy)');
|
||||
|
||||
// Check with browser without language settings - should return fallback
|
||||
// language.
|
||||
$this->drupalGet('/system-test/echo/language test', [], ['Accept-Language' => '']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'en');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'UNCACHEABLE (response policy)');
|
||||
|
||||
// Check with french browser again.
|
||||
$this->drupalGet('/system-test/echo/language test', [], ['Accept-Language' => 'fr-FR,fr']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'fr');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'UNCACHEABLE (response policy)');
|
||||
|
||||
// Check with UK browser.
|
||||
$this->drupalGet('/system-test/echo/language test', [], ['Accept-Language' => 'en-UK,en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'en');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'UNCACHEABLE (response policy)');
|
||||
|
||||
// Check if prefixed URLs are still cached.
|
||||
$this->drupalGet('/en/system-test/echo/language test', [], ['Accept-Language' => 'en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'en');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
|
||||
$this->drupalGet('/fr/system-test/echo/language test', [], ['Accept-Language' => 'en']);
|
||||
$this->assertSession()->responseHeaderEquals('Content-Language', 'fr');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests browser language detection.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageBrowserDetectionTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests mappings between browser language codes and Drupal language codes.
|
||||
*/
|
||||
public function testUIBrowserLanguageMappings(): void {
|
||||
// User to manage languages.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Check that the configure link exists.
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->assertSession()->linkByHrefExists('admin/config/regional/language/detection/browser');
|
||||
|
||||
// Check that defaults are loaded from language.mappings.yml.
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser');
|
||||
$this->assertSession()->fieldValueEquals('edit-mappings-zh-cn-browser-langcode', 'zh-cn');
|
||||
$this->assertSession()->fieldValueEquals('edit-mappings-zh-cn-drupal-langcode', 'zh-hans');
|
||||
|
||||
// Delete zh-cn language code.
|
||||
$browser_langcode = 'zh-cn';
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser/delete/' . $browser_langcode);
|
||||
$this->assertSession()->pageTextContains("Are you sure you want to delete {$browser_langcode}?");
|
||||
|
||||
// Confirm the delete.
|
||||
$edit = [];
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser/delete/' . $browser_langcode);
|
||||
$this->submitForm($edit, 'Confirm');
|
||||
|
||||
$this->assertSession()->statusMessageContains("The mapping for the {$browser_langcode} browser language code has been deleted.", 'status');
|
||||
|
||||
// Check we went back to the browser negotiation mapping overview.
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('language.negotiation_browser'));
|
||||
// Check that Chinese browser language code no longer exists.
|
||||
$this->assertSession()->fieldNotExists('edit-mappings-zh-cn-browser-langcode');
|
||||
|
||||
// Add a new custom mapping.
|
||||
$edit = [
|
||||
'new_mapping[browser_langcode]' => 'xx',
|
||||
'new_mapping[drupal_langcode]' => 'en',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('language.negotiation_browser'));
|
||||
$this->assertSession()->fieldValueEquals('edit-mappings-xx-browser-langcode', 'xx');
|
||||
$this->assertSession()->fieldValueEquals('edit-mappings-xx-drupal-langcode', 'en');
|
||||
|
||||
// Add the same custom mapping again.
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('Browser language codes must be unique.', 'error');
|
||||
|
||||
// Change browser language code of our custom mapping to zh-sg.
|
||||
$edit = [
|
||||
'mappings[xx][browser_langcode]' => 'zh-sg',
|
||||
'mappings[xx][drupal_langcode]' => 'en',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('Browser language codes must be unique.', 'error');
|
||||
|
||||
// Change Drupal language code of our custom mapping to zh-hans.
|
||||
$edit = [
|
||||
'mappings[xx][browser_langcode]' => 'xx',
|
||||
'mappings[xx][drupal_langcode]' => 'zh-hans',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/browser');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('language.negotiation_browser'));
|
||||
$this->assertSession()->fieldValueEquals('edit-mappings-xx-browser-langcode', 'xx');
|
||||
$this->assertSession()->fieldValueEquals('edit-mappings-xx-drupal-langcode', 'zh-hans');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Ensures the language config is installed but not altered on install.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigInstallOverrideExistingTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'test_language_negotiation';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests when language config is installed existing config is not overridden.
|
||||
*/
|
||||
public function testLanguageConfigInstallOverrideExisting(): void {
|
||||
/** @var \Drupal\Core\Config\StorageInterface $storage */
|
||||
$storage = $this->container->get('config.storage');
|
||||
$config = $this->config('language.types');
|
||||
|
||||
// The negotiation methods that have been removed should be disabled after
|
||||
// purging if not avoided in language_modules_installed().
|
||||
$language_types_data = $storage->read('language.types');
|
||||
$this->assertTrue(isset($language_types_data['negotiation']['language_content']['enabled']['test_language_negotiation_method']));
|
||||
$this->assertTrue(isset($language_types_data['negotiation']['language_content']['enabled']['language-selected']));
|
||||
|
||||
$this->assertEquals(-10, $config->get('negotiation.language_content.enabled.test_language_negotiation_method'));
|
||||
$this->assertEquals(12, $config->get('negotiation.language_content.enabled.language-selected'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Config\ConfigCollectionEvents;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Ensures the language config overrides can be synchronized.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigOverrideImportTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'config',
|
||||
'locale',
|
||||
'config_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests that language can be enabled and overrides are created during a sync.
|
||||
*/
|
||||
public function testConfigOverrideImport(): void {
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
/** @var \Drupal\Core\Config\StorageInterface $sync */
|
||||
$sync = \Drupal::service('config.storage.sync');
|
||||
$this->copyConfig(\Drupal::service('config.storage'), $sync);
|
||||
|
||||
// Uninstall the language module and its dependencies so we can test
|
||||
// enabling the language module and creating overrides at the same time
|
||||
// during a configuration synchronization.
|
||||
\Drupal::service('module_installer')->uninstall(['language']);
|
||||
// Ensure that the current site has no overrides registered to the
|
||||
// ConfigFactory.
|
||||
$this->rebuildContainer();
|
||||
|
||||
/** @var \Drupal\Core\Config\StorageInterface $override_sync */
|
||||
$override_sync = $sync->createCollection('language.fr');
|
||||
// Create some overrides in sync.
|
||||
$override_sync->write('system.site', ['name' => 'FR default site name']);
|
||||
$override_sync->write('system.maintenance', ['message' => 'FR message: @site is currently under maintenance. We should be back shortly. Thank you for your patience']);
|
||||
|
||||
$this->configImporter()->import();
|
||||
$this->rebuildContainer();
|
||||
|
||||
$override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'system.site');
|
||||
$this->assertEquals('FR default site name', $override->get('name'));
|
||||
$this->drupalGet('fr');
|
||||
$this->assertSession()->pageTextContains('FR default site name');
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'translate configuration',
|
||||
]));
|
||||
$this->drupalGet('admin/config/development/maintenance/translate/fr/edit');
|
||||
$this->assertSession()->pageTextContains('FR message: @site is currently under maintenance. We should be back shortly. Thank you for your patience');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that configuration events are not fired during a sync of overrides.
|
||||
*/
|
||||
public function testConfigOverrideImportEvents(): void {
|
||||
// Enable the config_events_test module so we can record events occurring.
|
||||
\Drupal::service('module_installer')->install(['config_events_test']);
|
||||
$this->rebuildContainer();
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
/** @var \Drupal\Core\Config\StorageInterface $sync */
|
||||
$sync = \Drupal::service('config.storage.sync');
|
||||
$this->copyConfig(\Drupal::service('config.storage'), $sync);
|
||||
|
||||
/** @var \Drupal\Core\Config\StorageInterface $override_sync */
|
||||
$override_sync = $sync->createCollection('language.fr');
|
||||
// Create some overrides in sync.
|
||||
$override_sync->write('system.site', ['name' => 'FR default site name']);
|
||||
\Drupal::state()->set('config_events_test.event', FALSE);
|
||||
|
||||
$this->configImporter()->import();
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Test that no config save event has been fired during the import because
|
||||
// language configuration overrides do not fire events.
|
||||
$event_recorder = \Drupal::state()->get('config_events_test.event', FALSE);
|
||||
$this->assertSame([
|
||||
'event_name' => ConfigCollectionEvents::SAVE_IN_COLLECTION,
|
||||
'current_config_data' => ['name' => 'FR default site name'],
|
||||
'original_config_data' => [],
|
||||
'raw_config_data' => ['name' => 'FR default site name'],
|
||||
], $event_recorder);
|
||||
|
||||
$this->drupalGet('fr');
|
||||
$this->assertSession()->pageTextContains('FR default site name');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Ensures the language config schema is correct.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigSchemaTest extends BrowserTestBase {
|
||||
|
||||
use SchemaCheckTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'menu_link_content'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* A user with administrative permissions.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create user.
|
||||
$this->adminUser = $this->drupalCreateUser(['administer languages']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the language config schema is valid.
|
||||
*/
|
||||
public function testValidLanguageConfigSchema(): void {
|
||||
// Make sure no language configuration available by default.
|
||||
$config_data = $this->config('language.settings')->get();
|
||||
$this->assertEmpty($config_data);
|
||||
|
||||
$settings_path = 'admin/config/regional/content-language';
|
||||
|
||||
// Enable translation for menu link.
|
||||
$edit['entity_types[menu_link_content]'] = TRUE;
|
||||
$edit['settings[menu_link_content][menu_link_content][settings][language][language_alterable]'] = TRUE;
|
||||
|
||||
// Enable translation for user.
|
||||
$edit['entity_types[user]'] = TRUE;
|
||||
$edit['settings[user][user][settings][language][language_alterable]'] = TRUE;
|
||||
$edit['settings[user][user][settings][language][langcode]'] = 'en';
|
||||
|
||||
$this->drupalGet($settings_path);
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
|
||||
$config_data = $this->config('language.content_settings.menu_link_content.menu_link_content');
|
||||
// Make sure configuration saved correctly.
|
||||
$this->assertTrue($config_data->get('language_alterable'));
|
||||
|
||||
$this->assertConfigSchema(\Drupal::service('config.typed'), $config_data->getName(), $config_data->get());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\entity_test\EntityTestHelper;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the features of the language configuration element field.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigurationElementTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'taxonomy',
|
||||
'node',
|
||||
'language',
|
||||
'language_elements_test',
|
||||
'field_ui',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$user = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'administer languages',
|
||||
'administer content types',
|
||||
]);
|
||||
$this->drupalLogin($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the language settings have been saved.
|
||||
*/
|
||||
public function testLanguageConfigurationElement(): void {
|
||||
$this->drupalGet('language-tests/language_configuration_element');
|
||||
$edit['lang_configuration[langcode]'] = 'current_interface';
|
||||
$edit['lang_configuration[language_alterable]'] = FALSE;
|
||||
$this->submitForm($edit, 'Save');
|
||||
$lang_conf = ContentLanguageSettings::loadByEntityTypeBundle('entity_test', 'some_bundle');
|
||||
|
||||
// Check that the settings have been saved.
|
||||
$this->assertEquals('current_interface', $lang_conf->getDefaultLangcode());
|
||||
$this->assertFalse($lang_conf->isLanguageAlterable());
|
||||
$this->drupalGet('language-tests/language_configuration_element');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-lang-configuration-langcode', 'current_interface')->isSelected());
|
||||
$this->assertSession()->checkboxNotChecked('edit-lang-configuration-language-alterable');
|
||||
|
||||
// Reload the page and save again.
|
||||
$this->drupalGet('language-tests/language_configuration_element');
|
||||
$edit['lang_configuration[langcode]'] = 'authors_default';
|
||||
$edit['lang_configuration[language_alterable]'] = TRUE;
|
||||
$this->submitForm($edit, 'Save');
|
||||
$lang_conf = ContentLanguageSettings::loadByEntityTypeBundle('entity_test', 'some_bundle');
|
||||
|
||||
// Check that the settings have been saved.
|
||||
$this->assertEquals('authors_default', $lang_conf->getDefaultLangcode());
|
||||
$this->assertTrue($lang_conf->isLanguageAlterable());
|
||||
$this->drupalGet('language-tests/language_configuration_element');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-lang-configuration-langcode', 'authors_default')->isSelected());
|
||||
$this->assertSession()->checkboxChecked('edit-lang-configuration-language-alterable');
|
||||
|
||||
// Test if content type settings have been saved.
|
||||
$edit = [
|
||||
'name' => 'Page',
|
||||
'type' => 'page',
|
||||
'language_configuration[langcode]' => 'authors_default',
|
||||
'language_configuration[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/types/add');
|
||||
$this->submitForm($edit, 'Save and manage fields');
|
||||
|
||||
// Make sure the settings are saved when creating the content type.
|
||||
$this->drupalGet('admin/structure/types/manage/page');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-language-configuration-langcode', 'authors_default')->isSelected());
|
||||
$this->assertSession()->checkboxChecked('edit-language-configuration-language-alterable');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the language_get_default_langcode() returns the correct values.
|
||||
*/
|
||||
public function testDefaultLangcode(): void {
|
||||
// Add some custom languages.
|
||||
foreach (['aa', 'bb', 'cc'] as $language_code) {
|
||||
ConfigurableLanguage::create([
|
||||
'id' => $language_code,
|
||||
'label' => $this->randomMachineName(),
|
||||
])->save();
|
||||
}
|
||||
|
||||
// Ensure the bundles under test exist, to avoid config validation errors.
|
||||
EntityTestHelper::createBundle('custom_bundle');
|
||||
EntityTestHelper::createBundle('some_bundle');
|
||||
|
||||
// Fixed language.
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('entity_test', 'custom_bundle')
|
||||
->setLanguageAlterable(TRUE)
|
||||
->setDefaultLangcode('bb')
|
||||
->save();
|
||||
|
||||
$langcode = language_get_default_langcode('entity_test', 'custom_bundle');
|
||||
$this->assertEquals('bb', $langcode);
|
||||
|
||||
// Current interface.
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('entity_test', 'custom_bundle')
|
||||
->setLanguageAlterable(TRUE)
|
||||
->setDefaultLangcode('current_interface')
|
||||
->save();
|
||||
|
||||
$langcode = language_get_default_langcode('entity_test', 'custom_bundle');
|
||||
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
|
||||
$this->assertEquals($langcode, $language_interface->getId());
|
||||
|
||||
// Site's default.
|
||||
$old_default = \Drupal::languageManager()->getDefaultLanguage();
|
||||
// Ensure the language entity default value is correct.
|
||||
$configurable_language = ConfigurableLanguage::load($old_default->getId());
|
||||
$this->assertTrue($configurable_language->isDefault(), 'The en language entity is flagged as the default language.');
|
||||
|
||||
$this->config('system.site')->set('default_langcode', 'cc')->save();
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('entity_test', 'custom_bundle')
|
||||
->setLanguageAlterable(TRUE)
|
||||
->setDefaultLangcode(LanguageInterface::LANGCODE_SITE_DEFAULT)
|
||||
->save();
|
||||
$langcode = language_get_default_langcode('entity_test', 'custom_bundle');
|
||||
$this->assertEquals('cc', $langcode);
|
||||
|
||||
// Ensure the language entity default value is correct.
|
||||
$configurable_language = ConfigurableLanguage::load($old_default->getId());
|
||||
$this->assertFalse($configurable_language->isDefault(), 'The en language entity is not flagged as the default language.');
|
||||
$configurable_language = ConfigurableLanguage::load('cc');
|
||||
// Check calling the
|
||||
// \Drupal\language\ConfigurableLanguageInterface::isDefault() method
|
||||
// directly.
|
||||
$this->assertTrue($configurable_language->isDefault(), 'The cc language entity is flagged as the default language.');
|
||||
|
||||
// Check the default value of a language field when authors preferred option
|
||||
// is selected.
|
||||
// First create a user, then assign a langcode.
|
||||
$some_user = $this->drupalCreateUser();
|
||||
$some_user->preferred_langcode = 'bb';
|
||||
$some_user->save();
|
||||
$this->drupalLogin($some_user);
|
||||
ContentLanguageSettings::create([
|
||||
'target_entity_type_id' => 'entity_test',
|
||||
'target_bundle' => 'some_bundle',
|
||||
])->setLanguageAlterable(TRUE)
|
||||
->setDefaultLangcode('authors_default')
|
||||
->save();
|
||||
|
||||
$this->drupalGet('language-tests/language_configuration_element_test');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode', 'bb')->isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the configuration is retained when the node type is updated.
|
||||
*/
|
||||
public function testNodeTypeUpdate(): void {
|
||||
// Create the article content type first if the profile used is not the
|
||||
// standard one.
|
||||
if ($this->profile != 'standard') {
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
}
|
||||
$admin_user = $this->drupalCreateUser(['administer content types']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$edit = [
|
||||
'language_configuration[langcode]' => 'current_interface',
|
||||
'language_configuration[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/types/manage/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
// Check the language default configuration for the articles.
|
||||
$configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', 'article');
|
||||
$uuid = $configuration->uuid();
|
||||
$this->assertEquals('current_interface', $configuration->getDefaultLangcode(), 'The default language configuration has been saved on the Article content type.');
|
||||
$this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been saved on the Article content type.');
|
||||
// Update the article content type by changing the title label.
|
||||
$edit = [
|
||||
'title_label' => 'Name',
|
||||
];
|
||||
$this->drupalGet('admin/structure/types/manage/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
// Check that we still have the settings for the updated node type.
|
||||
$configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', 'article');
|
||||
$this->assertEquals('current_interface', $configuration->getDefaultLangcode(), 'The default language configuration has been kept on the updated Article content type.');
|
||||
$this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been kept on the updated Article content type.');
|
||||
$this->assertEquals($uuid, $configuration->uuid(), 'The language configuration uuid has been kept on the updated Article content type.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the language settings are deleted on bundle delete.
|
||||
*/
|
||||
public function testNodeTypeDelete(): void {
|
||||
// Create the article content type first if the profile used is not the
|
||||
// standard one.
|
||||
if ($this->profile != 'standard') {
|
||||
$this->drupalCreateContentType([
|
||||
'type' => 'article',
|
||||
'name' => 'Article',
|
||||
]);
|
||||
}
|
||||
$admin_user = $this->drupalCreateUser(['administer content types']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create language configuration for the articles.
|
||||
$edit = [
|
||||
'language_configuration[langcode]' => 'authors_default',
|
||||
'language_configuration[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/types/manage/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check the language default configuration for articles is present.
|
||||
$configuration = \Drupal::entityTypeManager()->getStorage('language_content_settings')->load('node.article');
|
||||
$this->assertNotEmpty($configuration, 'The language configuration is present.');
|
||||
|
||||
// Delete 'article' bundle.
|
||||
$this->drupalGet('admin/structure/types/manage/article/delete');
|
||||
$this->submitForm([], 'Delete');
|
||||
|
||||
// Check that the language configuration has been deleted.
|
||||
\Drupal::entityTypeManager()->getStorage('language_content_settings')->resetCache();
|
||||
$configuration = \Drupal::entityTypeManager()->getStorage('language_content_settings')->load('node.article');
|
||||
$this->assertNull($configuration, 'The language configuration was deleted after bundle was deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the configuration is retained when a vocabulary is updated.
|
||||
*/
|
||||
public function testTaxonomyVocabularyUpdate(): void {
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Country',
|
||||
'vid' => 'country',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['administer taxonomy']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$edit = [
|
||||
'default_language[langcode]' => 'current_interface',
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/country');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check the language default configuration.
|
||||
$configuration = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', 'country');
|
||||
$uuid = $configuration->uuid();
|
||||
$this->assertEquals('current_interface', $configuration->getDefaultLangcode(), 'The default language configuration has been saved on the Country vocabulary.');
|
||||
$this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been saved on the Country vocabulary.');
|
||||
// Update the vocabulary.
|
||||
$edit = [
|
||||
'name' => 'Nation',
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/country');
|
||||
$this->submitForm($edit, 'Save');
|
||||
// Check that we still have the settings for the updated vocabulary.
|
||||
$configuration = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', 'country');
|
||||
$this->assertEquals('current_interface', $configuration->getDefaultLangcode(), 'The default language configuration has been kept on the updated Country vocabulary.');
|
||||
$this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been kept on the updated Country vocabulary.');
|
||||
$this->assertEquals($uuid, $configuration->uuid(), 'The language configuration uuid has been kept on the updated Country vocabulary.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Adds and configures languages to check negotiation changes.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigurationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Functional tests for adding, editing and deleting languages.
|
||||
*/
|
||||
public function testLanguageConfiguration(): void {
|
||||
// Ensure the after installing the language module the weight of the English
|
||||
// language is still 0.
|
||||
$this->assertEquals(0, ConfigurableLanguage::load('en')->getWeight(), 'The English language has a weight of 0.');
|
||||
|
||||
// User to add and remove language.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Check if the Default English language has no path prefix.
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->assertSession()->fieldValueEquals("prefix[en]", '');
|
||||
|
||||
// Check that Add language is a primary button.
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$button = $this->assertSession()->buttonExists('Add language');
|
||||
$this->assertTrue($button->hasClass("button--primary"));
|
||||
|
||||
// Add predefined language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->submitForm($edit, 'Add language');
|
||||
$this->assertSession()->pageTextContains('French');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
// Langcode for Languages is always 'en'.
|
||||
$language = $this->config('language.entity.fr')->get();
|
||||
$this->assertEquals('en', $language['langcode']);
|
||||
|
||||
// Check if the Default English language has no path prefix.
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->assertSession()->fieldValueEquals("prefix[en]", '');
|
||||
// Check if French has a path prefix.
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->assertSession()->fieldValueEquals("prefix[fr]", 'fr');
|
||||
|
||||
// Check if we can change the default language.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertSession()->checkboxChecked('edit-site-default-language-en');
|
||||
|
||||
// Change the default language.
|
||||
$edit = [
|
||||
'site_default_language' => 'fr',
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->rebuildContainer();
|
||||
$this->assertSession()->checkboxChecked('edit-site-default-language-fr');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection', [], ['langcode' => 'fr']));
|
||||
|
||||
// Check if a valid language prefix is added after changing the default
|
||||
// language.
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->assertSession()->fieldValueEquals("prefix[en]", 'en');
|
||||
// Check if French still has a path prefix.
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->assertSession()->fieldValueEquals("prefix[fr]", 'fr');
|
||||
|
||||
// Check that prefix can be changed.
|
||||
$edit = [
|
||||
'prefix[fr]' => 'french',
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->fieldValueEquals("prefix[fr]", 'french');
|
||||
|
||||
// Check that the prefix can be removed.
|
||||
$edit = [
|
||||
'prefix[fr]' => '',
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageNotContains('The prefix may only be left blank for the selected detection fallback language.');
|
||||
|
||||
// Change default negotiation language.
|
||||
$this->config('language.negotiation')->set('selected_langcode', 'fr')->save();
|
||||
// Check that the prefix of a language that is not the negotiation one
|
||||
// cannot be changed to empty string.
|
||||
$edit = [
|
||||
'prefix[en]' => '',
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('The prefix may only be left blank for the selected detection fallback language.', 'error');
|
||||
|
||||
// Check that prefix cannot be changed to contain a slash.
|
||||
$edit = [
|
||||
'prefix[en]' => 'foo/bar',
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('The prefix may not contain a slash.', 'error');
|
||||
|
||||
// Remove English language and add a new Language to check if langcode of
|
||||
// Language entity is 'en'.
|
||||
$this->drupalGet('admin/config/regional/language/delete/en');
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->rebuildContainer();
|
||||
$this->assertSession()->statusMessageContains('The English (en) language has been removed.', 'status');
|
||||
|
||||
// Ensure that French language has a weight of 1 after being created through
|
||||
// the UI.
|
||||
$french = ConfigurableLanguage::load('fr');
|
||||
$this->assertEquals(1, $french->getWeight(), 'The French language has a weight of 1.');
|
||||
// Ensure that French language can now have a weight of 0.
|
||||
$french->setWeight(0)->save();
|
||||
$this->assertEquals(0, $french->getWeight(), 'The French language has a weight of 0.');
|
||||
// Ensure that new languages created through the API get a weight of 0.
|
||||
$afrikaans = ConfigurableLanguage::createFromLangcode('af');
|
||||
$afrikaans->save();
|
||||
$this->assertEquals(0, $afrikaans->getWeight(), 'The Afrikaans language has a weight of 0.');
|
||||
// Ensure that a new language can be created with any weight.
|
||||
$arabic = ConfigurableLanguage::createFromLangcode('ar');
|
||||
$arabic->setWeight(4)->save();
|
||||
$this->assertEquals(4, $arabic->getWeight(), 'The Arabic language has a weight of 0.');
|
||||
|
||||
$edit = [
|
||||
'predefined_langcode' => 'de',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
$language = $this->config('language.entity.de')->get();
|
||||
$this->assertEquals('fr', $language['langcode']);
|
||||
|
||||
// Ensure that German language has a weight of 5 after being created through
|
||||
// the UI.
|
||||
$french = ConfigurableLanguage::load('de');
|
||||
$this->assertEquals(5, $french->getWeight(), 'The German language has a weight of 5.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional tests for setting system language weight on adding, editing and deleting languages.
|
||||
*/
|
||||
public function testLanguageConfigurationWeight(): void {
|
||||
// User to add and remove language.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->checkConfigurableLanguageWeight();
|
||||
|
||||
// Add predefined language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
$this->checkConfigurableLanguageWeight('after adding new language');
|
||||
|
||||
// Re-ordering languages.
|
||||
$edit = [
|
||||
'languages[en][weight]' => $this->getHighestConfigurableLanguageWeight() + 1,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->checkConfigurableLanguageWeight('after re-ordering');
|
||||
|
||||
// Remove predefined language.
|
||||
$this->drupalGet('admin/config/regional/language/delete/fr');
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->checkConfigurableLanguageWeight('after deleting a language');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates system languages are ordered after configurable languages.
|
||||
*
|
||||
* @param string $state
|
||||
* (optional) A string for customizing assert messages, containing the
|
||||
* description of the state of the check, for example: 'after re-ordering'.
|
||||
* Defaults to 'by default'.
|
||||
*/
|
||||
protected function checkConfigurableLanguageWeight($state = 'by default'): void {
|
||||
// Reset language list.
|
||||
\Drupal::languageManager()->reset();
|
||||
$max_configurable_language_weight = $this->getHighestConfigurableLanguageWeight();
|
||||
foreach (\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_LOCKED) as $locked_language) {
|
||||
$this->assertGreaterThan($max_configurable_language_weight, $locked_language->getWeight(), sprintf('System language %s does not have higher weight than configurable languages %s', $locked_language->getName(), $state));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get maximum weight of configurable (unlocked) languages.
|
||||
*
|
||||
* @return int
|
||||
* Maximum weight of configurable languages.
|
||||
*/
|
||||
protected function getHighestConfigurableLanguageWeight(): int {
|
||||
$max_weight = 0;
|
||||
|
||||
$storage = $this->container->get('entity_type.manager')
|
||||
->getStorage('configurable_language');
|
||||
$storage->resetCache();
|
||||
/** @var \Drupal\Core\Language\LanguageInterface[] $languages */
|
||||
$languages = $storage->loadMultiple();
|
||||
foreach ($languages as $language) {
|
||||
if (!$language->isLocked()) {
|
||||
$max_weight = max($max_weight, $language->getWeight());
|
||||
}
|
||||
}
|
||||
|
||||
return $max_weight;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Adds and configures custom languages.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageCustomLanguageConfigurationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Functional tests for adding, editing and deleting languages.
|
||||
*/
|
||||
public function testLanguageConfiguration(): void {
|
||||
|
||||
// Create user with permissions to add and remove languages.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Add custom language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
// Test validation on missing values.
|
||||
$this->assertSession()->statusMessageContains('Language code field is required.', 'error');
|
||||
$this->assertSession()->statusMessageContains('Language name field is required.', 'error');
|
||||
$empty_language = new Language();
|
||||
$this->assertSession()->checkboxChecked('edit-direction-' . $empty_language->getDirection());
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('language.add'));
|
||||
|
||||
// Test validation of invalid values.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => 'white space',
|
||||
'label' => '<strong>evil markup</strong>',
|
||||
'direction' => LanguageInterface::DIRECTION_LTR,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
|
||||
$this->assertSession()->statusMessageContains('Language code must be a valid language tag as defined by the W3C.', 'error');
|
||||
$this->assertSession()->linkExists("defined by the W3C");
|
||||
$this->assertSession()->linkByHrefExists("https://www.w3.org/International/articles/language-tags/");
|
||||
$this->assertSession()->statusMessageContains('Language name cannot contain any markup.', 'error');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('language.add'));
|
||||
|
||||
// Test adding a custom language with a numeric region code.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => 'es-419',
|
||||
'label' => 'Latin American Spanish',
|
||||
'direction' => LanguageInterface::DIRECTION_LTR,
|
||||
];
|
||||
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
$this->assertSession()->statusMessageContains("The language {$edit['label']} has been created and can now be used.", 'status');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
|
||||
// Test validation of existing language values.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => 'de',
|
||||
'label' => 'German',
|
||||
'direction' => LanguageInterface::DIRECTION_LTR,
|
||||
];
|
||||
|
||||
// Add the language the first time.
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
$this->assertSession()->statusMessageContains("The language {$edit['label']} has been created and can now be used.", 'status');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
|
||||
// Add the language a second time and confirm that this is not allowed.
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
$this->assertSession()->statusMessageContains("The language {$edit['label']} ({$edit['langcode']}) already exists.", 'error');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('language.add'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests language picker compatibility with hook_entity_field_access.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageEntityFieldAccessHookTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'text',
|
||||
'field',
|
||||
'filter',
|
||||
'language',
|
||||
'language_entity_field_access_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests compatibility with hook_entity_field_access().
|
||||
*/
|
||||
public function testHookEntityFieldAccess(): void {
|
||||
// Create an admin user and do the login.
|
||||
$user = $this->drupalCreateUser([], NULL, TRUE);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Assess the field is not visible.
|
||||
$this->drupalGet('node/add/page');
|
||||
$this->assertSession()->fieldNotExists('langcode[0][value]');
|
||||
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that the language list is not empty when language is installed.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageListModuleInstallTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests enabling Language.
|
||||
*/
|
||||
public function testModuleInstallLanguageList(): void {
|
||||
// Since LanguageManager::getLanguages() uses static caches we need to do
|
||||
// this by enabling the module using the UI.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'administer modules',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
$edit = [];
|
||||
$edit['modules[language][enable]'] = 'language';
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
$this->assertEquals(1, \Drupal::state()->get('language_test.language_count_preinstall', 0), 'Using LanguageManager::getLanguages() returns 1 language during Language installation.');
|
||||
|
||||
// Get updated module list by rebuilding container.
|
||||
$this->rebuildContainer();
|
||||
$this->assertTrue(\Drupal::moduleHandler()->moduleExists('language'), 'Language module is enabled');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Adds a new language and tests changing its status and the default language.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageListTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Functional tests for adding, editing and deleting languages.
|
||||
*/
|
||||
public function testLanguageList(): void {
|
||||
|
||||
// User to add and remove language.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Get the weight of the last language.
|
||||
$languages = \Drupal::service('language_manager')->getLanguages();
|
||||
$last_language_weight = end($languages)->getWeight();
|
||||
|
||||
// Add predefined language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
$this->assertSession()->pageTextContains('French');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
|
||||
// Get the weight of the last language and check that the weight is one unit
|
||||
// heavier than the last configurable language.
|
||||
$this->rebuildContainer();
|
||||
$languages = \Drupal::service('language_manager')->getLanguages();
|
||||
$last_language = end($languages);
|
||||
$this->assertEquals($last_language_weight + 1, $last_language->getWeight());
|
||||
$this->assertEquals($edit['predefined_langcode'], $last_language->getId());
|
||||
|
||||
// Add custom language.
|
||||
$langcode = 'xx';
|
||||
$name = $this->randomMachineName(16);
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => $langcode,
|
||||
'label' => $name,
|
||||
'direction' => Language::DIRECTION_LTR,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
$this->assertSession()->responseContains('"edit-languages-' . $langcode . '-weight"');
|
||||
$this->assertSession()->pageTextContains($name);
|
||||
|
||||
$language = \Drupal::service('language_manager')->getLanguage($langcode);
|
||||
$english = \Drupal::service('language_manager')->getLanguage('en');
|
||||
|
||||
// Check if we can change the default language.
|
||||
$path = 'admin/config/regional/language';
|
||||
$this->drupalGet($path);
|
||||
$this->assertSession()->checkboxChecked('edit-site-default-language-en');
|
||||
// Change the default language.
|
||||
$edit = [
|
||||
'site_default_language' => $langcode,
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->rebuildContainer();
|
||||
$this->assertSession()->checkboxNotChecked('edit-site-default-language-en');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection', [], ['language' => $language]));
|
||||
|
||||
// Ensure we can't delete the default language.
|
||||
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Ensure 'Edit' link works.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->clickLink('Edit');
|
||||
$this->assertSession()->titleEquals('Edit language | Drupal');
|
||||
// Edit a language.
|
||||
$name = $this->randomMachineName(16);
|
||||
$edit = [
|
||||
'label' => $name,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/edit/' . $langcode);
|
||||
$this->submitForm($edit, 'Save language');
|
||||
$this->assertSession()->pageTextContains($name);
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection', [], ['language' => $language]));
|
||||
|
||||
// Change back the default language.
|
||||
$edit = [
|
||||
'site_default_language' => 'en',
|
||||
];
|
||||
$this->drupalGet($path);
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->rebuildContainer();
|
||||
// Ensure 'delete' link works.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->clickLink('Delete');
|
||||
$this->assertSession()->pageTextContains('Are you sure you want to delete the language');
|
||||
// Delete a language.
|
||||
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
|
||||
// First test the 'cancel' link.
|
||||
$this->clickLink('Cancel');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection', [], ['language' => $english]));
|
||||
$this->assertSession()->pageTextContains($name);
|
||||
// Delete the language for real. This a confirm form, we do not need any
|
||||
// fields changed.
|
||||
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertSession()->statusMessageContains("The {$name} ({$langcode}) language has been removed.", 'status');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection', [], ['language' => $english]));
|
||||
// Verify that language is no longer found.
|
||||
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
|
||||
// Delete French.
|
||||
$this->drupalGet('admin/config/regional/language/delete/fr');
|
||||
$this->submitForm([], 'Delete');
|
||||
// Make sure the "language_count" state has been updated correctly.
|
||||
$this->rebuildContainer();
|
||||
$this->assertSession()->statusMessageContains('The French (fr) language has been removed.', 'status');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
// Verify that language is no longer found.
|
||||
$this->drupalGet('admin/config/regional/language/delete/fr');
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
// Make sure the "language_count" state has not changed.
|
||||
|
||||
// Ensure we can delete the English language. Right now English is the only
|
||||
// language so we must add a new language and make it the default before
|
||||
// deleting English.
|
||||
$langcode = 'xx';
|
||||
$name = $this->randomMachineName(16);
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => $langcode,
|
||||
'label' => $name,
|
||||
'direction' => Language::DIRECTION_LTR,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add custom language');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
$this->assertSession()->pageTextContains($name);
|
||||
|
||||
// Check if we can change the default language.
|
||||
$path = 'admin/config/regional/language';
|
||||
$this->drupalGet($path);
|
||||
$this->assertSession()->checkboxChecked('edit-site-default-language-en');
|
||||
// Change the default language.
|
||||
$edit = [
|
||||
'site_default_language' => $langcode,
|
||||
];
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->rebuildContainer();
|
||||
$this->assertSession()->checkboxNotChecked('edit-site-default-language-en');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection', [], ['language' => $language]));
|
||||
|
||||
$this->drupalGet('admin/config/regional/language/delete/en');
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertSession()->statusMessageContains('The English (en) language has been removed.', 'status');
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Ensure we can't delete a locked language.
|
||||
$this->drupalGet('admin/config/regional/language/delete/und');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Ensure that NL cannot be set default when it's not available.
|
||||
// First create the NL language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'nl',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Load the form which has now the additional NL language option.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
|
||||
// Delete the NL language in the background.
|
||||
$language_storage = $this->container->get('entity_type.manager')->getStorage('configurable_language');
|
||||
$language_storage->load('nl')->delete();
|
||||
|
||||
$this->submitForm(['site_default_language' => 'nl'], 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('Selected default language no longer exists.', 'error');
|
||||
$this->assertSession()->checkboxNotChecked('edit-site-default-language-xx');
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional tests for the language states (locked or configurable).
|
||||
*/
|
||||
public function testLanguageStates(): void {
|
||||
// Add some languages, and also lock some of them.
|
||||
ConfigurableLanguage::create(['label' => $this->randomMachineName(), 'id' => 'l1'])->save();
|
||||
ConfigurableLanguage::create(['label' => $this->randomMachineName(), 'id' => 'l2', 'locked' => TRUE])->save();
|
||||
ConfigurableLanguage::create(['label' => $this->randomMachineName(), 'id' => 'l3'])->save();
|
||||
ConfigurableLanguage::create(['label' => $this->randomMachineName(), 'id' => 'l4', 'locked' => TRUE])->save();
|
||||
$expected_locked_languages = ['l4' => 'l4', 'l2' => 'l2', 'und' => 'und', 'zxx' => 'zxx'];
|
||||
$expected_all_languages = ['l4' => 'l4', 'l3' => 'l3', 'l2' => 'l2', 'l1' => 'l1', 'en' => 'en', 'und' => 'und', 'zxx' => 'zxx'];
|
||||
$expected_conf_languages = ['l3' => 'l3', 'l1' => 'l1', 'en' => 'en'];
|
||||
|
||||
$locked_languages = $this->container->get('language_manager')->getLanguages(LanguageInterface::STATE_LOCKED);
|
||||
$this->assertEquals([], array_diff_key($expected_locked_languages, $locked_languages), 'Locked languages loaded correctly.');
|
||||
|
||||
$all_languages = $this->container->get('language_manager')->getLanguages(LanguageInterface::STATE_ALL);
|
||||
$this->assertEquals([], array_diff_key($expected_all_languages, $all_languages), 'All languages loaded correctly.');
|
||||
|
||||
$conf_languages = $this->container->get('language_manager')->getLanguages();
|
||||
$this->assertEquals([], array_diff_key($expected_conf_languages, $conf_languages), 'Configurable languages loaded correctly.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\locale\StringStorageInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
// cspell:ignore espagnol
|
||||
|
||||
/**
|
||||
* Adds a new language with translations and tests language list order.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageLocaleListTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'locale'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* @var \Drupal\locale\StringStorageInterface
|
||||
*/
|
||||
protected StringStorageInterface $storage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Add a default locale storage for all these tests.
|
||||
$this->storage = $this->container->get('locale.storage');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests adding, editing, and deleting languages.
|
||||
*/
|
||||
public function testLanguageLocaleList(): void {
|
||||
// User to add and remove language.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Add predefined language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
$this->assertSession()->statusMessageContains('The language French has been created and can now be used', 'status');
|
||||
$this->assertSession()->addressEquals(Url::fromRoute('entity.configurable_language.collection'));
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Translate Spanish language to French (Espagnol).
|
||||
$source = $this->storage->createString([
|
||||
'source' => 'Spanish',
|
||||
'context' => '',
|
||||
])->save();
|
||||
$this->storage->createTranslation([
|
||||
'lid' => $source->lid,
|
||||
'language' => 'fr',
|
||||
'translation' => 'Espagnol',
|
||||
])->save();
|
||||
|
||||
// Get language list displayed in select list.
|
||||
$this->drupalGet('fr/admin/config/regional/language/add');
|
||||
$options = $this->assertSession()->selectExists('edit-predefined-langcode')->findAll('css', 'option');
|
||||
$options = array_map(function ($item) {
|
||||
return $item->getText();
|
||||
}, $options);
|
||||
// Remove the 'Custom language...' option form the end.
|
||||
array_pop($options);
|
||||
// Order language list.
|
||||
$options_ordered = $options;
|
||||
natcasesort($options_ordered);
|
||||
|
||||
// Check the language list displayed is ordered.
|
||||
$this->assertSame($options, $options_ordered, 'Language list is ordered.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Core\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Tests language negotiation with the language negotiator content entity.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationContentEntityTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'language_test',
|
||||
'entity_test',
|
||||
'system',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The entity being used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
// In order to reflect the changes for a multilingual site in the container
|
||||
// we have to rebuild it.
|
||||
$this->rebuildContainer();
|
||||
|
||||
$this->createTranslatableEntity();
|
||||
|
||||
$user = $this->drupalCreateUser(['view test entity']);
|
||||
$this->drupalLogin($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests default with content language remaining same as interface language.
|
||||
*/
|
||||
public function testDefaultConfiguration(): void {
|
||||
$translation = $this->entity;
|
||||
$this->drupalGet($translation->toUrl());
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
$last_content_language = $last[LanguageInterface::TYPE_CONTENT];
|
||||
$last_interface_language = $last[LanguageInterface::TYPE_INTERFACE];
|
||||
$this->assertSame($last_content_language, $last_interface_language);
|
||||
$this->assertSame($translation->language()->getId(), $last_content_language);
|
||||
|
||||
$translation = $this->entity->getTranslation('es');
|
||||
$this->drupalGet($translation->toUrl());
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
$last_content_language = $last[LanguageInterface::TYPE_CONTENT];
|
||||
$last_interface_language = $last[LanguageInterface::TYPE_INTERFACE];
|
||||
$this->assertSame($last_content_language, $last_interface_language);
|
||||
$this->assertSame($translation->language()->getId(), $last_content_language);
|
||||
|
||||
$translation = $this->entity->getTranslation('fr');
|
||||
$this->drupalGet($translation->toUrl());
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
$last_content_language = $last[LanguageInterface::TYPE_CONTENT];
|
||||
$last_interface_language = $last[LanguageInterface::TYPE_INTERFACE];
|
||||
$this->assertSame($last_content_language, $last_interface_language);
|
||||
$this->assertSame($translation->language()->getId(), $last_content_language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests enabling the language negotiator language_content_entity.
|
||||
*/
|
||||
public function testEnabledLanguageContentNegotiator(): void {
|
||||
// Define the method language-url with a higher priority than
|
||||
// language-content-entity. This configuration should match the default one,
|
||||
// where the language-content-entity is turned off.
|
||||
$config = $this->config('language.types');
|
||||
$config->set('configurable', [LanguageInterface::TYPE_INTERFACE, LanguageInterface::TYPE_CONTENT]);
|
||||
$config->set('negotiation.language_content.enabled', [
|
||||
LanguageNegotiationUrl::METHOD_ID => 0,
|
||||
LanguageNegotiationContentEntity::METHOD_ID => 1,
|
||||
]);
|
||||
$config->save();
|
||||
|
||||
// In order to reflect the changes for a multilingual site in the container
|
||||
// we have to rebuild it.
|
||||
$this->rebuildContainer();
|
||||
|
||||
// The tests for the default configuration should still pass.
|
||||
$this->testDefaultConfiguration();
|
||||
|
||||
// Define the method language-content-entity with a higher priority than
|
||||
// language-url.
|
||||
$config->set('negotiation.language_content.enabled', [
|
||||
LanguageNegotiationContentEntity::METHOD_ID => 0,
|
||||
LanguageNegotiationUrl::METHOD_ID => 1,
|
||||
]);
|
||||
$config->save();
|
||||
|
||||
// In order to reflect the changes for a multilingual site in the container
|
||||
// we have to rebuild it.
|
||||
$this->rebuildContainer();
|
||||
|
||||
// The method language-content-entity should run before language-url and
|
||||
// append query parameter for the content language and prevent language-url
|
||||
// from overwriting the URL.
|
||||
$default_site_langcode = $this->config('system.site')->get('default_langcode');
|
||||
|
||||
// Now switching to an entity route, so that the URL links are generated
|
||||
// while being on an entity route.
|
||||
$this->setCurrentRequestForRoute('/entity_test/{entity_test}', 'entity.entity_test.canonical');
|
||||
|
||||
$translation = $this->entity;
|
||||
$this->drupalGet($translation->toUrl());
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
$last_content_language = $last[LanguageInterface::TYPE_CONTENT];
|
||||
$last_interface_language = $last[LanguageInterface::TYPE_INTERFACE];
|
||||
// Check that interface language and content language are the same as the
|
||||
// default translation language of the entity.
|
||||
$this->assertSame($default_site_langcode, $last_interface_language);
|
||||
$this->assertSame($last_content_language, $last_interface_language);
|
||||
$this->assertSame($translation->language()->getId(), $last_content_language);
|
||||
|
||||
$translation = $this->entity->getTranslation('es');
|
||||
$this->drupalGet($translation->toUrl());
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
$last_content_language = $last[LanguageInterface::TYPE_CONTENT];
|
||||
$last_interface_language = $last[LanguageInterface::TYPE_INTERFACE];
|
||||
$this->assertSame($last_interface_language, $default_site_langcode, 'Interface language did not change from the default site language.');
|
||||
$this->assertSame($last_content_language, $translation->language()->getId(), 'Content language matches the current entity translation language.');
|
||||
|
||||
$translation = $this->entity->getTranslation('fr');
|
||||
$this->drupalGet($translation->toUrl());
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
$last_content_language = $last[LanguageInterface::TYPE_CONTENT];
|
||||
$last_interface_language = $last[LanguageInterface::TYPE_INTERFACE];
|
||||
$this->assertSame($last_interface_language, $default_site_langcode, 'Interface language did not change from the default site language.');
|
||||
$this->assertSame($last_content_language, $translation->language()->getId(), 'Content language matches the current entity translation language.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a translated entity.
|
||||
*/
|
||||
protected function createTranslatableEntity(): void {
|
||||
$this->entity = EntityTest::create();
|
||||
$this->entity->addTranslation('es', ['name' => 'name spanish']);
|
||||
$this->entity->addTranslation('fr', ['name' => 'name french']);
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current request to a specific path with the corresponding route.
|
||||
*
|
||||
* @param string $path
|
||||
* The path for which the current request should be created.
|
||||
* @param string $route_name
|
||||
* The route name for which the route object for the request should be
|
||||
* created.
|
||||
*/
|
||||
protected function setCurrentRequestForRoute($path, $route_name): void {
|
||||
$request = Request::create($path);
|
||||
$request->attributes->set(RouteObjectInterface::ROUTE_NAME, $route_name);
|
||||
$request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route($path));
|
||||
$request->setSession(new Session(new MockArraySessionStorage()));
|
||||
$this->container->get('request_stack')->push($request);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests alterations to language types/negotiation info.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationInfoTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'content_translation'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
'view the administration theme',
|
||||
'administer modules',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm(['predefined_langcode' => 'it'], 'Add language');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurable language manager.
|
||||
*
|
||||
* @return \Drupal\language\ConfigurableLanguageManager
|
||||
* The language manager.
|
||||
*/
|
||||
protected function languageManager() {
|
||||
return $this->container->get('language_manager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets key/value pairs for language_test module.
|
||||
*
|
||||
* Ensures to correctly update data both in the child site and the test runner
|
||||
* environment.
|
||||
*
|
||||
* @param array $values
|
||||
* The key/value pairs to set in the key value store.
|
||||
*/
|
||||
protected function keysValuesSet(array $values): void {
|
||||
// Set the new key value values.
|
||||
$this->container->get('keyvalue')->get('language_test')->setMultiple($values);
|
||||
// Refresh in-memory static key value/config caches and static variables.
|
||||
$this->refreshVariables();
|
||||
// Refresh/rewrite language negotiation configuration, in order to pick up
|
||||
// the manipulations performed by language_test module's info alter hooks.
|
||||
$this->container->get('language_negotiator')->purgeConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alterations to language types/negotiation info.
|
||||
*/
|
||||
public function testInfoAlterations(): void {
|
||||
$this->keysValuesSet([
|
||||
// Enable language_test type info.
|
||||
'language_types' => TRUE,
|
||||
// Enable language_test negotiation info (not altered yet).
|
||||
'language_negotiation_info' => TRUE,
|
||||
// Alter LanguageInterface::TYPE_CONTENT to be configurable.
|
||||
'content_language_type' => TRUE,
|
||||
]);
|
||||
$this->container->get('module_installer')->install(['language_test']);
|
||||
$this->resetAll();
|
||||
|
||||
// Check that fixed language types are properly configured without the need
|
||||
// of saving the language negotiation settings.
|
||||
$this->checkFixedLanguageTypes();
|
||||
|
||||
$type = LanguageInterface::TYPE_CONTENT;
|
||||
$language_types = $this->languageManager()->getLanguageTypes();
|
||||
$this->assertContains($type, $language_types, 'Content language type is configurable.');
|
||||
|
||||
// Enable some core and custom language negotiation methods. The test
|
||||
// language type is supposed to be configurable.
|
||||
$test_type = 'test_language_type';
|
||||
$interface_method_id = LanguageNegotiationUI::METHOD_ID;
|
||||
$test_method_id = 'test_language_negotiation_method';
|
||||
$form_field = $type . '[enabled][' . $interface_method_id . ']';
|
||||
$edit = [
|
||||
$form_field => TRUE,
|
||||
$type . '[enabled][' . $test_method_id . ']' => TRUE,
|
||||
$test_type . '[enabled][' . $test_method_id . ']' => TRUE,
|
||||
$test_type . '[configurable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Alter language negotiation info to remove interface language negotiation
|
||||
// method.
|
||||
$this->keysValuesSet([
|
||||
'language_negotiation_info_alter' => TRUE,
|
||||
]);
|
||||
|
||||
$negotiation = $this->config('language.types')->get('negotiation.' . $type . '.enabled');
|
||||
$this->assertFalse(isset($negotiation[$interface_method_id]), 'Interface language negotiation method removed from the stored settings.');
|
||||
|
||||
// Check that the interface language negotiation method is unavailable.
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->assertSession()->fieldNotExists($form_field);
|
||||
|
||||
// Check that type-specific language negotiation methods can be assigned
|
||||
// only to the corresponding language types.
|
||||
foreach ($this->languageManager()->getLanguageTypes() as $type) {
|
||||
$form_field = $type . '[enabled][test_language_negotiation_method_ts]';
|
||||
if ($type == $test_type) {
|
||||
$this->assertSession()->fieldExists($form_field);
|
||||
}
|
||||
else {
|
||||
$this->assertSession()->fieldNotExists($form_field);
|
||||
}
|
||||
}
|
||||
|
||||
// Check language negotiation results.
|
||||
$this->drupalGet('');
|
||||
$last = \Drupal::keyValue('language_test')->get('language_negotiation_last');
|
||||
foreach ($this->languageManager()->getDefinedLanguageTypes() as $type) {
|
||||
$langcode = $last[$type];
|
||||
$value = $type == LanguageInterface::TYPE_CONTENT || str_contains($type, 'test') ? 'it' : 'en';
|
||||
$this->assertEquals($langcode, $value, "The negotiated language for $type is $value");
|
||||
}
|
||||
|
||||
// Uninstall language_test and check that everything is set back to the
|
||||
// original status.
|
||||
$this->container->get('module_installer')->uninstall(['language_test']);
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Check that only the core language types are available.
|
||||
foreach ($this->languageManager()->getDefinedLanguageTypes() as $type) {
|
||||
$this->assertStringNotContainsString('test', $type, "The $type language is still available");
|
||||
}
|
||||
|
||||
// Check that fixed language types are properly configured, even those
|
||||
// previously set to configurable.
|
||||
$this->checkFixedLanguageTypes();
|
||||
|
||||
// Check that unavailable language negotiation methods are not present in
|
||||
// the negotiation settings.
|
||||
$negotiation = $this->config('language.types')->get('negotiation.' . $type . '.enabled');
|
||||
$this->assertFalse(isset($negotiation[$test_method_id]), 'The disabled test language negotiation method is not part of the content language negotiation settings.');
|
||||
|
||||
// Check that configuration page presents the correct options and settings.
|
||||
$this->assertSession()->pageTextNotContains("Test language detection");
|
||||
$this->assertSession()->pageTextNotContains("This is a test language negotiation method");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that language negotiation for fixed types matches the stored one.
|
||||
*/
|
||||
protected function checkFixedLanguageTypes(): void {
|
||||
$configurable = $this->languageManager()->getLanguageTypes();
|
||||
foreach ($this->languageManager()->getDefinedLanguageTypesInfo() as $type => $info) {
|
||||
if (!in_array($type, $configurable) && isset($info['fixed'])) {
|
||||
$negotiation = $this->config('language.types')->get('negotiation.' . $type . '.enabled');
|
||||
$equal = array_keys($negotiation) === array_values($info['fixed']);
|
||||
$this->assertTrue($equal, "language negotiation for $type is properly set up");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests altering config of configurable language types.
|
||||
*/
|
||||
public function testConfigLangTypeAlterations(): void {
|
||||
// Default of config.
|
||||
$test_type = LanguageInterface::TYPE_CONTENT;
|
||||
$this->assertFalse($this->isLanguageTypeConfigurable($test_type), 'Language type is not configurable.');
|
||||
|
||||
// Editing config.
|
||||
$edit = [$test_type . '[configurable]' => TRUE];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
$this->assertTrue($this->isLanguageTypeConfigurable($test_type), 'Language type is now configurable.');
|
||||
|
||||
// After installing another module, the config should be the same.
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm(['modules[test_module][enable]' => 1], 'Install');
|
||||
$this->assertTrue($this->isLanguageTypeConfigurable($test_type), 'Language type is still configurable.');
|
||||
|
||||
// After uninstalling the other module, the config should be the same.
|
||||
$this->drupalGet('admin/modules/uninstall');
|
||||
$this->submitForm(['uninstall[test_module]' => 1], 'Uninstall');
|
||||
$this->assertTrue($this->isLanguageTypeConfigurable($test_type), 'Language type is still configurable.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given language type is configurable.
|
||||
*
|
||||
* @param string $type
|
||||
* The language type.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the specified language type is configurable, FALSE otherwise.
|
||||
*/
|
||||
protected function isLanguageTypeConfigurable($type): bool {
|
||||
$configurable_types = $this->config('language.types')->get('configurable');
|
||||
return in_array($type, $configurable_types);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the session language negotiation method.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationSessionTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* An administrative user to configure the test environment.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create a new user with permission to manage the languages.
|
||||
$this->adminUser = $this->drupalCreateUser(['administer languages']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language negotiation via query/session parameters.
|
||||
*/
|
||||
public function testSessionLanguageNegotiationMethod(): void {
|
||||
// Enable Session and Selected language for interface language detection.
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$edit = [
|
||||
'language_interface[enabled][language-session]' => 1,
|
||||
'language_interface[enabled][language-selected]' => 1,
|
||||
'language_interface[weight][language-session]' => -6,
|
||||
'language_interface[weight][language-selected]' => 12,
|
||||
];
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Set language via query parameter.
|
||||
$this->drupalGet('user/' . $this->adminUser->id(), ['query' => ['language' => 'fr']]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('Content-language', 'fr');
|
||||
|
||||
// Verify that the language is persisted in the session.
|
||||
$this->drupalGet('user/' . $this->adminUser->id());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('Content-language', 'fr');
|
||||
|
||||
// Set language via query parameter.
|
||||
$this->drupalGet('user/' . $this->adminUser->id(), ['query' => ['language' => 'en']]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('Content-language', 'en');
|
||||
|
||||
// Verify that the language is persisted in the session.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('Content-language', 'en');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationUrlTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'node',
|
||||
'path',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create an Article node type.
|
||||
if ($this->profile != 'standard') {
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
}
|
||||
|
||||
$this->user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
'view the administration theme',
|
||||
'administer nodes',
|
||||
'create article content',
|
||||
'create url aliases',
|
||||
]);
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm(['predefined_langcode' => 'de'], 'Add language');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::processInbound
|
||||
*/
|
||||
public function testDomain(): void {
|
||||
// Check if paths that contain language prefixes can be reached when
|
||||
// language is taken from the domain.
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => 'domain',
|
||||
'prefix[en]' => 'eng',
|
||||
'prefix[de]' => 'de',
|
||||
'domain[en]' => $_SERVER['HTTP_HOST'],
|
||||
'domain[de]' => "de.$_SERVER[HTTP_HOST]",
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
|
||||
$nodeValues = [
|
||||
'title[0][value]' => 'Test',
|
||||
'path[0][alias]' => '/eng/test',
|
||||
];
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->submitForm($nodeValues, 'Save');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Confirm that paths are not changed on monolingual non-English sites.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguagePathMonolingualTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'language', 'path'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create and log in user.
|
||||
$web_user = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
'administer site configuration',
|
||||
]);
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Enable French language.
|
||||
$edit = [];
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Make French the default language.
|
||||
$edit = [
|
||||
'site_default_language' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
|
||||
// Delete English.
|
||||
$this->drupalGet('admin/config/regional/language/delete/en');
|
||||
$this->submitForm([], 'Delete');
|
||||
|
||||
// Changing the default language causes a container rebuild. Therefore need
|
||||
// to rebuild the container in the test environment.
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Verify that French is the only language.
|
||||
$this->container->get('language_manager')->reset();
|
||||
$this->assertFalse(\Drupal::languageManager()->isMultilingual(), 'Site is mono-lingual');
|
||||
$this->assertEquals('fr', \Drupal::languageManager()->getDefaultLanguage()->getId(), 'French is the default language');
|
||||
|
||||
// Set language detection to URL.
|
||||
$edit = ['language_interface[enabled][language-url]' => TRUE];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
$this->drupalPlaceBlock('local_actions_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that links do not have language prefixes in them.
|
||||
*/
|
||||
public function testPageLinks(): void {
|
||||
// Navigate to 'admin/config' path.
|
||||
$this->drupalGet('admin/config');
|
||||
|
||||
// Verify that links in this page do not have a 'fr/' prefix.
|
||||
$this->assertSession()->linkByHrefNotExists('/fr/', 'Links do not contain language prefix');
|
||||
|
||||
// Verify that links in this page can be followed and work.
|
||||
$this->clickLink('Languages');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Add language');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\language\Traits\LanguageTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the content translation settings language selector options.
|
||||
*
|
||||
* @covers \Drupal\language\Form\ContentLanguageSettingsForm
|
||||
* @group language
|
||||
*/
|
||||
class LanguageSelectorTranslatableTest extends BrowserTestBase {
|
||||
|
||||
use LanguageTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'content_translation',
|
||||
'node',
|
||||
'comment',
|
||||
'field_ui',
|
||||
'entity_test',
|
||||
'locale',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The user with administrator privileges.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
public $administrator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create user and set permissions.
|
||||
$this->administrator = $this->drupalCreateUser($this->getAdministratorPermissions(), 'administrator');
|
||||
$this->drupalLogin($this->administrator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of permissions needed for the translator.
|
||||
*/
|
||||
protected function getAdministratorPermissions() {
|
||||
return array_filter(
|
||||
['translate interface',
|
||||
'administer content translation',
|
||||
'create content translations',
|
||||
'update content translations',
|
||||
'delete content translations',
|
||||
'administer languages',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests content translation language selectors are correctly translated.
|
||||
*/
|
||||
public function testLanguageStringSelector(): void {
|
||||
// Add another language.
|
||||
static::createLanguageFromLangcode('es');
|
||||
|
||||
// Translate the string English in Spanish (Inglés). Override config entity.
|
||||
$name_translation = 'Inglés';
|
||||
\Drupal::languageManager()
|
||||
->getLanguageConfigOverride('es', 'language.entity.en')
|
||||
->set('label', $name_translation)
|
||||
->save();
|
||||
|
||||
// Check content translation overview selector.
|
||||
$path = 'es/admin/config/regional/content-language';
|
||||
$this->drupalGet($path);
|
||||
|
||||
// Get en language from selector.
|
||||
$option = $this->assertSession()->optionExists('edit-settings-user-user-settings-language-langcode', 'en');
|
||||
|
||||
// Check that the language text is translated.
|
||||
$this->assertSame($name_translation, $option->getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that correct title is displayed for content translation page.
|
||||
*/
|
||||
public function testContentTranslationPageTitle(): void {
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$this->assertSession()->pageTextContains('Content language and translation');
|
||||
$this->assertSession()->pageTextNotMatches('#Content language$#');
|
||||
|
||||
\Drupal::service('module_installer')->uninstall(['content_translation']);
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$this->assertSession()->pageTextContains('Content language');
|
||||
$this->assertSession()->pageTextNotContains('Content language and translation');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,723 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
// cspell:ignore publi publié
|
||||
|
||||
/**
|
||||
* Functional tests for the language switching feature.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageSwitchingTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'locale',
|
||||
'locale_test',
|
||||
'language',
|
||||
'block',
|
||||
'language_test',
|
||||
'menu_ui',
|
||||
'node',
|
||||
];
|
||||
|
||||
/**
|
||||
* The theme to install as the default for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultTheme = 'starterkit_theme';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create and log in user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer languages',
|
||||
'administer site configuration',
|
||||
'access administration pages',
|
||||
'access content',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional tests for the language switcher block.
|
||||
*/
|
||||
public function testLanguageBlock(): void {
|
||||
// Add language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Set the native language name.
|
||||
$this->saveNativeLanguageName('fr', 'français');
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = ['language_interface[enabled][language-url]' => '1'];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Enable the language switching block.
|
||||
$block = $this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, [
|
||||
'id' => 'test_language_block',
|
||||
// Ensure a 2-byte UTF-8 sequence is in the tested output.
|
||||
'label' => $this->randomMachineName(8) . '×',
|
||||
]);
|
||||
|
||||
$this->doTestLanguageBlockAuthenticated($block->label());
|
||||
$this->doTestHomePageLinks($block->label());
|
||||
$this->doTestLanguageBlockAnonymous($block->label());
|
||||
$this->doTestLanguageBlock404($block->label(), 'system/404');
|
||||
|
||||
// Test 404s with big_pipe where the behavior is different for logged-in
|
||||
// users.
|
||||
\Drupal::service('module_installer')->install(['big_pipe']);
|
||||
$this->rebuildAll();
|
||||
$this->doTestLanguageBlock404($block->label(), 'system/404');
|
||||
$this->drupalLogin($this->drupalCreateUser());
|
||||
// @todo This is testing the current behavior with the big_pipe module
|
||||
// enabled. This behavior is a bug will be fixed in
|
||||
// https://www.drupal.org/project/drupal/issues/3349201.
|
||||
$this->doTestLanguageBlock404($block->label(), '<front>');
|
||||
}
|
||||
|
||||
/**
|
||||
* The home page link should be "/" or "/{language_prefix}".
|
||||
*
|
||||
* @param string $block_label
|
||||
* The label of the language switching block.
|
||||
*
|
||||
* @see self::testLanguageBlock()
|
||||
*/
|
||||
protected function doTestHomePageLinks($block_label): void {
|
||||
// Create a node and set as home page.
|
||||
$this->createHomePage();
|
||||
// Go to home page.
|
||||
$this->DrupalGet('<front>');
|
||||
// The language switcher block should display.
|
||||
$this->assertSession()->pageTextContains($block_label);
|
||||
// Assert that each list item and anchor element has the appropriate data-
|
||||
// attributes.
|
||||
$language_switchers = $this->xpath('//div[@id=:id]/ul/li', [':id' => 'block-test-language-block']);
|
||||
$list_items = [];
|
||||
$anchors = [];
|
||||
$labels = [];
|
||||
foreach ($language_switchers as $list_item) {
|
||||
$list_items[] = [
|
||||
'hreflang' => $list_item->getAttribute('hreflang'),
|
||||
'data-drupal-link-system-path' => $list_item->getAttribute('data-drupal-link-system-path'),
|
||||
];
|
||||
|
||||
$link = $list_item->find('xpath', 'a');
|
||||
$anchors[] = [
|
||||
'hreflang' => $link->getAttribute('hreflang'),
|
||||
'data-drupal-link-system-path' => $link->getAttribute('data-drupal-link-system-path'),
|
||||
'href' => $link->getAttribute('href'),
|
||||
];
|
||||
$labels[] = $link->getText();
|
||||
}
|
||||
$expected_list_items = [
|
||||
0 => [
|
||||
'hreflang' => 'en',
|
||||
'data-drupal-link-system-path' => '<front>',
|
||||
],
|
||||
1 => [
|
||||
'hreflang' => 'fr',
|
||||
'data-drupal-link-system-path' => '<front>',
|
||||
],
|
||||
];
|
||||
$this->assertSame($expected_list_items, $list_items, 'The list items have the correct attributes that will contain the correct home page links.');
|
||||
$expected_anchors = [
|
||||
0 => [
|
||||
'hreflang' => 'en',
|
||||
'data-drupal-link-system-path' => '<front>',
|
||||
'href' => Url::fromRoute('<front>')->toString(),
|
||||
],
|
||||
1 => [
|
||||
'hreflang' => 'fr',
|
||||
'data-drupal-link-system-path' => '<front>',
|
||||
'href' => Url::fromRoute('<front>')->toString() . 'fr',
|
||||
],
|
||||
];
|
||||
$this->assertSame($expected_anchors, $anchors, 'The anchors have the correct attributes that will link to the correct home page in that language.');
|
||||
$this->assertSame(['English', 'français'], $labels, 'The language links labels are in their own language on the language switcher block.');
|
||||
}
|
||||
|
||||
/**
|
||||
* For authenticated users, the "active" class is set by JavaScript.
|
||||
*
|
||||
* @param string $block_label
|
||||
* The label of the language switching block.
|
||||
*
|
||||
* @see self::testLanguageBlock()
|
||||
*/
|
||||
protected function doTestLanguageBlockAuthenticated($block_label): void {
|
||||
// Assert that the language switching block is displayed on the frontpage.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($block_label);
|
||||
|
||||
// Assert that each list item and anchor element has the appropriate data-
|
||||
// attributes.
|
||||
$language_switchers = $this->xpath('//div[@id=:id]/ul/li', [':id' => 'block-test-language-block']);
|
||||
$list_items = [];
|
||||
$anchors = [];
|
||||
$labels = [];
|
||||
foreach ($language_switchers as $list_item) {
|
||||
$list_items[] = [
|
||||
'hreflang' => $list_item->getAttribute('hreflang'),
|
||||
'data-drupal-link-system-path' => $list_item->getAttribute('data-drupal-link-system-path'),
|
||||
];
|
||||
|
||||
$link = $list_item->find('xpath', 'a');
|
||||
$anchors[] = [
|
||||
'hreflang' => $link->getAttribute('hreflang'),
|
||||
'data-drupal-link-system-path' => $link->getAttribute('data-drupal-link-system-path'),
|
||||
];
|
||||
$labels[] = $link->getText();
|
||||
}
|
||||
$expected_list_items = [
|
||||
0 => ['hreflang' => 'en', 'data-drupal-link-system-path' => 'user/2'],
|
||||
1 => ['hreflang' => 'fr', 'data-drupal-link-system-path' => 'user/2'],
|
||||
];
|
||||
$this->assertSame($expected_list_items, $list_items, 'The list items have the correct attributes that will allow the drupal.active-link library to mark them as active.');
|
||||
$expected_anchors = [
|
||||
0 => ['hreflang' => 'en', 'data-drupal-link-system-path' => 'user/2'],
|
||||
1 => ['hreflang' => 'fr', 'data-drupal-link-system-path' => 'user/2'],
|
||||
];
|
||||
$this->assertSame($expected_anchors, $anchors, 'The anchors have the correct attributes that will allow the drupal.active-link library to mark them as active.');
|
||||
$settings = $this->getDrupalSettings();
|
||||
$this->assertSame('user/2', $settings['path']['currentPath'], 'drupalSettings.path.currentPath is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertFalse($settings['path']['isFront'], 'drupalSettings.path.isFront is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertSame('en', $settings['path']['currentLanguage'], 'drupalSettings.path.currentLanguage is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertSame(['English', 'français'], $labels, 'The language links labels are in their own language on the language switcher block.');
|
||||
}
|
||||
|
||||
/**
|
||||
* For anonymous users, the "active" class is set by PHP.
|
||||
*
|
||||
* @param string $block_label
|
||||
* The label of the language switching block.
|
||||
*
|
||||
* @see self::testLanguageBlock()
|
||||
*/
|
||||
protected function doTestLanguageBlockAnonymous($block_label): void {
|
||||
$this->drupalLogout();
|
||||
|
||||
// Assert that the language switching block is displayed on the frontpage
|
||||
// and ensure that the active class is added when query params are present.
|
||||
$this->drupalGet('', ['query' => ['foo' => 'bar']]);
|
||||
$this->assertSession()->pageTextContains($block_label);
|
||||
|
||||
// Assert that only the current language is marked as active.
|
||||
$language_switchers = $this->xpath('//div[@id=:id]/ul/li', [':id' => 'block-test-language-block']);
|
||||
$links = [
|
||||
'active' => [],
|
||||
'inactive' => [],
|
||||
];
|
||||
$anchors = [
|
||||
'active' => [],
|
||||
'inactive' => [],
|
||||
];
|
||||
$labels = [];
|
||||
foreach ($language_switchers as $list_item) {
|
||||
$langcode = $list_item->getAttribute('hreflang');
|
||||
if ($list_item->hasClass('is-active')) {
|
||||
$links['active'][] = $langcode;
|
||||
}
|
||||
else {
|
||||
$links['inactive'][] = $langcode;
|
||||
}
|
||||
|
||||
$link = $list_item->find('xpath', 'a');
|
||||
$anchor_classes = explode(" ", $link->getAttribute('class'));
|
||||
if (in_array('is-active', $anchor_classes)) {
|
||||
$anchors['active'][] = $langcode;
|
||||
}
|
||||
else {
|
||||
$anchors['inactive'][] = $langcode;
|
||||
}
|
||||
$labels[] = $link->getText();
|
||||
}
|
||||
$this->assertSame(['active' => ['en'], 'inactive' => ['fr']], $links, 'Only the current language list item is marked as active on the language switcher block.');
|
||||
$this->assertSame(['active' => ['en'], 'inactive' => ['fr']], $anchors, 'Only the current language anchor is marked as active on the language switcher block.');
|
||||
$this->assertSame(['English', 'français'], $labels, 'The language links labels are in their own language on the language switcher block.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the language switcher block on 404 pages.
|
||||
*
|
||||
* @param string $block_label
|
||||
* The label of the language switching block.
|
||||
* @param string $system_path
|
||||
* The expected system path for the links in the language switcher.
|
||||
*
|
||||
* @see self::testLanguageBlock()
|
||||
*/
|
||||
protected function doTestLanguageBlock404(string $block_label, string $system_path): void {
|
||||
$this->drupalGet('does-not-exist-' . $this->randomMachineName());
|
||||
$this->assertSession()->pageTextContains($block_label);
|
||||
|
||||
// Assert that each list item and anchor element has the appropriate data-
|
||||
// attributes.
|
||||
$language_switchers = $this->xpath('//div[@id=:id]/ul/li', [':id' => 'block-test-language-block']);
|
||||
$list_items = [];
|
||||
$anchors = [];
|
||||
$labels = [];
|
||||
foreach ($language_switchers as $list_item) {
|
||||
$list_items[] = [
|
||||
'hreflang' => $list_item->getAttribute('hreflang'),
|
||||
'data-drupal-link-system-path' => $list_item->getAttribute('data-drupal-link-system-path'),
|
||||
];
|
||||
|
||||
$link = $list_item->find('xpath', 'a');
|
||||
$anchors[] = [
|
||||
'hreflang' => $link->getAttribute('hreflang'),
|
||||
'data-drupal-link-system-path' => $link->getAttribute('data-drupal-link-system-path'),
|
||||
];
|
||||
$labels[] = $link->getText();
|
||||
}
|
||||
$expected_list_items = [
|
||||
0 => ['hreflang' => 'en', 'data-drupal-link-system-path' => $system_path],
|
||||
1 => ['hreflang' => 'fr', 'data-drupal-link-system-path' => $system_path],
|
||||
];
|
||||
$this->assertSame($expected_list_items, $list_items, 'The list items have the correct attributes that will allow the drupal.active-link library to mark them as active.');
|
||||
$expected_anchors = [
|
||||
0 => ['hreflang' => 'en', 'data-drupal-link-system-path' => $system_path],
|
||||
1 => ['hreflang' => 'fr', 'data-drupal-link-system-path' => $system_path],
|
||||
];
|
||||
$this->assertSame($expected_anchors, $anchors, 'The anchors have the correct attributes that will allow the drupal.active-link library to mark them as active.');
|
||||
$this->assertSame(['English', 'français'], $labels, 'The language links labels are in their own language on the language switcher block.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language switcher links for domain based negotiation.
|
||||
*/
|
||||
public function testLanguageBlockWithDomain(): void {
|
||||
// Add the Italian language.
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
|
||||
// Rebuild the container so that the new language is picked up by services
|
||||
// that hold a list of languages.
|
||||
$this->rebuildContainer();
|
||||
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
|
||||
// Enable browser and URL language detection.
|
||||
$edit = [
|
||||
'language_interface[enabled][language-url]' => TRUE,
|
||||
'language_interface[weight][language-url]' => -10,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Do not allow blank domain.
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domain[en]' => '',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('The domain may not be left blank for English', 'error');
|
||||
|
||||
// Change the domain for the Italian language.
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domain[en]' => \Drupal::request()->getHost(),
|
||||
'domain[it]' => 'it.example.com',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('The configuration options have been saved', 'status');
|
||||
|
||||
// Enable the language switcher block.
|
||||
$this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, ['id' => 'test_language_block']);
|
||||
|
||||
$this->drupalGet('');
|
||||
|
||||
/** @var \Drupal\Core\Routing\UrlGenerator $generator */
|
||||
$generator = $this->container->get('url_generator');
|
||||
|
||||
// Verify the English URL is correct
|
||||
$english_url = $generator->generateFromRoute('entity.user.canonical', ['user' => 2], ['language' => $languages['en']]);
|
||||
$this->assertSession()->elementAttributeContains('xpath', '//div[@id="block-test-language-block"]/ul/li/a[@hreflang="en"]', 'href', $english_url);
|
||||
|
||||
// Verify the Italian URL is correct
|
||||
$italian_url = $generator->generateFromRoute('entity.user.canonical', ['user' => 2], ['language' => $languages['it']]);
|
||||
$this->assertSession()->elementAttributeContains('xpath', '//div[@id="block-test-language-block"]/ul/li/a[@hreflang="it"]', 'href', $italian_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests active class on links when switching languages.
|
||||
*/
|
||||
public function testLanguageLinkActiveClass(): void {
|
||||
// Add language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = ['language_interface[enabled][language-url]' => '1'];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
$this->doTestLanguageLinkActiveClassAuthenticated();
|
||||
$this->doTestLanguageLinkActiveClassAnonymous();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the path-admin class, as same as on default language.
|
||||
*/
|
||||
public function testLanguageBodyClass(): void {
|
||||
// Add language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = ['language_interface[enabled][language-url]' => '1'];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Check if the default (English) admin/config page has the right class.
|
||||
$this->drupalGet('admin/config');
|
||||
$this->assertSession()->elementAttributeContains('xpath', '//body', 'class', 'path-admin');
|
||||
|
||||
// Check if the French admin/config page has the right class.
|
||||
$this->drupalGet('fr/admin/config');
|
||||
$this->assertSession()->elementAttributeContains('xpath', '//body', 'class', 'path-admin');
|
||||
|
||||
// The testing profile sets the user/login page as the frontpage. That
|
||||
// redirects authenticated users to their profile page, so check with an
|
||||
// anonymous user instead.
|
||||
$this->drupalLogout();
|
||||
|
||||
// Check if the default (English) frontpage has the right class.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->elementAttributeContains('xpath', '//body', 'class', 'path-frontpage');
|
||||
|
||||
// Check if the French frontpage has the right class.
|
||||
$this->drupalGet('fr');
|
||||
$this->assertSession()->elementAttributeContains('xpath', '//body', 'class', 'path-frontpage');
|
||||
}
|
||||
|
||||
/**
|
||||
* For authenticated users, the "active" class is set by JavaScript.
|
||||
*
|
||||
* @see self::testLanguageLinkActiveClass()
|
||||
*/
|
||||
protected function doTestLanguageLinkActiveClassAuthenticated(): void {
|
||||
$path = 'language_test/type-link-active-class';
|
||||
|
||||
// Test links generated by the link generator on an English page.
|
||||
$this->drupalGet($path);
|
||||
|
||||
// Language code 'none' link should be active.
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'no_lang_link'], 'data-drupal-link-system-path', $path);
|
||||
|
||||
// Language code 'en' link should be active.
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'en_link'], 'hreflang', 'en');
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'en_link'], 'data-drupal-link-system-path', $path);
|
||||
|
||||
// Language code 'fr' link should not be active.
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'fr_link'], 'hreflang', 'fr');
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'fr_link'], 'data-drupal-link-system-path', $path);
|
||||
|
||||
// Verify that drupalSettings contains the correct values.
|
||||
$settings = $this->getDrupalSettings();
|
||||
$this->assertSame($path, $settings['path']['currentPath'], 'drupalSettings.path.currentPath is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertFalse($settings['path']['isFront'], 'drupalSettings.path.isFront is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertSame('en', $settings['path']['currentLanguage'], 'drupalSettings.path.currentLanguage is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
|
||||
// Test links generated by the link generator on a French page.
|
||||
$this->drupalGet('fr/language_test/type-link-active-class');
|
||||
|
||||
// Language code 'none' link should be active.
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'no_lang_link'], 'data-drupal-link-system-path', $path);
|
||||
|
||||
// Language code 'en' link should not be active.
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'en_link'], 'hreflang', 'en');
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'en_link'], 'data-drupal-link-system-path', $path);
|
||||
|
||||
// Language code 'fr' link should be active.
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'fr_link'], 'hreflang', 'fr');
|
||||
$this->assertSession()->elementAttributeContains('named', ['id', 'fr_link'], 'data-drupal-link-system-path', $path);
|
||||
|
||||
// Verify that drupalSettings contains the correct values.
|
||||
$settings = $this->getDrupalSettings();
|
||||
$this->assertSame($path, $settings['path']['currentPath'], 'drupalSettings.path.currentPath is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertFalse($settings['path']['isFront'], 'drupalSettings.path.isFront is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
$this->assertSame('fr', $settings['path']['currentLanguage'], 'drupalSettings.path.currentLanguage is set correctly to allow drupal.active-link to mark the correct links as active.');
|
||||
}
|
||||
|
||||
/**
|
||||
* For anonymous users, the "active" class is set by PHP.
|
||||
*
|
||||
* @see self::testLanguageLinkActiveClass()
|
||||
*/
|
||||
protected function doTestLanguageLinkActiveClassAnonymous(): void {
|
||||
$this->drupalLogout();
|
||||
|
||||
// Test links generated by the link generator on an English page.
|
||||
$this->drupalGet('language_test/type-link-active-class');
|
||||
|
||||
// Language code 'none' link should be active.
|
||||
$this->assertSession()->elementExists('xpath', "//a[@id = 'no_lang_link' and contains(@class, 'is-active')]");
|
||||
|
||||
// Language code 'en' link should be active.
|
||||
$this->assertSession()->elementExists('xpath', "//a[@id = 'en_link' and contains(@class, 'is-active')]");
|
||||
|
||||
// Language code 'fr' link should not be active.
|
||||
$this->assertSession()->elementExists('xpath', "//a[@id = 'fr_link' and not(contains(@class, 'is-active'))]");
|
||||
|
||||
// Test links generated by the link generator on a French page.
|
||||
$this->drupalGet('fr/language_test/type-link-active-class');
|
||||
|
||||
// Language code 'none' link should be active.
|
||||
$this->assertSession()->elementExists('xpath', "//a[@id = 'no_lang_link' and contains(@class, 'is-active')]");
|
||||
|
||||
// Language code 'en' link should not be active.
|
||||
$this->assertSession()->elementExists('xpath', "//a[@id = 'en_link' and not(contains(@class, 'is-active'))]");
|
||||
|
||||
// Language code 'fr' link should be active.
|
||||
$this->assertSession()->elementExists('xpath', "//a[@id = 'fr_link' and contains(@class, 'is-active')]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language switcher links for session based negotiation.
|
||||
*/
|
||||
public function testLanguageSessionSwitchLinks(): void {
|
||||
// Add language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Enable session language detection and selection.
|
||||
$edit = [
|
||||
'language_interface[enabled][language-url]' => FALSE,
|
||||
'language_interface[enabled][language-session]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Enable the language switching block.
|
||||
$this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, [
|
||||
'id' => 'test_language_block',
|
||||
]);
|
||||
|
||||
// Enable the main menu block.
|
||||
$this->drupalPlaceBlock('system_menu_block:main', [
|
||||
'id' => 'test_menu',
|
||||
]);
|
||||
|
||||
// Add a link to the homepage.
|
||||
$link = MenuLinkContent::create([
|
||||
'title' => 'Home',
|
||||
'menu_name' => 'main',
|
||||
'bundle' => 'menu_link_content',
|
||||
'link' => [['uri' => 'entity:user/2']],
|
||||
]);
|
||||
$link->save();
|
||||
|
||||
// Go to the homepage.
|
||||
$this->drupalGet('');
|
||||
// Click on the French link.
|
||||
$this->clickLink('French');
|
||||
// There should be a query parameter to set the session language.
|
||||
$this->assertSession()->addressEquals('user/2?language=fr');
|
||||
// Click on the 'Home' Link.
|
||||
$this->clickLink('Home');
|
||||
// There should be no query parameter.
|
||||
$this->assertSession()->addressEquals('user/2');
|
||||
// Click on the French link.
|
||||
$this->clickLink('French');
|
||||
// There should be no query parameter.
|
||||
$this->assertSession()->addressEquals('user/2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the language switching block does not expose restricted paths.
|
||||
*/
|
||||
public function testRestrictedPaths(): void {
|
||||
$entity_type_manager = \Drupal::entityTypeManager();
|
||||
|
||||
// Add the French language.
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$this->config('language.types')
|
||||
->set('negotiation.language_interface.enabled.language-url', 1)
|
||||
->save();
|
||||
|
||||
// Enable the language switching block.
|
||||
$block = $this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE);
|
||||
|
||||
// Create a node type and make it translatable.
|
||||
$entity_type_manager->getStorage('node_type')
|
||||
->create([
|
||||
'type' => 'page',
|
||||
'name' => 'Page',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a published node with an unpublished translation.
|
||||
$node = $entity_type_manager->getStorage('node')
|
||||
->create([
|
||||
'type' => 'page',
|
||||
'title' => $this->randomMachineName(),
|
||||
'status' => 1,
|
||||
]);
|
||||
$node->save();
|
||||
$node->addTranslation('fr', ['title' => 'Non publié', 'status' => 0]);
|
||||
$node->save();
|
||||
|
||||
// Create path aliases.
|
||||
$alias_storage = $entity_type_manager->getStorage('path_alias');
|
||||
$alias_storage->create([
|
||||
'path' => '/user/1',
|
||||
'alias' => '/secret-identity/peter-parker',
|
||||
])->save();
|
||||
$alias_storage->create([
|
||||
'path' => '/node/1',
|
||||
'langcode' => 'en',
|
||||
'alias' => '/press-release/published-report',
|
||||
])->save();
|
||||
$alias_storage->create([
|
||||
'path' => '/node/1',
|
||||
'langcode' => 'fr',
|
||||
'alias' => '/press-release/rapport-non-publié',
|
||||
])->save();
|
||||
|
||||
// Visit a restricted user page.
|
||||
// Assert that the language switching block is displayed on the
|
||||
// access-denied page, but it does not contain the path alias.
|
||||
$this->assertLinkMarkup('/user/1', 403, $block->label(), 'peter-parker');
|
||||
|
||||
// Visit the node and its translation. Use internal paths and aliases. The
|
||||
// non-ASCII character may be escaped, so remove it from the search string.
|
||||
$this->assertLinkMarkup('/node/1', 200, $block->label(), 'rapport-non-publi');
|
||||
$this->assertLinkMarkup('/press-release/published-report', 200, $block->label(), 'rapport-non-publi');
|
||||
$this->assertLinkMarkup('/fr/node/1', 403, $block->label(), 'rapport-non-publi');
|
||||
$this->assertLinkMarkup('/fr/press-release/rapport-non-publié', 403, $block->label(), 'rapport-non-publi');
|
||||
|
||||
// Test as a user with access to other users and unpublished content.
|
||||
$privileged_user = $this->drupalCreateUser([
|
||||
'access user profiles',
|
||||
'bypass node access',
|
||||
]);
|
||||
$this->drupalLogin($privileged_user);
|
||||
$this->assertLinkMarkup('/user/1', 200, $block->label(), 'peter-parker', TRUE);
|
||||
$this->assertLinkMarkup('/node/1', 200, $block->label(), 'rapport-non-publi', TRUE);
|
||||
$this->assertLinkMarkup('/press-release/published-report', 200, $block->label(), 'rapport-non-publi', TRUE);
|
||||
$this->assertLinkMarkup('/fr/node/1', 200, $block->label(), 'rapport-non-publi', TRUE);
|
||||
$this->assertLinkMarkup('/fr/press-release/rapport-non-publié', 200, $block->label(), 'rapport-non-publi', TRUE);
|
||||
|
||||
// Test as an anonymous user.
|
||||
$this->drupalLogout();
|
||||
$this->assertLinkMarkup('/user/1', 403, $block->label(), 'peter-parker');
|
||||
$this->assertLinkMarkup('/node/1', 200, $block->label(), 'rapport-non-publi');
|
||||
$this->assertLinkMarkup('/press-release/published-report', 200, $block->label(), 'rapport-non-publi');
|
||||
$this->assertLinkMarkup('/fr/node/1', 403, $block->label(), 'rapport-non-publi');
|
||||
$this->assertLinkMarkup('/fr/press-release/rapport-non-publié', 403, $block->label(), 'rapport-non-publi');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that restricted text is or is not present in the page response.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to test.
|
||||
* @param int $status
|
||||
* The HTTP status code, such as 200 or 403.
|
||||
* @param string $marker
|
||||
* Text that should always be present.
|
||||
* @param string $restricted
|
||||
* Text that should be tested.
|
||||
* @param bool $found
|
||||
* (optional) If TRUE, then the restricted text is present. Defaults to
|
||||
* FALSE.
|
||||
*/
|
||||
protected function assertLinkMarkup(string $path, int $status, string $marker, string $restricted, bool $found = FALSE): void {
|
||||
$this->drupalGet($path);
|
||||
$this->assertSession()->statusCodeEquals($status);
|
||||
$this->assertSession()->pageTextContains($marker);
|
||||
if ($found) {
|
||||
$this->assertSession()->responseContains($restricted);
|
||||
}
|
||||
else {
|
||||
$this->assertSession()->responseNotContains($restricted);
|
||||
}
|
||||
|
||||
// Assert that all languages had a link passed to
|
||||
// hook_language_switch_links_alter() to allow alternatives to be provided.
|
||||
$languages = \Drupal::languageManager()->getNativeLanguages();
|
||||
$links_for_alter = \Drupal::state()->get('language_test.language_switch_link_ids');
|
||||
$this->assertSame(array_keys($languages), $links_for_alter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the native name of a language entity in configuration as a label.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code of the language.
|
||||
* @param string $label
|
||||
* The native name of the language.
|
||||
*/
|
||||
protected function saveNativeLanguageName($langcode, $label): void {
|
||||
\Drupal::service('language.config_factory_override')
|
||||
->getOverride($langcode, 'language.entity.' . $langcode)->set('label', $label)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a node and set it as the home pages.
|
||||
*/
|
||||
protected function createHomePage(): void {
|
||||
$entity_type_manager = \Drupal::entityTypeManager();
|
||||
|
||||
// Create a node type and make it translatable.
|
||||
$entity_type_manager->getStorage('node_type')
|
||||
->create([
|
||||
'type' => 'page',
|
||||
'name' => 'Page',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a published node.
|
||||
$node = $entity_type_manager->getStorage('node')
|
||||
->create([
|
||||
'type' => 'page',
|
||||
'title' => $this->randomMachineName(),
|
||||
'status' => 1,
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
// Change the front page to /node/1.
|
||||
$edit = ['site_frontpage' => '/node/1'];
|
||||
$this->drupalGet('admin/config/system/site-information');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,629 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\file\Entity\File;
|
||||
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\Tests\BrowserTestBase;
|
||||
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
|
||||
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Drupal\language\LanguageNegotiatorInterface;
|
||||
use Drupal\block\Entity\Block;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
|
||||
/**
|
||||
* Tests the language UI for language switching.
|
||||
*
|
||||
* The uses cases that get tested, are:
|
||||
* - URL (path) > default: Test that the URL prefix setting gets precedence over
|
||||
* the default language. The browser language preference does not have any
|
||||
* influence.
|
||||
* - URL (path) > browser > default: Test that the URL prefix setting gets
|
||||
* precedence over the browser language preference, which in turn gets
|
||||
* precedence over the default language.
|
||||
* - URL (domain) > default: Tests that the URL domain setting gets precedence
|
||||
* over the default language.
|
||||
*
|
||||
* The paths that are used for each of these, are:
|
||||
* - admin/config: Tests the UI using the precedence rules.
|
||||
* - zh-hans/admin/config: Tests the UI in Chinese.
|
||||
* - blah-blah/admin/config: Tests the 404 page.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageUILanguageNegotiationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $configSchemaCheckerExclusions = [
|
||||
// Necessary to allow setting `selected_langcode` to NULL.
|
||||
// @see testUILanguageNegotiation()
|
||||
'language.negotiation',
|
||||
];
|
||||
|
||||
/**
|
||||
* The admin user for testing.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* We marginally use interface translation functionality here, so need to use
|
||||
* the locale module instead of language only, but the 90% of the test is
|
||||
* about the negotiation process which is solely in language module.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $modules = [
|
||||
'locale',
|
||||
'language_test',
|
||||
'block',
|
||||
'user',
|
||||
'content_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'translate interface',
|
||||
'access administration pages',
|
||||
'administer blocks',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for language switching by URL path.
|
||||
*/
|
||||
public function testUILanguageNegotiation(): void {
|
||||
// A few languages to switch to.
|
||||
// This one is unknown, should get the default lang version.
|
||||
$langcode_unknown = 'blah-blah';
|
||||
// For testing browser lang preference.
|
||||
$langcode_browser_fallback = 'vi';
|
||||
// For testing path prefix.
|
||||
$langcode = 'zh-hans';
|
||||
// For setting browser language preference to 'vi'.
|
||||
$http_header_browser_fallback = ["Accept-Language" => "$langcode_browser_fallback;q=1"];
|
||||
// For setting browser language preference to some unknown.
|
||||
$http_header_blah = ["Accept-Language" => "blah;q=1"];
|
||||
|
||||
// Create a private file for testing accessible by the admin user.
|
||||
\Drupal::service('file_system')->mkdir($this->privateFilesDirectory . '/test');
|
||||
$filepath = 'private://test/private-file-test.txt';
|
||||
$contents = "file_put_contents() doesn't seem to appreciate empty strings so let's put in some data.";
|
||||
file_put_contents($filepath, $contents);
|
||||
$file = File::create([
|
||||
'uri' => $filepath,
|
||||
'uid' => $this->adminUser->id(),
|
||||
]);
|
||||
$file->save();
|
||||
|
||||
// Setup the site languages by installing two languages.
|
||||
// Set the default language in order for the translated string to be
|
||||
// registered into database when seen by t(). Without doing this, our target
|
||||
// string is for some reason not found when doing translate search. This
|
||||
// might be some bug.
|
||||
$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();
|
||||
|
||||
// We will look for this string in the admin/config screen to see if the
|
||||
// corresponding translated string is shown.
|
||||
$default_string = 'Hide descriptions';
|
||||
|
||||
// First visit this page to make sure our target string is searchable.
|
||||
$this->drupalGet('admin/config');
|
||||
|
||||
// Now the t()'ed string is in db so switch the language back to default.
|
||||
// This will rebuild the container so we need to rebuild the container in
|
||||
// the test environment.
|
||||
$this->config('system.site')->set('default_langcode', $default_language->getId())->save();
|
||||
$this->config('language.negotiation')->set('url.prefixes.en', '')->save();
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Translate the string.
|
||||
$language_browser_fallback_string = "In $langcode_browser_fallback In $langcode_browser_fallback In $langcode_browser_fallback";
|
||||
$language_string = "In $langcode In $langcode In $langcode";
|
||||
// Do a translate search of our target string.
|
||||
$search = [
|
||||
'string' => $default_string,
|
||||
'langcode' => $langcode_browser_fallback,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/translate');
|
||||
$this->submitForm($search, 'Filter');
|
||||
$textarea = $this->assertSession()->elementExists('xpath', '//textarea');
|
||||
$lid = $textarea->getAttribute('name');
|
||||
$edit = [
|
||||
$lid => $language_browser_fallback_string,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/translate');
|
||||
$this->submitForm($edit, 'Save translations');
|
||||
|
||||
$search = [
|
||||
'string' => $default_string,
|
||||
'langcode' => $langcode,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/translate');
|
||||
$this->submitForm($search, 'Filter');
|
||||
$textarea = $this->assertSession()->elementExists('xpath', '//textarea');
|
||||
$lid = $textarea->getAttribute('name');
|
||||
$edit = [
|
||||
$lid => $language_string,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/translate');
|
||||
$this->submitForm($edit, 'Save translations');
|
||||
|
||||
// Configure selected language negotiation to use zh-hans.
|
||||
$edit = ['selected_langcode' => $langcode];
|
||||
$this->drupalGet('admin/config/regional/language/detection/selected');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$test = [
|
||||
'language_negotiation' => [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->doRunTest($test);
|
||||
|
||||
// An invalid language is selected.
|
||||
$this->config('language.negotiation')->set('selected_langcode', NULL)->save();
|
||||
$test = [
|
||||
'language_negotiation' => [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->doRunTest($test);
|
||||
|
||||
// No selected language is available.
|
||||
$this->config('language.negotiation')->set('selected_langcode', $langcode_unknown)->save();
|
||||
$test = [
|
||||
'language_negotiation' => [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->doRunTest($test);
|
||||
|
||||
$tests = [
|
||||
// Default, browser preference should have no influence.
|
||||
[
|
||||
'language_negotiation' => [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.',
|
||||
],
|
||||
// Language prefix.
|
||||
[
|
||||
'language_negotiation' => [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',
|
||||
],
|
||||
// Default, go by browser preference.
|
||||
[
|
||||
'language_negotiation' => [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',
|
||||
],
|
||||
// Prefix, switch to the language.
|
||||
[
|
||||
'language_negotiation' => [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',
|
||||
],
|
||||
// Default, browser language preference is not one of site's lang.
|
||||
[
|
||||
'language_negotiation' => [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->doRunTest($test);
|
||||
}
|
||||
|
||||
// Unknown language prefix should return 404.
|
||||
$definitions = \Drupal::languageManager()->getNegotiator()->getNegotiationMethods();
|
||||
// Enable only methods, which are either not limited to a specific language
|
||||
// type or are supporting the interface language type.
|
||||
$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", [], $http_header_browser_fallback);
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
|
||||
// Set preferred langcode for user to NULL.
|
||||
$account = $this->loggedInUser;
|
||||
$account->preferred_langcode = NULL;
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID],
|
||||
'path' => 'admin/config',
|
||||
'expect' => $default_string,
|
||||
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER > DEFAULT: no preferred user language setting, the UI language is default',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Set preferred langcode for user to default langcode.
|
||||
$account = $this->loggedInUser;
|
||||
$account->preferred_langcode = $default_language->getId();
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUser::METHOD_ID, LanguageNegotiationUrl::METHOD_ID],
|
||||
'path' => "$langcode/admin/config",
|
||||
'expect' => $default_string,
|
||||
'expected_method_id' => LanguageNegotiationUser::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER > URL: User has default language as preferred user language setting, the UI language is default',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Set preferred langcode for user to unknown language.
|
||||
$account = $this->loggedInUser;
|
||||
$account->preferred_langcode = $langcode_unknown;
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID],
|
||||
'path' => 'admin/config',
|
||||
'expect' => $default_string,
|
||||
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER > DEFAULT: invalid preferred user language setting, the UI language is default',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Set preferred langcode for user to non default.
|
||||
$account->preferred_langcode = $langcode;
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID],
|
||||
'path' => 'admin/config',
|
||||
'expect' => $language_string,
|
||||
'expected_method_id' => LanguageNegotiationUser::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER > DEFAULT: defined preferred user language setting, the UI language is based on user setting',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Set preferred admin langcode for user to NULL.
|
||||
$account->preferred_admin_langcode = NULL;
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUserAdmin::METHOD_ID, LanguageNegotiationSelected::METHOD_ID],
|
||||
'path' => 'admin/config',
|
||||
'expect' => $default_string,
|
||||
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER ADMIN > DEFAULT: no preferred user admin language setting, the UI language is default',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Set preferred admin langcode for user to unknown language.
|
||||
$account->preferred_admin_langcode = $langcode_unknown;
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUserAdmin::METHOD_ID, LanguageNegotiationSelected::METHOD_ID],
|
||||
'path' => 'admin/config',
|
||||
'expect' => $default_string,
|
||||
'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER ADMIN > DEFAULT: invalid preferred user admin language setting, the UI language is default',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Set preferred admin langcode for user to non default.
|
||||
$account->preferred_admin_langcode = $langcode;
|
||||
$account->save();
|
||||
|
||||
$test = [
|
||||
'language_negotiation' => [LanguageNegotiationUserAdmin::METHOD_ID, LanguageNegotiationSelected::METHOD_ID],
|
||||
'path' => 'admin/config',
|
||||
'expect' => $language_string,
|
||||
'expected_method_id' => LanguageNegotiationUserAdmin::METHOD_ID,
|
||||
'http_header' => [],
|
||||
'message' => 'USER ADMIN > DEFAULT: defined preferred user admin language setting, the UI language is based on user setting',
|
||||
];
|
||||
$this->doRunTest($test);
|
||||
|
||||
// Go by session preference.
|
||||
$language_negotiation_session_param = $this->randomMachineName();
|
||||
$edit = ['language_negotiation_session_param' => $language_negotiation_session_param];
|
||||
$this->drupalGet('admin/config/regional/language/detection/session');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$tests = [
|
||||
[
|
||||
'language_negotiation' => [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',
|
||||
],
|
||||
[
|
||||
'language_negotiation' => [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->doRunTest($test);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs common tests for the language user interface.
|
||||
*/
|
||||
protected function doRunTest($test): void {
|
||||
$test += ['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->assertSession()->pageTextContains($test['expect']);
|
||||
$this->assertSession()->statusMessageContains('Language negotiation method: ' . $test['expected_method_id'], 'status');
|
||||
|
||||
// Get the private file and ensure it is a 200. It is important to
|
||||
// invalidate the router cache to ensure the routing system runs a full
|
||||
// match.
|
||||
Cache::invalidateTags(['route_match']);
|
||||
$this->drupalGet('system/files/test/private-file-test.txt');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests URL language detection when the requested URL has no language.
|
||||
*/
|
||||
public function testUrlLanguageFallback(): void {
|
||||
// Add the Italian language.
|
||||
$langcode_browser_fallback = 'it';
|
||||
ConfigurableLanguage::createFromLangcode($langcode_browser_fallback)->save();
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
|
||||
// Enable the path prefix for the default language: this way any unprefixed
|
||||
// URL must have a valid fallback value.
|
||||
$edit = ['prefix[en]' => 'en'];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
|
||||
// Enable browser and URL language detection.
|
||||
$edit = [
|
||||
'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->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
|
||||
// Enable the language switcher block.
|
||||
$this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, ['id' => 'test_language_block']);
|
||||
|
||||
// Log out, because for anonymous users, the "active" class is set by PHP
|
||||
// (which means we can easily test it here), whereas for authenticated users
|
||||
// it is set by JavaScript.
|
||||
$this->drupalLogout();
|
||||
|
||||
// Place a site branding block in the header region.
|
||||
$this->drupalPlaceBlock('system_branding_block', [
|
||||
'region' => 'header',
|
||||
'id' => 'site_branding',
|
||||
]);
|
||||
|
||||
// Access the front page without specifying any valid URL language prefix
|
||||
// and having as browser language preference a non-default language.
|
||||
$http_header = ["Accept-Language" => "$langcode_browser_fallback;q=1"];
|
||||
$language = new Language(['id' => '']);
|
||||
$this->drupalGet('', ['language' => $language], $http_header);
|
||||
|
||||
// Check that the language switcher active link matches the given browser
|
||||
// language.
|
||||
$href = Url::fromRoute('<front>')->toString() . $langcode_browser_fallback;
|
||||
$this->assertSession()->elementTextEquals('xpath', "//div[@id='block-test-language-block']//a[@class='language-link is-active' and starts-with(@href, '$href')]", $languages[$langcode_browser_fallback]->getName());
|
||||
|
||||
// Check that URLs are rewritten using the given browser language.
|
||||
$this->assertSession()->elementTextEquals('xpath', "//div[@id='block-site-branding']/a[@rel='home' and @href='$href'][2]", 'Drupal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests URL handling when separate domains are used for multiple languages.
|
||||
*/
|
||||
public function testLanguageDomain(): void {
|
||||
global $base_url;
|
||||
|
||||
// Get the current host URI we're running on.
|
||||
$base_url_host = parse_url($base_url, PHP_URL_HOST);
|
||||
|
||||
// Add the Italian language.
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
|
||||
// Enable browser and URL language detection.
|
||||
$edit = [
|
||||
'language_interface[enabled][language-url]' => TRUE,
|
||||
'language_interface[weight][language-url]' => -10,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Do not allow blank domain.
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domain[en]' => '',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('The domain may not be left blank for English', 'error');
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Change the domain for the Italian language.
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domain[en]' => $base_url_host,
|
||||
'domain[it]' => 'it.example.com',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains('The configuration options have been saved', 'status');
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Try to use an invalid domain.
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domain[en]' => $base_url_host,
|
||||
'domain[it]' => 'it.example.com/',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->assertSession()->statusMessageContains("The domain for Italian may only contain the domain name, not a trailing slash, protocol and/or port.", 'error');
|
||||
|
||||
// Build the link we're going to test.
|
||||
$link = 'it.example.com' . rtrim(base_path(), '/') . '/admin';
|
||||
|
||||
// Test URL in another language: http://it.example.com/admin.
|
||||
// Base path gives problems on the testbot, so $correct_link is hard-coded.
|
||||
// @see UrlAlterFunctionalTest::assertUrlOutboundAlter (path.test).
|
||||
$italian_url = Url::fromRoute('system.admin', [], ['language' => $languages['it']])->toString();
|
||||
$url_scheme = \Drupal::request()->isSecure() ? 'https://' : 'http://';
|
||||
$correct_link = $url_scheme . $link;
|
||||
$this->assertEquals($correct_link, $italian_url, "The right URL ($italian_url) in accordance with the chosen language");
|
||||
|
||||
// Test HTTPS via options.
|
||||
$italian_url = Url::fromRoute('system.admin', [], ['https' => TRUE, 'language' => $languages['it']])->toString();
|
||||
$correct_link = 'https://' . $link;
|
||||
$this->assertSame($correct_link, $italian_url, "The right HTTPS URL (via options) ($italian_url) in accordance with the chosen language");
|
||||
|
||||
// Test HTTPS via current URL scheme.
|
||||
$request = Request::create('', 'GET', [], [], [], ['HTTPS' => 'on']);
|
||||
$request->setSession(new Session(new MockArraySessionStorage()));
|
||||
$this->container->get('request_stack')->push($request);
|
||||
$italian_url = Url::fromRoute('system.admin', [], ['language' => $languages['it']])->toString();
|
||||
$correct_link = 'https://' . $link;
|
||||
$this->assertSame($correct_link, $italian_url, "The right URL (via current URL scheme) ($italian_url) in accordance with the chosen language");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests persistence of negotiation settings for the content language type.
|
||||
*/
|
||||
public function testContentCustomization(): void {
|
||||
// Customize content language settings from their defaults.
|
||||
$edit = [
|
||||
'language_content[configurable]' => TRUE,
|
||||
'language_content[enabled][language-url]' => FALSE,
|
||||
'language_content[enabled][language-session]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Check if configurability persisted.
|
||||
$config = $this->config('language.types');
|
||||
$this->assertContains('language_interface', $config->get('configurable'), 'Interface language is configurable.');
|
||||
$this->assertContains('language_content', $config->get('configurable'), 'Content language is configurable.');
|
||||
|
||||
// Ensure configuration was saved.
|
||||
$this->assertArrayNotHasKey('language-url', $config->get('negotiation.language_content.enabled'));
|
||||
$this->assertArrayHasKey('language-session', $config->get('negotiation.language_content.enabled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the language switcher block gets deleted when a language type has been made not configurable.
|
||||
*/
|
||||
public function testDisableLanguageSwitcher(): void {
|
||||
$block_id = 'test_language_block';
|
||||
|
||||
// Enable the language switcher block.
|
||||
$this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_CONTENT, ['id' => $block_id]);
|
||||
|
||||
// Check if the language switcher block has been created.
|
||||
$block = Block::load($block_id);
|
||||
$this->assertNotEmpty($block, 'Language switcher block was created.');
|
||||
|
||||
// Make sure language_content is not configurable.
|
||||
$edit = [
|
||||
'language_content[configurable]' => FALSE,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
// Check if the language switcher block has been removed.
|
||||
$block = Block::load($block_id);
|
||||
$this->assertNull($block, 'Language switcher block was removed.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional;
|
||||
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests that URL rewriting works as expected.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageUrlRewritingTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'language_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* A user with permissions to administer languages.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create and log in user.
|
||||
$this->webUser = $this->drupalCreateUser([
|
||||
'administer languages',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($this->webUser);
|
||||
|
||||
// Install French language.
|
||||
$edit = [];
|
||||
$edit['predefined_langcode'] = 'fr';
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Enable URL language detection and selection.
|
||||
$edit = ['language_interface[enabled][language-url]' => 1];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Check that drupalSettings contains path prefix.
|
||||
$this->drupalGet('fr/admin/config/regional/language/detection');
|
||||
$this->assertSession()->responseContains('"pathPrefix":"fr\/"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that non-installed languages are not considered.
|
||||
*/
|
||||
public function testUrlRewritingEdgeCases(): void {
|
||||
// Check URL rewriting with a non-installed language.
|
||||
$non_existing = new Language(['id' => $this->randomMachineName()]);
|
||||
$this->checkUrl($non_existing, 'Path language is ignored if language is not installed.');
|
||||
|
||||
// Check that URL rewriting is not applied to subrequests.
|
||||
$this->drupalGet('language_test/subrequest');
|
||||
$this->assertSession()->pageTextContains($this->webUser->getAccountName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check URL rewriting for the given language.
|
||||
*
|
||||
* The test is performed with a fixed URL (the default front page) to simply
|
||||
* check that language prefixes are not added to it and that the prefixed URL
|
||||
* is actually not working.
|
||||
*
|
||||
* @param \Drupal\Core\Language\LanguageInterface $language
|
||||
* The language object.
|
||||
* @param string $message
|
||||
* Message to display in assertion that language prefixes are not added.
|
||||
*/
|
||||
private function checkUrl(LanguageInterface $language, $message): void {
|
||||
$options = ['language' => $language, 'script' => ''];
|
||||
$base_path = trim(base_path(), '/');
|
||||
$rewritten_path = trim(str_replace($base_path, '', Url::fromRoute('<front>', [], $options)->toString()), '/');
|
||||
$segments = explode('/', $rewritten_path, 2);
|
||||
$prefix = $segments[0];
|
||||
$path = $segments[1] ?? $prefix;
|
||||
|
||||
// If the rewritten URL has not a language prefix we pick a random prefix so
|
||||
// we can always check the prefixed URL.
|
||||
$prefixes = $this->config('language.negotiation')->get('url.prefixes');
|
||||
$stored_prefix = $prefixes[$language->getId()] ?? $this->randomMachineName();
|
||||
$this->assertNotEquals($prefix, $stored_prefix, $message);
|
||||
$prefix = $stored_prefix;
|
||||
|
||||
$this->drupalGet("$prefix/$path");
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check URL rewriting when using a domain name and a non-standard port.
|
||||
*/
|
||||
public function testDomainNameNegotiationPort(): void {
|
||||
global $base_url;
|
||||
$language_domain = 'example.fr';
|
||||
// Get the current host URI we're running on.
|
||||
$base_url_host = parse_url($base_url, PHP_URL_HOST);
|
||||
$edit = [
|
||||
'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domain[en]' => $base_url_host,
|
||||
'domain[fr]' => $language_domain,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection/url');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
// Rebuild the container so that the new language gets picked up by services
|
||||
// that hold the list of languages.
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Enable domain configuration.
|
||||
$this->config('language.negotiation')
|
||||
->set('url.source', LanguageNegotiationUrl::CONFIG_DOMAIN)
|
||||
->save();
|
||||
|
||||
// Reset static caching.
|
||||
$this->container->get('language_manager')->reset();
|
||||
|
||||
// In case index.php is part of the URLs, we need to adapt the asserted
|
||||
// URLs as well.
|
||||
$index_php = str_contains(Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(), 'index.php');
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$server = $request->server->all();
|
||||
$request = $this->prepareRequestForGenerator(TRUE, ['HTTP_HOST' => $server['HTTP_HOST'] . ':88']);
|
||||
|
||||
// Create an absolute French link.
|
||||
$language = \Drupal::languageManager()->getLanguage('fr');
|
||||
$url = Url::fromRoute('<front>', [], [
|
||||
'absolute' => TRUE,
|
||||
'language' => $language,
|
||||
])->toString();
|
||||
|
||||
$expected = ($index_php ? 'http://example.fr:88/index.php' : 'http://example.fr:88') . rtrim(base_path(), '/') . '/';
|
||||
|
||||
$this->assertEquals($expected, $url, 'The right port is used.');
|
||||
|
||||
// If we set the port explicitly, it should not be overridden.
|
||||
$url = Url::fromRoute('<front>', [], [
|
||||
'absolute' => TRUE,
|
||||
'language' => $language,
|
||||
'base_url' => $request->getBaseUrl() . ':90',
|
||||
])->toString();
|
||||
|
||||
$expected = $index_php ? 'http://example.fr:90/index.php' : 'http://example.fr:90' . rtrim(base_path(), '/') . '/';
|
||||
|
||||
$this->assertEquals($expected, $url, 'A given port is not overridden.');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonAnonTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonBasicAuthTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonCookieTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigEntityResourceTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Resource test base for ConfigurableLanguage entity.
|
||||
*/
|
||||
abstract class ConfigurableLanguageResourceTestBase extends ConfigEntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'configurable_language';
|
||||
|
||||
/**
|
||||
* @var \Drupal\language\ConfigurableLanguageInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer languages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$configurable_language = ConfigurableLanguage::create([
|
||||
'id' => 'll',
|
||||
'label' => 'Llama Language',
|
||||
]);
|
||||
$configurable_language->save();
|
||||
|
||||
return $configurable_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'direction' => 'ltr',
|
||||
'id' => 'll',
|
||||
'label' => 'Llama Language',
|
||||
'langcode' => 'en',
|
||||
'locked' => FALSE,
|
||||
'status' => TRUE,
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'weight' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['languages:language_interface']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a GET request for a default config entity, which has a _core key.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2915414
|
||||
*/
|
||||
public function testGetDefaultConfig(): void {
|
||||
$this->initAuthentication();
|
||||
$url = Url::fromUri('base:/entity/configurable_language/en')->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = $this->getAuthenticationRequestOptions('GET');
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
|
||||
$normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
$this->assertArrayNotHasKey('_core', $normalization);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageXmlAnonTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageXmlBasicAuthTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageXmlCookieTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsJsonAnonTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsJsonBasicAuthTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsJsonCookieTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigEntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* Resource test base for the ContentLanguageSettings entity.
|
||||
*/
|
||||
abstract class ContentLanguageSettingsResourceTestBase extends ConfigEntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'language_content_settings';
|
||||
|
||||
/**
|
||||
* @var \Drupal\language\ContentLanguageSettingsInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer languages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" node type.
|
||||
$camelids = NodeType::create([
|
||||
'name' => 'Camelids',
|
||||
'type' => 'camelids',
|
||||
]);
|
||||
$camelids->save();
|
||||
|
||||
$entity = ContentLanguageSettings::create([
|
||||
'target_entity_type_id' => 'node',
|
||||
'target_bundle' => 'camelids',
|
||||
]);
|
||||
$entity->setDefaultLangcode('site_default')
|
||||
->save();
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'default_langcode' => 'site_default',
|
||||
'dependencies' => [
|
||||
'config' => [
|
||||
'node.type.camelids',
|
||||
],
|
||||
],
|
||||
'id' => 'node.camelids',
|
||||
'langcode' => 'en',
|
||||
'language_alterable' => FALSE,
|
||||
'status' => TRUE,
|
||||
'target_bundle' => 'camelids',
|
||||
'target_entity_type_id' => 'node',
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return [
|
||||
'languages:language_interface',
|
||||
'user.permissions',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsXmlAnonTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsXmlBasicAuthTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsXmlCookieTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Condition;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the language condition plugin.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConditionTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* The condition plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Condition\ConditionManager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['language']);
|
||||
// Setup Italian.
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
|
||||
$this->manager = $this->container->get('plugin.manager.condition');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the language condition.
|
||||
*/
|
||||
public function testConditions(): void {
|
||||
// Grab the language condition and configure it to check the content
|
||||
// language.
|
||||
$language = \Drupal::languageManager()->getLanguage('en');
|
||||
$condition = $this->manager->createInstance('language')
|
||||
->setConfig('langcodes', ['en' => 'en', 'it' => 'it'])
|
||||
->setContextValue('language', $language);
|
||||
$this->assertTrue($condition->execute(), 'Language condition passes as expected.');
|
||||
// Check for the proper summary.
|
||||
$this->assertEquals('The language is English, Italian.', $condition->summary());
|
||||
|
||||
// Change to Italian only.
|
||||
$condition->setConfig('langcodes', ['it' => 'it']);
|
||||
$this->assertFalse($condition->execute(), 'Language condition fails as expected.');
|
||||
// Check for the proper summary.
|
||||
$this->assertEquals('The language is Italian.', $condition->summary());
|
||||
|
||||
// Negate the condition
|
||||
$condition->setConfig('negate', TRUE);
|
||||
$this->assertTrue($condition->execute(), 'Language condition passes as expected.');
|
||||
// Check for the proper summary.
|
||||
$this->assertEquals('The language is not Italian.', $condition->summary());
|
||||
|
||||
// Change the default language to Italian.
|
||||
$language = \Drupal::languageManager()->getLanguage('it');
|
||||
|
||||
$condition = $this->manager->createInstance('language')
|
||||
->setConfig('langcodes', ['en' => 'en', 'it' => 'it'])
|
||||
->setContextValue('language', $language);
|
||||
|
||||
$this->assertTrue($condition->execute(), 'Language condition passes as expected.');
|
||||
// Check for the proper summary.
|
||||
$this->assertEquals('The language is English, Italian.', $condition->summary());
|
||||
|
||||
// Change to Italian only.
|
||||
$condition->setConfig('langcodes', ['it' => 'it']);
|
||||
$this->assertTrue($condition->execute(), 'Language condition passes as expected.');
|
||||
// Check for the proper summary.
|
||||
$this->assertEquals('The language is Italian.', $condition->summary());
|
||||
|
||||
// Negate the condition
|
||||
$condition->setConfig('negate', TRUE);
|
||||
$this->assertFalse($condition->execute(), 'Language condition fails as expected.');
|
||||
// Check for the proper summary.
|
||||
$this->assertEquals('The language is not Italian.', $condition->summary());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Config\Action\ConfigActionManager;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* @group language
|
||||
*/
|
||||
class ConfigActionsTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* The configuration action manager.
|
||||
*/
|
||||
private readonly ConfigActionManager $configActionManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installConfig('language');
|
||||
$this->configActionManager = $this->container->get('plugin.manager.config_action');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the application of configuration actions on a language.
|
||||
*/
|
||||
public function testConfigActions(): void {
|
||||
$language = ConfigurableLanguage::load('en');
|
||||
$this->assertSame('English', $language->getName());
|
||||
$this->assertSame(0, $language->getWeight());
|
||||
|
||||
$this->configActionManager->applyAction(
|
||||
'entity_method:language.entity:setName',
|
||||
$language->getConfigDependencyName(),
|
||||
'Wacky language',
|
||||
);
|
||||
$this->configActionManager->applyAction(
|
||||
'entity_method:language.entity:setWeight',
|
||||
$language->getConfigDependencyName(),
|
||||
39,
|
||||
);
|
||||
|
||||
$language = ConfigurableLanguage::load('en');
|
||||
$this->assertSame('Wacky language', $language->getName());
|
||||
$this->assertSame(39, $language->getWeight());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Tests the ConfigurableLanguage entity.
|
||||
*
|
||||
* @group language
|
||||
* @coversDefaultClass \Drupal\language\ConfigurableLanguageManager
|
||||
*/
|
||||
class ConfigurableLanguageManagerTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* The language negotiator.
|
||||
*
|
||||
* @var \Drupal\language\LanguageNegotiatorInterface
|
||||
*/
|
||||
protected $languageNegotiator;
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\language\ConfigurableLanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('user');
|
||||
|
||||
$this->languageNegotiator = $this->container->get('language_negotiator');
|
||||
$this->languageManager = $this->container->get('language_manager');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getLanguageSwitchLinks
|
||||
*/
|
||||
public function testLanguageSwitchLinks(): void {
|
||||
$this->languageNegotiator->setCurrentUser($this->prophesize('Drupal\Core\Session\AccountInterface')->reveal());
|
||||
$this->languageManager->getLanguageSwitchLinks(LanguageInterface::TYPE_INTERFACE, new Url('<current>'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the ConfigurableLanguage entity.
|
||||
*
|
||||
* @group language
|
||||
* @see \Drupal\language\Entity\ConfigurableLanguage.
|
||||
*/
|
||||
class ConfigurableLanguageTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Tests configurable language name methods.
|
||||
*/
|
||||
public function testName(): void {
|
||||
$name = $this->randomMachineName();
|
||||
$language_code = $this->randomMachineName(2);
|
||||
$configurableLanguage = new ConfigurableLanguage(['label' => $name, 'id' => $language_code], 'configurable_language');
|
||||
$this->assertEquals($name, $configurableLanguage->getName());
|
||||
$this->assertEquals('Test language', $configurableLanguage->setName('Test language')->getName());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests validation of configurable_language entities.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class ConfigurableLanguageValidationTest extends ConfigEntityValidationTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->entity = ConfigurableLanguage::createFromLangcode('fr');
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestBundle;
|
||||
use Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
|
||||
|
||||
/**
|
||||
* Tests validation of content_language_settings entities.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class ContentLanguageSettingsValidationTest extends ConfigEntityValidationTestBase {
|
||||
|
||||
use ContentTypeCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'entity_test',
|
||||
'field',
|
||||
'language',
|
||||
'node',
|
||||
'text',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected bool $hasLabel = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig('node');
|
||||
|
||||
$this->createContentType(['type' => 'alpha']);
|
||||
$this->createContentType(['type' => 'bravo']);
|
||||
|
||||
EntityTestBundle::create(['id' => 'alpha'])->save();
|
||||
EntityTestBundle::create(['id' => 'bravo'])->save();
|
||||
|
||||
$this->entity = ContentLanguageSettings::create([
|
||||
'target_entity_type_id' => 'node',
|
||||
'target_bundle' => 'alpha',
|
||||
]);
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the target bundle of the language content settings is checked.
|
||||
*/
|
||||
public function testTargetBundleMustExist(): void {
|
||||
$this->entity->set('target_bundle', 'superhero');
|
||||
$this->assertValidationErrors([
|
||||
'' => "The 'target_bundle' property cannot be changed.",
|
||||
'target_bundle' => "The 'superhero' bundle does not exist on the 'node' entity type.",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testImmutableProperties(array $valid_values = []): void {
|
||||
parent::testImmutableProperties([
|
||||
'target_entity_type_id' => 'entity_test_with_bundle',
|
||||
'target_bundle' => 'bravo',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests default language code is properly generated for entities.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class EntityDefaultLanguageTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'node',
|
||||
'field',
|
||||
'text',
|
||||
'user',
|
||||
'system',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('user');
|
||||
|
||||
// Activate Spanish language, so there are two languages activated.
|
||||
$language = $this->container->get('entity_type.manager')->getStorage('configurable_language')->create([
|
||||
'id' => 'es',
|
||||
'label' => 'Spanish',
|
||||
]);
|
||||
$language->save();
|
||||
|
||||
// Create a new content type which has Undefined language by default.
|
||||
$this->createContentType('content_und', LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
// Create a new content type which has Spanish language by default.
|
||||
$this->createContentType('content_es', 'es');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that default language code is properly set for new nodes.
|
||||
*/
|
||||
public function testEntityTranslationDefaultLanguageViaCode(): void {
|
||||
// With language module activated, and a content type that is configured to
|
||||
// have no language by default, a new node of this content type will have
|
||||
// "und" language code when language is not specified.
|
||||
$node = $this->createNode('content_und');
|
||||
$this->assertEquals(LanguageInterface::LANGCODE_NOT_SPECIFIED, $node->langcode->value);
|
||||
// With language module activated, and a content type that is configured to
|
||||
// have no language by default, a new node of this content type will have
|
||||
// "es" language code when language is specified as "es".
|
||||
$node = $this->createNode('content_und', 'es');
|
||||
$this->assertEquals('es', $node->langcode->value);
|
||||
|
||||
// With language module activated, and a content type that is configured to
|
||||
// have language "es" by default, a new node of this content type will have
|
||||
// "es" language code when language is not specified.
|
||||
$node = $this->createNode('content_es');
|
||||
$this->assertEquals('es', $node->langcode->value);
|
||||
// With language module activated, and a content type that is configured to
|
||||
// have language "es" by default, a new node of this content type will have
|
||||
// "en" language code when language "en" is specified.
|
||||
$node = $this->createNode('content_es', 'en');
|
||||
$this->assertEquals('en', $node->langcode->value);
|
||||
|
||||
// Disable language module.
|
||||
$this->disableModules(['language']);
|
||||
|
||||
// With language module disabled, and a content type that is configured to
|
||||
// have no language specified by default, a new node of this content type
|
||||
// will have site's default language code when language is not specified.
|
||||
$node = $this->createNode('content_und');
|
||||
$this->assertEquals('en', $node->langcode->value);
|
||||
// With language module disabled, and a content type that is configured to
|
||||
// have no language specified by default, a new node of this type will have
|
||||
// "es" language code when language "es" is specified.
|
||||
$node = $this->createNode('content_und', 'es');
|
||||
$this->assertEquals('es', $node->langcode->value);
|
||||
|
||||
// With language module disabled, and a content type that is configured to
|
||||
// have language "es" by default, a new node of this type will have site's
|
||||
// default language code when language is not specified.
|
||||
$node = $this->createNode('content_es');
|
||||
$this->assertEquals('en', $node->langcode->value);
|
||||
// With language module disabled, and a content type that is configured to
|
||||
// have language "es" by default, a new node of this type will have "en"
|
||||
// language code when language "en" is specified.
|
||||
$node = $this->createNode('content_es', 'en');
|
||||
$this->assertEquals('en', $node->langcode->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node content type.
|
||||
*
|
||||
* @param string $name
|
||||
* The content type name.
|
||||
* @param string $langcode
|
||||
* Default language code of the nodes of this type.
|
||||
*/
|
||||
protected function createContentType($name, $langcode): void {
|
||||
$content_type = $this->container->get('entity_type.manager')->getStorage('node_type')->create([
|
||||
'name' => 'Test ' . $name,
|
||||
'title_label' => 'Title',
|
||||
'type' => $name,
|
||||
'create_body' => FALSE,
|
||||
]);
|
||||
$content_type->save();
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('node', $name)
|
||||
->setLanguageAlterable(FALSE)
|
||||
->setDefaultLangcode($langcode)
|
||||
->save();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node of given type and language using Entity API.
|
||||
*
|
||||
* @param string $type
|
||||
* The node content type.
|
||||
* @param string $langcode
|
||||
* (optional) Language code to pass to entity create.
|
||||
*
|
||||
* @return \Drupal\node\NodeInterface
|
||||
* The node created.
|
||||
*/
|
||||
protected function createNode($type, $langcode = NULL) {
|
||||
$values = [
|
||||
'type' => $type,
|
||||
'title' => $this->randomString(),
|
||||
];
|
||||
if (!empty($langcode)) {
|
||||
$values['langcode'] = $langcode;
|
||||
}
|
||||
$node = $this->container->get('entity_type.manager')->getStorage('node')->create($values);
|
||||
return $node;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Core\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Tests the language of entity URLs.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class EntityUrlLanguageTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['entity_test', 'user'];
|
||||
|
||||
/**
|
||||
* The entity being used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test');
|
||||
$this->installEntitySchema('configurable_language');
|
||||
|
||||
// In order to reflect the changes for a multilingual site in the container
|
||||
// we have to rebuild it.
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$config->set('url.prefixes', ['en' => 'en', 'es' => 'es', 'fr' => 'fr'])
|
||||
->save();
|
||||
|
||||
\Drupal::service('kernel')->rebuildContainer();
|
||||
|
||||
$this->createTranslatableEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that entity URLs in a language have the right language prefix.
|
||||
*/
|
||||
public function testEntityUrlLanguage(): void {
|
||||
$this->assertStringContainsString('/en/entity_test/' . $this->entity->id(), $this->entity->toUrl()->toString());
|
||||
$this->assertStringContainsString('/es/entity_test/' . $this->entity->id(), $this->entity->getTranslation('es')->toUrl()->toString());
|
||||
$this->assertStringContainsString('/fr/entity_test/' . $this->entity->id(), $this->entity->getTranslation('fr')->toUrl()->toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures correct entity URLs with the method language-content-entity enabled.
|
||||
*
|
||||
* Test case with the method language-content-entity enabled and configured
|
||||
* with higher and also with lower priority than the method language-url.
|
||||
*/
|
||||
public function testEntityUrlLanguageWithLanguageContentEnabled(): void {
|
||||
// Define the method language-content-entity with a higher priority than
|
||||
// language-url.
|
||||
$config = $this->config('language.types');
|
||||
$config->set('configurable', [LanguageInterface::TYPE_INTERFACE, LanguageInterface::TYPE_CONTENT]);
|
||||
$config->set('negotiation.language_content.enabled', [
|
||||
LanguageNegotiationContentEntity::METHOD_ID => 0,
|
||||
LanguageNegotiationUrl::METHOD_ID => 1,
|
||||
]);
|
||||
$config->save();
|
||||
|
||||
// Without being on a content entity route the default entity URL tests
|
||||
// should still pass.
|
||||
$this->testEntityUrlLanguage();
|
||||
|
||||
// Now switching to an entity route, so that the URL links are generated
|
||||
// while being on an entity route.
|
||||
$this->setCurrentRequestForRoute('/entity_test/{entity_test}', 'entity.entity_test.canonical');
|
||||
|
||||
// The method language-content-entity should run before language-url and
|
||||
// append query parameter for the content language and prevent language-url
|
||||
// from overwriting the URL.
|
||||
$this->assertStringContainsString('/en/entity_test/' . $this->entity->id() . '?' . LanguageNegotiationContentEntity::QUERY_PARAMETER . '=en', $this->entity->toUrl('canonical')->toString());
|
||||
$this->assertStringContainsString('/en/entity_test/' . $this->entity->id() . '?' . LanguageNegotiationContentEntity::QUERY_PARAMETER . '=es', $this->entity->getTranslation('es')->toUrl('canonical')->toString());
|
||||
$this->assertStringContainsString('/en/entity_test/' . $this->entity->id() . '?' . LanguageNegotiationContentEntity::QUERY_PARAMETER . '=fr', $this->entity->getTranslation('fr')->toUrl('canonical')->toString());
|
||||
|
||||
// Define the method language-url with a higher priority than
|
||||
// language-content-entity. This configuration should match the default one,
|
||||
// where the language-content-entity is turned off.
|
||||
$config->set('negotiation.language_content.enabled', [
|
||||
LanguageNegotiationUrl::METHOD_ID => 0,
|
||||
LanguageNegotiationContentEntity::METHOD_ID => 1,
|
||||
]);
|
||||
$config->save();
|
||||
|
||||
// The default entity URL tests should pass again with the current
|
||||
// configuration.
|
||||
$this->testEntityUrlLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a translated entity.
|
||||
*/
|
||||
protected function createTranslatableEntity(): void {
|
||||
$this->entity = EntityTest::create();
|
||||
$this->entity->addTranslation('es', ['name' => 'name spanish']);
|
||||
$this->entity->addTranslation('fr', ['name' => 'name french']);
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current request to a specific path with the corresponding route.
|
||||
*
|
||||
* @param string $path
|
||||
* The path for which the current request should be created.
|
||||
* @param string $route_name
|
||||
* The route name for which the route object for the request should be
|
||||
* created.
|
||||
*/
|
||||
protected function setCurrentRequestForRoute($path, $route_name): void {
|
||||
$request = Request::create($path);
|
||||
$request->attributes->set(RouteObjectInterface::ROUTE_NAME, $route_name);
|
||||
$request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route($path));
|
||||
$request->setSession(new Session(new MockArraySessionStorage()));
|
||||
$this->container->get('request_stack')->push($request);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests \Drupal\language\Config\LanguageConfigFactoryOverride.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigFactoryOverrideTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'language'];
|
||||
|
||||
/**
|
||||
* Tests language.config_factory_override service has the default language.
|
||||
*/
|
||||
public function testLanguageConfigFactoryOverride(): void {
|
||||
$this->installConfig('system');
|
||||
$this->installConfig('language');
|
||||
|
||||
/** @var \Drupal\language\Config\LanguageConfigFactoryOverride $config_factory_override */
|
||||
$config_factory_override = \Drupal::service('language.config_factory_override');
|
||||
$this->assertEquals('en', $config_factory_override->getLanguage()->getId());
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
|
||||
// Invalidate the container.
|
||||
$this->config('system.site')->set('default_langcode', 'de')->save();
|
||||
$this->container->get('kernel')->rebuildContainer();
|
||||
|
||||
$config_factory_override = \Drupal::service('language.config_factory_override');
|
||||
$this->assertEquals('de', $config_factory_override->getLanguage()->getId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Config\ConfigCollectionEvents;
|
||||
use Drupal\language\Config\LanguageConfigOverrideEvents;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
// cspell:ignore deutsch
|
||||
|
||||
/**
|
||||
* Ensures the language config overrides can be installed.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigOverrideInstallTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'config_events_test', 'language_events_test'];
|
||||
|
||||
/**
|
||||
* Tests the configuration events are not fired during install of overrides.
|
||||
*/
|
||||
public function testLanguageConfigOverrideInstall(): void {
|
||||
$this->installConfig(['language']);
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
// Need to enable test module after creating the language otherwise saving
|
||||
// the language will install the configuration.
|
||||
$this->enableModules(['language_config_override_test']);
|
||||
\Drupal::state()->set('config_events_test.event', FALSE);
|
||||
\Drupal::state()->set('language_events_test.all_events', []);
|
||||
$this->installConfig(['language_config_override_test']);
|
||||
|
||||
// Ensure the save-in-collection event is triggered when saving data in
|
||||
// config collections during an install.
|
||||
$event_recorder = \Drupal::state()->get('config_events_test.event', FALSE);
|
||||
$this->assertSame([
|
||||
'event_name' => ConfigCollectionEvents::SAVE_IN_COLLECTION,
|
||||
'current_config_data' => ['name' => 'Deutsch'],
|
||||
'original_config_data' => [],
|
||||
'raw_config_data' => ['name' => 'Deutsch'],
|
||||
], $event_recorder);
|
||||
$config = \Drupal::service('language.config_factory_override')->getOverride('de', 'language_config_override_test.settings');
|
||||
$this->assertEquals('Deutsch', $config->get('name'));
|
||||
|
||||
// Ensure the save override event is triggered when saving overrides during
|
||||
// an install.
|
||||
$event_recorder = \Drupal::state()->get('language_events_test.all_events', []);
|
||||
$this->assertArrayHasKey(LanguageConfigOverrideEvents::SAVE_OVERRIDE, $event_recorder);
|
||||
$this->assertArrayHasKey('language_config_override_test.settings', $event_recorder[LanguageConfigOverrideEvents::SAVE_OVERRIDE]);
|
||||
$this->assertSame([
|
||||
'event_name' => LanguageConfigOverrideEvents::SAVE_OVERRIDE,
|
||||
'current_override_data' => ['name' => 'Deutsch'],
|
||||
'original_override_data' => [],
|
||||
], $event_recorder['language.save_override']['language_config_override_test.settings'][0]);
|
||||
|
||||
// Test events during uninstall.
|
||||
\Drupal::state()->set('config_events_test.all_events', []);
|
||||
\Drupal::state()->set('language_events_test.all_events', []);
|
||||
$this->container->get('module_installer')->uninstall(['language_config_override_test']);
|
||||
|
||||
// Ensure the delete-in-collection event is triggered when deleting data in
|
||||
// config collections during an uninstall.
|
||||
$event_recorder = \Drupal::state()->get('config_events_test.all_events', []);
|
||||
$this->assertArrayHasKey(ConfigCollectionEvents::DELETE_IN_COLLECTION, $event_recorder);
|
||||
$this->assertArrayHasKey('language_config_override_test.settings', $event_recorder[ConfigCollectionEvents::DELETE_IN_COLLECTION]);
|
||||
$this->assertSame([
|
||||
'event_name' => ConfigCollectionEvents::DELETE_IN_COLLECTION,
|
||||
'current_config_data' => [],
|
||||
'original_config_data' => ['name' => 'Deutsch'],
|
||||
'raw_config_data' => [],
|
||||
], $event_recorder[ConfigCollectionEvents::DELETE_IN_COLLECTION]['language_config_override_test.settings'][0]);
|
||||
|
||||
// Ensure the delete override event is triggered when deleting overrides
|
||||
// during an uninstall.
|
||||
$event_recorder = \Drupal::state()->get('language_events_test.all_events', []);
|
||||
$this->assertArrayHasKey(LanguageConfigOverrideEvents::DELETE_OVERRIDE, $event_recorder);
|
||||
$this->assertArrayHasKey('language_config_override_test.settings', $event_recorder[LanguageConfigOverrideEvents::DELETE_OVERRIDE]);
|
||||
$this->assertSame([
|
||||
'event_name' => LanguageConfigOverrideEvents::DELETE_OVERRIDE,
|
||||
'current_override_data' => [],
|
||||
'original_override_data' => ['name' => 'Deutsch'],
|
||||
], $event_recorder['language.delete_override']['language_config_override_test.settings'][0]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Exception\DeleteDefaultLanguageException;
|
||||
|
||||
/**
|
||||
* Tests that a language object can be injected.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageDependencyInjectionTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* Tests dependency injected languages against a new Language object.
|
||||
*
|
||||
* @see \Drupal\Core\Language\LanguageInterface
|
||||
*/
|
||||
public function testDependencyInjectedNewLanguage(): void {
|
||||
$expected = $this->languageManager->getDefaultLanguage();
|
||||
$result = $this->languageManager->getCurrentLanguage();
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests dependency injected Language object.
|
||||
*
|
||||
* @see \Drupal\Core\Language\Language
|
||||
*/
|
||||
public function testDependencyInjectedNewDefaultLanguage(): void {
|
||||
$default_language = ConfigurableLanguage::load(\Drupal::languageManager()->getDefaultLanguage()->getId());
|
||||
// Change the language default object to different values.
|
||||
$fr = ConfigurableLanguage::createFromLangcode('fr');
|
||||
$fr->save();
|
||||
$this->config('system.site')->set('default_langcode', 'fr')->save();
|
||||
|
||||
// The language system creates a Language object which contains the
|
||||
// same properties as the new default language object.
|
||||
$result = \Drupal::languageManager()->getCurrentLanguage();
|
||||
$this->assertSame('fr', $result->getId());
|
||||
|
||||
// Delete the language to check that we fallback to the default.
|
||||
try {
|
||||
$fr->delete();
|
||||
$this->fail('Expected DeleteDefaultLanguageException thrown.');
|
||||
}
|
||||
catch (DeleteDefaultLanguageException) {
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Re-save the previous default language and the delete should work.
|
||||
$this->config('system.site')->set('default_langcode', $default_language->getId())->save();
|
||||
|
||||
$fr->delete();
|
||||
$result = \Drupal::languageManager()->getCurrentLanguage();
|
||||
$this->assertSame($default_language->getId(), $result->getId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the language fallback behavior.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageFallbackTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$i = 0;
|
||||
foreach (['af', 'am', 'ar'] as $langcode) {
|
||||
$language = ConfigurableLanguage::createFromLangcode($langcode);
|
||||
$language->set('weight', $i--);
|
||||
$language->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language fallback candidates.
|
||||
*/
|
||||
public function testCandidates(): void {
|
||||
$language_list = $this->languageManager->getLanguages();
|
||||
$expected = array_keys($language_list + [LanguageInterface::LANGCODE_NOT_SPECIFIED => NULL]);
|
||||
|
||||
// Check that language fallback candidates by default are all the available
|
||||
// languages sorted by weight.
|
||||
$candidates = $this->languageManager->getFallbackCandidates();
|
||||
$this->assertEquals($expected, array_values($candidates), 'Language fallback candidates are properly returned.');
|
||||
|
||||
// Check that candidates are alterable.
|
||||
$this->state->set('language_test.fallback_alter.candidates', TRUE);
|
||||
$expected = array_slice($expected, 0, count($expected) - 1);
|
||||
$candidates = $this->languageManager->getFallbackCandidates();
|
||||
$this->assertEquals($expected, array_values($candidates), 'Language fallback candidates are alterable.');
|
||||
|
||||
// Check that candidates are alterable for specific operations.
|
||||
$this->state->set('language_test.fallback_alter.candidates', FALSE);
|
||||
$this->state->set('language_test.fallback_operation_alter.candidates', TRUE);
|
||||
$expected[] = LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
$expected[] = LanguageInterface::LANGCODE_NOT_APPLICABLE;
|
||||
$candidates = $this->languageManager->getFallbackCandidates(['operation' => 'test']);
|
||||
$this->assertEquals($expected, array_values($candidates), 'Language fallback candidates are alterable for specific operations.');
|
||||
|
||||
// Check that when the site is monolingual no language fallback is applied.
|
||||
/** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $configurable_language_storage */
|
||||
$configurable_language_storage = $this->container->get('entity_type.manager')->getStorage('configurable_language');
|
||||
foreach ($language_list as $langcode => $language) {
|
||||
if (!$language->isDefault()) {
|
||||
$configurable_language_storage->load($langcode)->delete();
|
||||
}
|
||||
}
|
||||
$candidates = $this->languageManager->getFallbackCandidates();
|
||||
$this->assertEquals([LanguageInterface::LANGCODE_DEFAULT], array_values($candidates), 'Language fallback is not applied when the Language module is not enabled.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Logger\LoggerChannelFactory;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Symfony\Component\ErrorHandler\BufferingLogger;
|
||||
|
||||
/**
|
||||
* Tests PluginNotFoundException.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiatorPluginTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'user'];
|
||||
|
||||
/**
|
||||
* Tests for PluginNotFoundException.
|
||||
*/
|
||||
public function testLanguageNegotiatorNoPlugin(): void {
|
||||
$logger = new BufferingLogger();
|
||||
$logger_factory = $this->createMock(LoggerChannelFactory::class);
|
||||
$logger_factory->expects($this->once())
|
||||
->method('get')
|
||||
->with('language')
|
||||
->willReturn($logger);
|
||||
$this->container->set('logger.factory', $logger_factory);
|
||||
$this->installEntitySchema('user');
|
||||
|
||||
// Test unavailable plugin.
|
||||
$config = $this->config('language.types');
|
||||
$config->set('configurable', [LanguageInterface::TYPE_URL]);
|
||||
$config->set('negotiation.language_url.enabled', [
|
||||
self::CLASS => -3,
|
||||
]);
|
||||
$config->save();
|
||||
$languageNegotiator = $this->container->get('language_negotiator');
|
||||
$languageNegotiator->setCurrentUser($this->prophesize('Drupal\Core\Session\AccountInterface')->reveal());
|
||||
try {
|
||||
$languageNegotiator->initializeType(LanguageInterface::TYPE_URL);
|
||||
}
|
||||
catch (PluginNotFoundException) {
|
||||
$this->fail('Plugin not found exception unhandled.');
|
||||
}
|
||||
$log_message = $logger->cleanLogs()[0];
|
||||
$this->assertEquals('error', $log_message[0]);
|
||||
$this->assertStringContainsString('The "Drupal\Tests\language\Kernel\LanguageNegotiatorPluginTest" plugin does not exist.', $log_message[1]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the language select widget.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageSelectWidgetTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'entity_test',
|
||||
'language',
|
||||
'user',
|
||||
'system',
|
||||
];
|
||||
|
||||
/**
|
||||
* The entity form display.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Entity\EntityFormDisplay
|
||||
*/
|
||||
protected $entityFormDisplay;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test');
|
||||
$this->installEntitySchema('user');
|
||||
|
||||
$storage = $this->container->get('entity_type.manager')->getStorage('entity_form_display');
|
||||
$this->entityFormDisplay = $storage->create([
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the widget with the locked languages.
|
||||
*/
|
||||
public function testWithIncludedLockedLanguage(): void {
|
||||
$this->entityFormDisplay->setComponent('langcode', [
|
||||
'type' => 'language_select',
|
||||
])->save();
|
||||
$entity = EntityTest::create(['name' => $this->randomString()]);
|
||||
$form = $this->container->get('entity.form_builder')->getForm($entity);
|
||||
$options = array_keys($form['langcode']['widget'][0]['value']['#options']);
|
||||
$this->assertSame(['en', 'und', 'zxx'], $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the widget without the locked languages.
|
||||
*/
|
||||
public function testWithoutIncludedLockedLanguage(): void {
|
||||
$this->entityFormDisplay->setComponent('langcode', [
|
||||
'type' => 'language_select',
|
||||
'settings' => ['include_locked' => FALSE],
|
||||
])->save();
|
||||
$entity = EntityTest::create(['name' => $this->randomString()]);
|
||||
$form = $this->container->get('entity.form_builder')->getForm($entity);
|
||||
$options = array_keys($form['langcode']['widget'][0]['value']['#options']);
|
||||
$this->assertSame(['en'], $options);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Test for dependency injected language object.
|
||||
*/
|
||||
abstract class LanguageTestBase extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'language', 'language_test'];
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* The state storage service.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['language']);
|
||||
|
||||
$this->state = $this->container->get('state');
|
||||
|
||||
// Ensure we are building a new Language object for each test.
|
||||
$this->languageManager = $this->container->get('language_manager');
|
||||
$this->languageManager->reset();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests the default language variable migration.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateDefaultLanguageTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Tests language_default migration with an existing language.
|
||||
*/
|
||||
public function testMigrationWithExistingLanguage(): void {
|
||||
$this->setDefaultLanguage('fr');
|
||||
$this->startCollectingMessages();
|
||||
$this->executeMigrations(['language', 'default_language']);
|
||||
|
||||
// Tests the language is loaded and is the default language.
|
||||
$default_language = ConfigurableLanguage::load('fr');
|
||||
$this->assertNotNull($default_language);
|
||||
$this->assertSame('fr', $this->config('system.site')->get('default_langcode'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language_default migration with a non-existing language.
|
||||
*/
|
||||
public function testMigrationWithNonExistentLanguage(): void {
|
||||
$this->setDefaultLanguage('tv');
|
||||
$this->startCollectingMessages();
|
||||
$this->executeMigrations(['language', 'default_language']);
|
||||
|
||||
// Tests the migration log contains an error message.
|
||||
$messages = $this->migration->getIdMap()->getMessages();
|
||||
$count = 0;
|
||||
foreach ($messages as $message) {
|
||||
$count++;
|
||||
$this->assertSame("The language 'tv' does not exist on this site.", $message->message);
|
||||
$this->assertSame(MigrationInterface::MESSAGE_ERROR, (int) $message->level);
|
||||
}
|
||||
$this->assertSame(1, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language_default migration with unset default language variable.
|
||||
*/
|
||||
public function testMigrationWithUnsetVariable(): void {
|
||||
// Delete the language_default variable.
|
||||
$this->sourceDatabase->delete('variable')
|
||||
->condition('name', 'language_default')
|
||||
->execute();
|
||||
$this->startCollectingMessages();
|
||||
$this->executeMigrations(['language', 'default_language']);
|
||||
|
||||
$messages = $this->migration->getIdMap()->getMessages()->fetchAll();
|
||||
// Make sure there's no migration exceptions.
|
||||
$this->assertEmpty($messages);
|
||||
// Make sure the default langcode is 'en', as it was the default on D6 & D7.
|
||||
$this->assertSame('en', $this->config('system.site')->get('default_langcode'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to test the migration.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The langcode of the default language.
|
||||
*/
|
||||
protected function setDefaultLanguage($langcode): void {
|
||||
// The default language of the test fixture is English. Change it to
|
||||
// something else before migrating, to be sure that the source site
|
||||
// default language is migrated.
|
||||
$value = 'O:8:"stdClass":11:{s:8:"language";s:2:"' . $langcode . '";s:4:"name";s:6:"French";s:6:"native";s:6:"French";s:9:"direction";s:1:"0";s:7:"enabled";i:1;s:7:"plurals";s:1:"0";s:7:"formula";s:0:"";s:6:"domain";s:0:"";s:6:"prefix";s:0:"";s:6:"weight";s:1:"0";s:10:"javascript";s:0:"";}';
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(['value' => $value])
|
||||
->condition('name', 'language_default')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of language content comment settings.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageContentCommentSettingsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'comment',
|
||||
'language',
|
||||
'content_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installConfig(['comment']);
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_comment_type',
|
||||
'd6_language_content_comment_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of comment content language settings.
|
||||
*/
|
||||
public function testLanguageCommentSettings(): void {
|
||||
// Article and Employee content type have multilingual settings of 'Enabled,
|
||||
// with Translation'. Assert that comments are not translatable and the
|
||||
// default language is 'current_interface'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_article');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_article', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$third_party_settings = [
|
||||
'content_translation' => [
|
||||
'enabled' => FALSE,
|
||||
],
|
||||
];
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_employee');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_employee', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Sponsor content type has multilingual settings of 'Enabled'. Assert that
|
||||
// comments are not translatable and the default language is
|
||||
// 'current_interface'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_sponsor');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_sponsor', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Assert that non-translatable content is not translatable and the default
|
||||
// language is 'site_default.
|
||||
$not_translatable = [
|
||||
'comment_node_company',
|
||||
'comment_node_event',
|
||||
'comment_node_page',
|
||||
'comment_node_story',
|
||||
'comment_node_test_event',
|
||||
'comment_node_test_page',
|
||||
'comment_node_test_planet',
|
||||
'comment_node_test_story',
|
||||
'comment_forum',
|
||||
'comment_node_event',
|
||||
];
|
||||
foreach ($not_translatable as $bundle) {
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', $bundle);
|
||||
$this->assertTrue($config->isDefaultConfiguration());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
$this->assertSame('site_default', $config->getDefaultLangcode(), "Default language is not 'site_default' for comment bundle $bundle");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of the ability to translate menu content.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageContentMenuSettingsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'content_translation',
|
||||
'menu_link_content',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Create some languages.
|
||||
ConfigurableLanguage::createFromLangcode('en')->save();
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_content_menu_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of menu translation ability.
|
||||
*/
|
||||
public function testLanguageMenuContent(): void {
|
||||
$config = ContentLanguageSettings::load('menu_link_content.menu_link_content');
|
||||
$this->assertInstanceOf(ContentLanguageSettings::class, $config);
|
||||
$this->assertSame('menu_link_content', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('menu_link_content', $config->getTargetBundle());
|
||||
$this->assertSame(LanguageInterface::LANGCODE_SITE_DEFAULT, $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
|
||||
// Test that menus are not alterable when the i18nmenu is not enabled.
|
||||
$this->sourceDatabase->update('system')
|
||||
->fields(['status' => 0])
|
||||
->condition('name', 'i18nmenu')
|
||||
->execute();
|
||||
|
||||
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
|
||||
$migration = $this->getMigration('d6_language_content_menu_settings');
|
||||
// Indicate we're rerunning a migration that's already run.
|
||||
$migration->getIdMap()->prepareUpdate();
|
||||
$this->executeMigration($migration);
|
||||
|
||||
$config = ContentLanguageSettings::load('menu_link_content.menu_link_content');
|
||||
$this->assertInstanceOf(ContentLanguageSettings::class, $config);
|
||||
$this->assertSame('menu_link_content', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('menu_link_content', $config->getTargetBundle());
|
||||
$this->assertSame(LanguageInterface::LANGCODE_SITE_DEFAULT, $config->getDefaultLangcode());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration of language-related settings.
|
||||
*
|
||||
* Settings tested include language content setting variables,
|
||||
* language_content_type_$type, i18n_node_options_* and i18n_lock_node_*.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageContentSettingsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'text',
|
||||
'language',
|
||||
'content_translation',
|
||||
'menu_ui',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['node']);
|
||||
$this->installEntitySchema('node');
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_node_type',
|
||||
'd6_language_content_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of content language settings.
|
||||
*/
|
||||
public function testLanguageContent(): void {
|
||||
// Assert that a translatable content is still translatable.
|
||||
$config = $this->config('language.content_settings.node.article');
|
||||
$this->assertSame($config->get('target_entity_type_id'), 'node');
|
||||
$this->assertSame($config->get('target_bundle'), 'article');
|
||||
$this->assertSame($config->get('default_langcode'), 'current_interface');
|
||||
$this->assertTrue($config->get('third_party_settings.content_translation.enabled'));
|
||||
|
||||
// Assert that a non-translatable content is not translatable.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'company');
|
||||
$this->assertTrue($config->isDefaultConfiguration());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
$this->assertSame($config->getDefaultLangcode(), 'site_default');
|
||||
|
||||
// Assert that a we can assign a language when there is no language lock.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'employee');
|
||||
$this->assertSame($config->getDefaultLangcode(), 'current_interface');
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of i18ntaxonomy vocabulary settings.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageContentTaxonomyVocabularySettingsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'content_translation',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_language_content_taxonomy_vocabulary_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of 18ntaxonomy vocabulary settings.
|
||||
*/
|
||||
public function testLanguageContentTaxonomy(): void {
|
||||
$target_entity = 'taxonomy_term';
|
||||
// Per Language.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabulary_1_i_0_', LanguageInterface::LANGCODE_SITE_DEFAULT, TRUE, ['enabled' => FALSE]);
|
||||
// Set language to vocabulary.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabulary_2_i_1_', 'fr', FALSE, ['enabled' => FALSE]);
|
||||
// Localize terms.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabulary_3_i_2_', LanguageInterface::LANGCODE_SITE_DEFAULT, TRUE, ['enabled' => FALSE]);
|
||||
// None translation enabled.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabulary_name_much_longer_th', LanguageInterface::LANGCODE_SITE_DEFAULT, TRUE, ['enabled' => TRUE]);
|
||||
$this->assertLanguageContentSettings($target_entity, 'tags', LanguageInterface::LANGCODE_SITE_DEFAULT, FALSE, ['enabled' => FALSE]);
|
||||
$this->assertLanguageContentSettings($target_entity, 'forums', LanguageInterface::LANGCODE_SITE_DEFAULT, FALSE, ['enabled' => FALSE]);
|
||||
$this->assertLanguageContentSettings($target_entity, 'type', LanguageInterface::LANGCODE_SITE_DEFAULT, FALSE, ['enabled' => FALSE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a content language settings configuration.
|
||||
*
|
||||
* @param string $target_entity
|
||||
* The expected target entity type.
|
||||
* @param string $bundle
|
||||
* The expected bundle.
|
||||
* @param string $default_langcode
|
||||
* The default language code.
|
||||
* @param bool $language_alterable
|
||||
* The expected state of language alterable.
|
||||
* @param array $third_party_settings
|
||||
* The content translation setting.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function assertLanguageContentSettings(string $target_entity, string $bundle, string $default_langcode, bool $language_alterable, array $third_party_settings): void {
|
||||
$config = ContentLanguageSettings::load($target_entity . "." . $bundle);
|
||||
$this->assertInstanceOf(ContentLanguageSettings::class, $config);
|
||||
$this->assertSame($target_entity, $config->getTargetEntityTypeId());
|
||||
$this->assertSame($bundle, $config->getTargetBundle());
|
||||
$this->assertSame($default_langcode, $config->getDefaultLangcode());
|
||||
$this->assertSame($language_alterable, $config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->getThirdPartySettings('content_translation'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration of language negotiation and language types.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageNegotiationSettingsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_PATH_DEFAULT.
|
||||
*/
|
||||
public function testLanguageNegotiationWithDefaultPathPrefix(): void {
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_PATH_PREFIX, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'fr' => 'fr',
|
||||
'zu' => 'zu',
|
||||
];
|
||||
$this->assertSame($expected_prefixes, $config->get('url.prefixes'));
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame(['language_interface', 'language_content', 'language_url'], $config->get('all'));
|
||||
$this->assertSame(['language_interface'], $config->get('configurable'));
|
||||
$this->assertSame(['language-interface' => 0], $config->get('negotiation.language_content.enabled'));
|
||||
$this->assertSame(['language-url' => 0, 'language-url-fallback' => 1], $config->get('negotiation.language_url.enabled'));
|
||||
$expected_language_interface = [
|
||||
'language-url' => 0,
|
||||
'language-selected' => 1,
|
||||
];
|
||||
$this->assertSame($expected_language_interface, $config->get('negotiation.language_interface.enabled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_NONE.
|
||||
*/
|
||||
public function testLanguageNegotiationWithNoNegotiation(): void {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(['value' => serialize(0)])
|
||||
->condition('name', 'language_negotiation')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_PATH_PREFIX, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame(['language_interface', 'language_content', 'language_url'], $config->get('all'));
|
||||
$this->assertSame(['language_interface'], $config->get('configurable'));
|
||||
$this->assertSame(['language-interface' => 0], $config->get('negotiation.language_content.enabled'));
|
||||
$this->assertSame(['language-url' => 0, 'language-url-fallback' => 1], $config->get('negotiation.language_url.enabled'));
|
||||
$expected_language_interface = [
|
||||
'language-selected' => 0,
|
||||
];
|
||||
$this->assertSame($expected_language_interface, $config->get('negotiation.language_interface.enabled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_PATH.
|
||||
*/
|
||||
public function testLanguageNegotiationWithPathPrefix(): void {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(['value' => serialize(2)])
|
||||
->condition('name', 'language_negotiation')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_PATH_PREFIX, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'fr' => 'fr',
|
||||
'zu' => 'zu',
|
||||
];
|
||||
$this->assertSame($expected_prefixes, $config->get('url.prefixes'));
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame(['language_interface', 'language_content', 'language_url'], $config->get('all'));
|
||||
$this->assertSame(['language_interface'], $config->get('configurable'));
|
||||
$this->assertSame(['language-interface' => 0], $config->get('negotiation.language_content.enabled'));
|
||||
$this->assertSame(['language-url' => 0, 'language-url-fallback' => 1], $config->get('negotiation.language_url.enabled'));
|
||||
$expected_language_interface = [
|
||||
'language-url' => 0,
|
||||
'language-user' => 1,
|
||||
'language-browser' => 2,
|
||||
'language-selected' => 3,
|
||||
];
|
||||
$this->assertSame($expected_language_interface, $config->get('negotiation.language_interface.enabled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with LANGUAGE_NEGOTIATION_DOMAIN.
|
||||
*/
|
||||
public function testLanguageNegotiationWithDomain(): void {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(['value' => serialize(3)])
|
||||
->condition('name', 'language_negotiation')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
'd6_language_types',
|
||||
]);
|
||||
|
||||
global $base_url;
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_DOMAIN, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
$expected_domains = [
|
||||
'en' => parse_url($base_url, PHP_URL_HOST),
|
||||
'fr' => 'fr.drupal.org',
|
||||
'zu' => 'zu.drupal.org',
|
||||
];
|
||||
$this->assertSame($expected_domains, $config->get('url.domains'));
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame(['language_interface', 'language_content', 'language_url'], $config->get('all'));
|
||||
$this->assertSame(['language_interface'], $config->get('configurable'));
|
||||
$this->assertSame(['language-interface' => 0], $config->get('negotiation.language_content.enabled'));
|
||||
$this->assertSame(['language-url' => 0, 'language-url-fallback' => 1], $config->get('negotiation.language_url.enabled'));
|
||||
$expected_language_interface = [
|
||||
'language-url' => 0,
|
||||
'language-selected' => 1,
|
||||
];
|
||||
$this->assertSame($expected_language_interface, $config->get('negotiation.language_interface.enabled'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\language\ConfigurableLanguageInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateLanguageTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Asserts various properties of a configurable language entity.
|
||||
*
|
||||
* @param string $id
|
||||
* The language ID.
|
||||
* @param string $label
|
||||
* The language name.
|
||||
* @param string $direction
|
||||
* (optional) The language's direction (one of the DIRECTION_* constants in
|
||||
* ConfigurableLanguageInterface). Defaults to LTR.
|
||||
* @param int $weight
|
||||
* (optional) The weight of the language. Defaults to 0.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertLanguage(string $id, string $label, string $direction = ConfigurableLanguageInterface::DIRECTION_LTR, int $weight = 0): void {
|
||||
/** @var \Drupal\language\ConfigurableLanguageInterface $language */
|
||||
$language = ConfigurableLanguage::load($id);
|
||||
$this->assertInstanceOf(ConfigurableLanguageInterface::class, $language);
|
||||
$this->assertSame($label, $language->label());
|
||||
$this->assertSame($direction, $language->getDirection());
|
||||
$this->assertSame(0, $language->getWeight());
|
||||
$this->assertFalse($language->isLocked());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of Drupal 6 languages to configurable language entities.
|
||||
*/
|
||||
public function testLanguageMigration(): void {
|
||||
$this->executeMigration('language');
|
||||
$this->assertLanguage('en', 'English');
|
||||
$this->assertLanguage('fr', 'French');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests the default language variable migration.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateDefaultLanguageTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Tests language_default migration with a non-existing language.
|
||||
*/
|
||||
public function testMigrationWithExistingLanguage(): void {
|
||||
$this->setDefaultLanguage('is');
|
||||
$this->startCollectingMessages();
|
||||
$this->executeMigrations(['language', 'default_language']);
|
||||
|
||||
// Tests the language is loaded and is the default language.
|
||||
$default_language = ConfigurableLanguage::load('is');
|
||||
$this->assertNotNull($default_language);
|
||||
$this->assertSame('is', $this->config('system.site')->get('default_langcode'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language_default migration with a non-existing language.
|
||||
*/
|
||||
public function testMigrationWithNonExistentLanguage(): void {
|
||||
$this->setDefaultLanguage('tv');
|
||||
$this->startCollectingMessages();
|
||||
$this->executeMigrations(['language', 'default_language']);
|
||||
|
||||
// Tests the migration log contains an error message.
|
||||
$messages = $this->migration->getIdMap()->getMessages();
|
||||
$count = 0;
|
||||
foreach ($messages as $message) {
|
||||
$count++;
|
||||
$this->assertSame("The language 'tv' does not exist on this site.", $message->message);
|
||||
$this->assertSame(MigrationInterface::MESSAGE_ERROR, (int) $message->level);
|
||||
}
|
||||
$this->assertSame(1, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language_default migration with unset default language variable.
|
||||
*/
|
||||
public function testMigrationWithUnsetVariable(): void {
|
||||
// Delete the language_default variable.
|
||||
$this->sourceDatabase->delete('variable')
|
||||
->condition('name', 'language_default')
|
||||
->execute();
|
||||
$this->startCollectingMessages();
|
||||
$this->executeMigrations(['language', 'default_language']);
|
||||
|
||||
$messages = $this->migration->getIdMap()->getMessages()->fetchAll();
|
||||
// Make sure there's no migration exceptions.
|
||||
$this->assertEmpty($messages);
|
||||
// Make sure the default langcode is 'en', as it was the default on D6 & D7.
|
||||
$this->assertSame('en', $this->config('system.site')->get('default_langcode'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to test the migration.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The langcode of the default language.
|
||||
*/
|
||||
protected function setDefaultLanguage($langcode): void {
|
||||
// The default language of the test fixture is English. Change it to
|
||||
// something else before migrating, to be sure that the source site
|
||||
// default language is migrated.
|
||||
$value = 'O:8:"stdClass":11:{s:8:"language";s:2:"' . $langcode . '";s:4:"name";s:6:"French";s:6:"native";s:6:"French";s:9:"direction";s:1:"0";s:7:"enabled";i:1;s:7:"plurals";s:1:"0";s:7:"formula";s:0:"";s:6:"domain";s:0:"";s:6:"prefix";s:0:"";s:6:"weight";s:1:"0";s:10:"javascript";s:0:"";}';
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(['value' => $value])
|
||||
->condition('name', 'language_default')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\migrate\Kernel\MigrateDumpAlterInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests language content comment settings migration with no entity translation.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageContentCommentSettingsNoEntityTranslationTest extends MigrateDrupal7TestBase implements MigrateDumpAlterInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'comment',
|
||||
'content_translation',
|
||||
'language',
|
||||
'node',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->startCollectingMessages();
|
||||
$this->migrateCommentTypes();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_content_comment_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function migrateDumpAlter(KernelTestBase $test): void {
|
||||
// Disable comment entity translation.
|
||||
$db = Database::getConnection('default', 'migrate');
|
||||
|
||||
$db->update('variable')
|
||||
->condition('name', 'entity_translation_entity_types')
|
||||
->fields([
|
||||
'value' => 'a:4:{s:4:"node";s:4:"node";s:13:"taxonomy_term";i:0;s:7:"comment";i:0;s:4:"user";i:0;}',
|
||||
])
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of content language settings.
|
||||
*/
|
||||
public function testLanguageCommentSettings(): void {
|
||||
// Confirm there is no message about a missing bundle.
|
||||
$this->assertEmpty($this->migrateMessages, $this->migrateMessages['error'][0] ?? '');
|
||||
|
||||
// Article and Blog content type have multilingual settings of 'Enabled,
|
||||
// with Translation'. Assert that comments are translatable and the default
|
||||
// language is 'current_interface'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_article');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_article', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$third_party_settings = [
|
||||
'content_translation' => [
|
||||
'enabled' => FALSE,
|
||||
],
|
||||
];
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_blog');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_blog', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Page content type has multilingual settings of 'Enabled'. Assert that
|
||||
// comments are translatable and default language is 'current_interface'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_page');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_page', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// The content type with a long name has multilingual settings of 'Enabled'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_a_thirty_two_char');
|
||||
$this->assertFalse($config->isNew());
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_a_thirty_two_char', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Test content type has multilingual settings of 'Enabled, with field
|
||||
// translation'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_test_content_type');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_test_content_type', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$third_party_settings = [
|
||||
'content_translation' => [
|
||||
'enabled' => FALSE,
|
||||
],
|
||||
];
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Assert that non-translatable content is not translatable and the default
|
||||
// language is 'site_default.
|
||||
$not_translatable = [
|
||||
'comment_node_book',
|
||||
'comment_forum',
|
||||
];
|
||||
foreach ($not_translatable as $bundle) {
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', $bundle);
|
||||
$this->assertTrue($config->isDefaultConfiguration());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
$this->assertSame('site_default', $config->getDefaultLangcode(), "Default language is not 'site_default' for comment bundle $bundle");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of language comment settings.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageContentCommentSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'comment',
|
||||
'content_translation',
|
||||
'language',
|
||||
'node',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->startCollectingMessages();
|
||||
$this->migrateCommentTypes();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_content_comment_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of content language settings.
|
||||
*/
|
||||
public function testLanguageCommentSettings(): void {
|
||||
// Confirm there is no message about a missing bundle.
|
||||
$this->assertEmpty($this->migrateMessages, $this->migrateMessages['error'][0] ?? '');
|
||||
|
||||
// Article and Blog content type have multilingual settings of 'Enabled,
|
||||
// with Translation'. Assert that comments are translatable and the default
|
||||
// language is 'current_interface'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_article');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_article', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$third_party_settings = [
|
||||
'content_translation' => [
|
||||
'enabled' => FALSE,
|
||||
],
|
||||
];
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_blog');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_blog', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Page content type has multilingual settings of 'Enabled'. Assert that
|
||||
// comments are translatable and default language is 'current_interface'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_page');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_page', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// The content type with a long name has multilingual settings of 'Enabled'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_a_thirty_two_char');
|
||||
$this->assertFalse($config->isNew());
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_a_thirty_two_char', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Test content type has multilingual settings of 'Enabled, with field
|
||||
// translation'.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_node_test_content_type');
|
||||
$this->assertSame('comment', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('comment_node_test_content_type', $config->getTargetBundle());
|
||||
$this->assertSame('current_interface', $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$third_party_settings = [
|
||||
'content_translation' => [
|
||||
'enabled' => TRUE,
|
||||
],
|
||||
];
|
||||
$this->assertSame($third_party_settings, $config->get('third_party_settings'));
|
||||
|
||||
// Assert that non-translatable content is not translatable and the default
|
||||
// language is 'site_default.
|
||||
$not_translatable = [
|
||||
'comment_node_book',
|
||||
'comment_forum',
|
||||
];
|
||||
foreach ($not_translatable as $bundle) {
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('comment', $bundle);
|
||||
$this->assertTrue($config->isDefaultConfiguration());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
$this->assertSame('site_default', $config->getDefaultLangcode(), "Default language is not 'site_default' for comment bundle $bundle");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of i18n_menu settings.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageContentMenuSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'link',
|
||||
'menu_link_content',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('menu_link_content');
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_menu',
|
||||
'd7_language_content_menu_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of menu translation ability.
|
||||
*/
|
||||
public function testLanguageContentMenu(): void {
|
||||
$config = ContentLanguageSettings::load('menu_link_content.menu_link_content');
|
||||
$this->assertInstanceOf(ContentLanguageSettings::class, $config);
|
||||
$this->assertSame('menu_link_content', $config->getTargetEntityTypeId());
|
||||
$this->assertSame('menu_link_content', $config->getTargetBundle());
|
||||
$this->assertSame(LanguageInterface::LANGCODE_SITE_DEFAULT, $config->getDefaultLangcode());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$settings = [
|
||||
'enabled' => TRUE,
|
||||
'bundle_settings' => [
|
||||
'untranslatable_fields_hide' => '0',
|
||||
],
|
||||
];
|
||||
$this->assertSame($settings, $config->getThirdPartySettings('content_translation'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration of language-related settings.
|
||||
*
|
||||
* Settings tested include the language content setting variables,
|
||||
* language_content_type_$type, i18n_node_options_* and i18n_lock_node_*.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageContentSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'text',
|
||||
'language',
|
||||
'content_translation',
|
||||
'menu_ui',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->migrateContentTypes();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_content_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of content language settings.
|
||||
*/
|
||||
public function testLanguageContent(): void {
|
||||
// Assert that a translatable content is still translatable.
|
||||
$config = $this->config('language.content_settings.node.blog');
|
||||
$this->assertSame($config->get('target_entity_type_id'), 'node');
|
||||
$this->assertSame($config->get('target_bundle'), 'blog');
|
||||
$this->assertSame($config->get('default_langcode'), 'current_interface');
|
||||
$this->assertFalse($config->get('language_alterable'));
|
||||
$this->assertTrue($config->get('third_party_settings.content_translation.enabled'));
|
||||
|
||||
// Assert that a translatable content is translatable.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'page');
|
||||
$this->assertFalse($config->isDefaultConfiguration());
|
||||
$this->assertTrue($config->isLanguageAlterable());
|
||||
$this->assertSame($config->getDefaultLangcode(), 'current_interface');
|
||||
|
||||
// Assert that a non-translatable content is not translatable.
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'forum');
|
||||
$this->assertTrue($config->isDefaultConfiguration());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
$this->assertSame($config->getDefaultLangcode(), 'site_default');
|
||||
|
||||
// Make sure there's no migration exceptions.
|
||||
$messages = $this->migration->getIdMap()->getMessages()->fetchAll();
|
||||
$this->assertEmpty($messages);
|
||||
|
||||
// Assert that a content type translatable with entity_translation is still
|
||||
// translatable.
|
||||
$config = $this->config('language.content_settings.node.test_content_type');
|
||||
$this->assertTrue($config->get('third_party_settings.content_translation.enabled'));
|
||||
$this->assertSame($config->get('default_langcode'), 'und');
|
||||
|
||||
// Assert that a content type without a 'language_content_type' variable is
|
||||
// not translatable
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle('node', 'book');
|
||||
$this->assertTrue($config->isDefaultConfiguration());
|
||||
$this->assertFalse($config->isLanguageAlterable());
|
||||
$this->assertSame($config->getDefaultLangcode(), 'site_default');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of i18ntaxonomy vocabulary settings.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageContentTaxonomyVocabularySettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'content_translation',
|
||||
'taxonomy',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_taxonomy_vocabulary',
|
||||
'd7_language_content_taxonomy_vocabulary_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of 18ntaxonomy vocabulary settings.
|
||||
*/
|
||||
public function testLanguageContentTaxonomy(): void {
|
||||
$target_entity = 'taxonomy_term';
|
||||
// No multilingual options for terms, i18n_mode = 0.
|
||||
$this->assertLanguageContentSettings($target_entity, 'tags', LanguageInterface::LANGCODE_NOT_SPECIFIED, FALSE, ['enabled' => FALSE]);
|
||||
$this->assertLanguageContentSettings($target_entity, 'sujet_de_discussion', LanguageInterface::LANGCODE_NOT_SPECIFIED, FALSE, ['enabled' => FALSE]);
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabulary_name_much_longer_th', LanguageInterface::LANGCODE_NOT_SPECIFIED, FALSE, ['enabled' => FALSE]);
|
||||
$this->assertLanguageContentSettings($target_entity, 'test_vocabulary', LanguageInterface::LANGCODE_NOT_SPECIFIED, FALSE, ['enabled' => FALSE]);
|
||||
// Localize, i18n_mode = 1.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocablocalized', LanguageInterface::LANGCODE_NOT_SPECIFIED, TRUE, ['enabled' => TRUE]);
|
||||
// Translate, i18n_mode = 4.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabtranslate', LanguageInterface::LANGCODE_NOT_SPECIFIED, TRUE, ['enabled' => FALSE]);
|
||||
// Fixed language, i18n_mode = 2.
|
||||
$this->assertLanguageContentSettings($target_entity, 'vocabfixed', 'fr', FALSE, ['enabled' => FALSE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a content language settings configuration.
|
||||
*
|
||||
* @param string $target_entity
|
||||
* The expected target entity type.
|
||||
* @param string $bundle
|
||||
* The expected bundle.
|
||||
* @param string $default_langcode
|
||||
* The default language code.
|
||||
* @param bool $language_alterable
|
||||
* The expected state of language alterable.
|
||||
* @param array $third_party_settings
|
||||
* The content translation setting.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function assertLanguageContentSettings(string $target_entity, string $bundle, string $default_langcode, bool $language_alterable, array $third_party_settings): void {
|
||||
$config = ContentLanguageSettings::load($target_entity . '.' . $bundle);
|
||||
$this->assertInstanceOf(ContentLanguageSettings::class, $config);
|
||||
$this->assertSame($target_entity, $config->getTargetEntityTypeId());
|
||||
$this->assertSame($bundle, $config->getTargetBundle());
|
||||
$this->assertSame($default_langcode, $config->getDefaultLangcode());
|
||||
$this->assertSame($language_alterable, $config->isLanguageAlterable());
|
||||
$this->assertSame($third_party_settings, $config->getThirdPartySettings('content_translation'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration of language negotiation.
|
||||
*
|
||||
* @group #slow
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateLanguageNegotiationSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Tests migration of language types variables to language.types.yml.
|
||||
*/
|
||||
public function testLanguageTypes(): void {
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_negotiation_settings',
|
||||
'd7_language_types',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.types');
|
||||
$this->assertSame(['language_content', 'language_url', 'language_interface'], $config->get('all'));
|
||||
$this->assertSame(['language_content', 'language_interface'], $config->get('configurable'));
|
||||
$this->assertSame(['enabled' => ['language-interface' => 0]], $config->get('negotiation.language_content'));
|
||||
$this->assertSame(['enabled' => ['language-url' => 0, 'language-url-fallback' => 1]], $config->get('negotiation.language_url'));
|
||||
$expected_language_interface = [
|
||||
'enabled' => [
|
||||
'language-url' => -9,
|
||||
'language-user' => -10,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
'method_weights' => [
|
||||
'language-url' => -9,
|
||||
'language-session' => -8,
|
||||
'language-user' => -10,
|
||||
'language-browser' => -7,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
];
|
||||
$this->assertSame($expected_language_interface, $config->get('negotiation.language_interface'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with prefix negotiation.
|
||||
*/
|
||||
public function testLanguageNegotiationWithPrefix(): void {
|
||||
$this->sourceDatabase->update('languages')
|
||||
->fields(['domain' => ''])
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_PATH_PREFIX, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'fr' => 'fr',
|
||||
'is' => 'is',
|
||||
];
|
||||
$this->assertSame($expected_prefixes, $config->get('url.prefixes'));
|
||||
|
||||
// If prefix negotiation is used, make sure that no domains are migrated.
|
||||
// Otherwise there will be validation errors when trying to save URL
|
||||
// language detection configuration from the UI.
|
||||
$expected_domains = [
|
||||
'en' => '',
|
||||
'fr' => '',
|
||||
'is' => '',
|
||||
];
|
||||
$this->assertSame($expected_domains, $config->get('url.domains'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with domain negotiation.
|
||||
*/
|
||||
public function testLanguageNegotiationWithDomain(): void {
|
||||
$this->sourceDatabase->update('variable')
|
||||
->fields(['value' => serialize(1)])
|
||||
->condition('name', 'locale_language_negotiation_url_part')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
]);
|
||||
|
||||
global $base_url;
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_DOMAIN, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
$expected_domains = [
|
||||
'en' => parse_url($base_url, PHP_URL_HOST),
|
||||
'fr' => 'fr.drupal.org',
|
||||
'is' => 'is.drupal.org',
|
||||
];
|
||||
$this->assertSame($expected_domains, $config->get('url.domains'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration with non-existent variables.
|
||||
*/
|
||||
public function testLanguageNegotiationWithNonExistentVariables(): void {
|
||||
$this->sourceDatabase->delete('variable')
|
||||
->condition('name', ['local_language_negotiation_url_part', 'local_language_negotiation_session_param'], 'IN')
|
||||
->execute();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_language_negotiation_settings',
|
||||
'language_prefixes_and_domains',
|
||||
]);
|
||||
|
||||
$config = $this->config('language.negotiation');
|
||||
$this->assertSame('language', $config->get('session.parameter'));
|
||||
$this->assertSame(LanguageNegotiationUrl::CONFIG_PATH_PREFIX, $config->get('url.source'));
|
||||
$this->assertSame('site_default', $config->get('selected_langcode'));
|
||||
$expected_prefixes = [
|
||||
'en' => '',
|
||||
'fr' => 'fr',
|
||||
'is' => 'is',
|
||||
];
|
||||
$this->assertSame($expected_prefixes, $config->get('url.prefixes'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel;
|
||||
|
||||
use Drupal\Core\Config\ConfigImporter;
|
||||
use Drupal\Core\Config\StorageComparer;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests importing of config with language overrides.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class OverriddenConfigImportTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Config Importer object used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigImporter
|
||||
*/
|
||||
protected $configImporter;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['system']);
|
||||
$this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
|
||||
|
||||
// Set up the ConfigImporter object for testing.
|
||||
$storage_comparer = new StorageComparer(
|
||||
$this->container->get('config.storage.sync'),
|
||||
$this->container->get('config.storage')
|
||||
);
|
||||
$this->configImporter = new ConfigImporter(
|
||||
$storage_comparer->createChangelist(),
|
||||
$this->container->get('event_dispatcher'),
|
||||
$this->container->get('config.manager'),
|
||||
$this->container->get('lock'),
|
||||
$this->container->get('config.typed'),
|
||||
$this->container->get('module_handler'),
|
||||
$this->container->get('module_installer'),
|
||||
$this->container->get('theme_handler'),
|
||||
$this->container->get('string_translation'),
|
||||
$this->container->get('extension.list.module'),
|
||||
$this->container->get('extension.list.theme')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests importing overridden config alongside config in the default language.
|
||||
*/
|
||||
public function testConfigImportUpdates(): void {
|
||||
$storage = $this->container->get('config.storage');
|
||||
$sync = $this->container->get('config.storage.sync');
|
||||
/** @var \Drupal\language\ConfigurableLanguageManagerInterface $language_manager */
|
||||
$language_manager = $this->container->get('language_manager');
|
||||
|
||||
// Make a change to the site configuration in the default collection.
|
||||
$data = $storage->read('system.site');
|
||||
$data['name'] = 'English site name';
|
||||
$sync->write('system.site', $data);
|
||||
|
||||
// Also make a change to the same config object, but using a language
|
||||
// override.
|
||||
/** @var \Drupal\Core\Config\StorageInterface $overridden_sync */
|
||||
$overridden_sync = $sync->createCollection('language.fr');
|
||||
$overridden_sync->write('system.site', ['name' => 'French site name']);
|
||||
|
||||
// Before we start the import, the change to the site name should not be
|
||||
// present. This action also primes the cache in the config factory so that
|
||||
// we can test whether the cached data is correctly updated.
|
||||
$config = $this->config('system.site');
|
||||
$this->assertNotEquals('English site name', $config->getRawData()['name']);
|
||||
|
||||
// Before the import is started the site name should not yet be overridden.
|
||||
$this->assertFalse($config->hasOverrides());
|
||||
$override = $language_manager->getLanguageConfigOverride('fr', 'system.site');
|
||||
$this->assertTrue($override->isNew());
|
||||
|
||||
// Start the import of the new configuration.
|
||||
$this->configImporter->reset()->import();
|
||||
|
||||
// Verify the new site name in the default language.
|
||||
$config = $this->config('system.site')->getRawData();
|
||||
$this->assertEquals('English site name', $config['name']);
|
||||
|
||||
// Verify the overridden site name.
|
||||
$override = $language_manager->getLanguageConfigOverride('fr', 'system.site');
|
||||
$this->assertEquals('French site name', $override->get('name'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Plugin\migrate\source;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests the language source plugin.
|
||||
*
|
||||
* @covers \Drupal\language\Plugin\migrate\source\Language
|
||||
* @group language
|
||||
*/
|
||||
class LanguageTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['languages'] = [
|
||||
[
|
||||
'language' => 'en',
|
||||
'name' => 'English',
|
||||
'native' => 'English',
|
||||
'direction' => '0',
|
||||
'enabled' => '1',
|
||||
'plurals' => '0',
|
||||
'formula' => '',
|
||||
'domain' => '',
|
||||
'prefix' => '',
|
||||
'weight' => '0',
|
||||
'javascript' => '',
|
||||
],
|
||||
[
|
||||
'language' => 'fr',
|
||||
'name' => 'French',
|
||||
'native' => 'Français',
|
||||
'direction' => '0',
|
||||
'enabled' => '0',
|
||||
'plurals' => '2',
|
||||
'formula' => '($n>1)',
|
||||
'domain' => '',
|
||||
'prefix' => 'fr',
|
||||
'weight' => '0',
|
||||
'javascript' => '',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'language' => 'en',
|
||||
'name' => 'English',
|
||||
'native' => 'English',
|
||||
'direction' => '0',
|
||||
'enabled' => '1',
|
||||
'plurals' => '0',
|
||||
'formula' => '',
|
||||
'domain' => '',
|
||||
'prefix' => '',
|
||||
'weight' => '0',
|
||||
'javascript' => '',
|
||||
],
|
||||
[
|
||||
'language' => 'fr',
|
||||
'name' => 'French',
|
||||
'native' => 'Français',
|
||||
'direction' => '0',
|
||||
'enabled' => '0',
|
||||
'plurals' => '2',
|
||||
'formula' => '($n>1)',
|
||||
'domain' => '',
|
||||
'prefix' => 'fr',
|
||||
'weight' => '0',
|
||||
'javascript' => '',
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests menu source plugin.
|
||||
*
|
||||
* @covers \Drupal\language\Plugin\migrate\source\d6\LanguageContentSettings
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageContentSettingsTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['node_type'] = [
|
||||
[
|
||||
'type' => 'article',
|
||||
'name' => 'Article',
|
||||
'module' => 'node',
|
||||
'description' => 'An <em>article</em>, content type.',
|
||||
'help' => '',
|
||||
'has_title' => 1,
|
||||
'title_label' => 'Title',
|
||||
'has_body' => 1,
|
||||
'body_label' => 'Body',
|
||||
'min_word_count' => 0,
|
||||
'custom' => 1,
|
||||
'modified' => 1,
|
||||
'locked' => 0,
|
||||
'orig_type' => 'story',
|
||||
],
|
||||
[
|
||||
'type' => 'company',
|
||||
'name' => 'Company',
|
||||
'module' => 'node',
|
||||
'description' => 'Company node type',
|
||||
'help' => '',
|
||||
'has_title' => 1,
|
||||
'title_label' => 'Name',
|
||||
'has_body' => 1,
|
||||
'body_label' => 'Description',
|
||||
'min_word_count' => 0,
|
||||
'custom' => 0,
|
||||
'modified' => 1,
|
||||
'locked' => 0,
|
||||
'orig_type' => 'company',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($tests[0]['source_data']['node_type'] as $node_type) {
|
||||
$tests[0]['expected_data'][] = [
|
||||
'type' => $node_type['type'],
|
||||
'language_content_type' => NULL,
|
||||
'i18n_lock_node' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests i18ntaxonomy vocabulary setting source plugin.
|
||||
*
|
||||
* @covers \Drupal\language\Plugin\migrate\source\d6\LanguageContentSettingsTaxonomyVocabulary
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageContentTaxonomyVocabularySettingsTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'language', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'language' => '',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 1,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'language' => 'zu',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'i18ntaxonomy_vocabulary',
|
||||
'value' => 'a:4:{i:1;s:1:"3";i:2;s:1:"2";i:3;s:1:"3";i:5;s:1:"1";}',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'language' => '',
|
||||
'state' => 3,
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'language' => 'zu',
|
||||
'state' => 2,
|
||||
],
|
||||
];
|
||||
|
||||
// Test without a language column in the database.
|
||||
$tests[1] = $tests[0];
|
||||
foreach ($tests[1]['source_data']['vocabulary'] as $key => $row) {
|
||||
unset($tests[1]['source_data']['vocabulary'][$key]['language']);
|
||||
}
|
||||
$tests[1]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'i18ntaxonomy_vocabulary',
|
||||
'value' => 'a:4:{i:1;s:1:"0";i:2;s:1:"0";i:3;s:1:"3";i:5;s:1:"1";}',
|
||||
],
|
||||
];
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'state' => 0,
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'state' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// Test without a i18ntaxonomy_vocabulary variable.
|
||||
$tests[2] = $tests[1];
|
||||
unset($tests[2]['source_data']['variable']);
|
||||
return $tests;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests menu source plugin.
|
||||
*
|
||||
* @covers \Drupal\language\Plugin\migrate\source\d7\LanguageContentSettings
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageContentSettingsTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['node_type'] = [
|
||||
[
|
||||
'type' => 'article',
|
||||
'name' => 'Article',
|
||||
'base' => 'node_content',
|
||||
'module' => 'node',
|
||||
'description' => 'Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.',
|
||||
'help' => 'Help text for articles',
|
||||
'has_title' => 1,
|
||||
'title_label' => 'Title',
|
||||
'custom' => 1,
|
||||
'modified' => 1,
|
||||
'locked' => 0,
|
||||
'disabled' => 0,
|
||||
'orig_type' => 'article',
|
||||
],
|
||||
[
|
||||
'type' => 'blog',
|
||||
'name' => 'Blog entry',
|
||||
'base' => 'blog',
|
||||
'module' => 'blog',
|
||||
'description' => 'Use for multi-user blogs. Every user gets a personal blog.',
|
||||
'help' => 'Blog away, good sir!',
|
||||
'has_title' => 1,
|
||||
'title_label' => 'Title',
|
||||
'custom' => 0,
|
||||
'modified' => 1,
|
||||
'locked' => 1,
|
||||
'disabled' => 0,
|
||||
'orig_type' => 'blog',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($tests[0]['source_data']['node_type'] as $node_type) {
|
||||
$tests[0]['expected_data'][] = [
|
||||
'type' => $node_type['type'],
|
||||
'language_content_type' => NULL,
|
||||
'i18n_lock_node' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7\VocabularyTest;
|
||||
|
||||
/**
|
||||
* Tests i18ntaxonomy vocabulary setting source plugin.
|
||||
*
|
||||
* @covers \Drupal\language\Plugin\migrate\source\d7\LanguageContentSettingsTaxonomyVocabulary
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageContentTaxonomyVocabularySettingsTest extends VocabularyTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'language', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
// Get the source data from parent.
|
||||
$tests = parent::providerSource();
|
||||
|
||||
foreach ($tests as &$test) {
|
||||
// Add the extra columns provided by i18n_taxonomy.
|
||||
foreach ($test['source_data']['taxonomy_vocabulary'] as &$vocabulary) {
|
||||
$vocabulary['language'] = 'und';
|
||||
$vocabulary['i18n_mode'] = 2;
|
||||
}
|
||||
foreach ($test['expected_data'] as &$expected) {
|
||||
$expected['language'] = 'und';
|
||||
$expected['i18n_mode'] = 2;
|
||||
}
|
||||
}
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the argument language handler.
|
||||
*
|
||||
* @group language
|
||||
* @see \Drupal\language\Plugin\views\argument\Language.php
|
||||
*/
|
||||
class ArgumentLanguageTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Tests the language argument.
|
||||
*/
|
||||
public function testArgument(): void {
|
||||
$view = Views::getView('test_view');
|
||||
foreach (['en' => 'John', 'xx-lolspeak' => 'George'] as $langcode => $name) {
|
||||
$view->setDisplay();
|
||||
$view->displayHandlers->get('default')->overrideOption('arguments', [
|
||||
'langcode' => [
|
||||
'id' => 'langcode',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'langcode',
|
||||
],
|
||||
]);
|
||||
$this->executeView($view, [$langcode]);
|
||||
|
||||
$expected = [
|
||||
['name' => $name],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected, ['views_test_data_name' => 'name']);
|
||||
$view->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the field language handler.
|
||||
*
|
||||
* @group language
|
||||
* @see \Drupal\language\Plugin\views\field\Language
|
||||
*/
|
||||
class FieldLanguageTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Tests the language field.
|
||||
*/
|
||||
public function testField(): void {
|
||||
$view = Views::getView('test_view');
|
||||
$view->setDisplay();
|
||||
$view->displayHandlers->get('default')->overrideOption('fields', [
|
||||
'langcode' => [
|
||||
'id' => 'langcode',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'langcode',
|
||||
],
|
||||
]);
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEquals('English', $view->field['langcode']->advancedRender($view->result[0]));
|
||||
$this->assertEquals('Lolspeak', $view->field['langcode']->advancedRender($view->result[1]));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the filter language handler.
|
||||
*
|
||||
* @group language
|
||||
* @see \Drupal\language\Plugin\views\filter\Language
|
||||
*/
|
||||
class FilterLanguageTest extends LanguageTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Tests the language filter.
|
||||
*/
|
||||
public function testFilter(): void {
|
||||
$view = Views::getView('test_view');
|
||||
foreach (['en' => 'John', 'xx-lolspeak' => 'George'] as $langcode => $name) {
|
||||
$view->setDisplay();
|
||||
$view->displayHandlers->get('default')->overrideOption('filters', [
|
||||
'langcode' => [
|
||||
'id' => 'langcode',
|
||||
'table' => 'views_test_data',
|
||||
'field' => 'langcode',
|
||||
'value' => [$langcode => $langcode],
|
||||
],
|
||||
]);
|
||||
$this->executeView($view);
|
||||
|
||||
$expected = [
|
||||
['name' => $name],
|
||||
];
|
||||
$this->assertIdenticalResultset($view, $expected, ['views_test_data_name' => 'name']);
|
||||
|
||||
$expected = [
|
||||
'***LANGUAGE_site_default***',
|
||||
'***LANGUAGE_language_interface***',
|
||||
'en',
|
||||
'xx-lolspeak',
|
||||
'und',
|
||||
'zxx',
|
||||
];
|
||||
$this->assertSame($expected, array_keys($view->filter['langcode']->getValueOptions()));
|
||||
|
||||
$view->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Kernel\Views;
|
||||
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
|
||||
/**
|
||||
* Defines the base class for all Language handler tests.
|
||||
*/
|
||||
abstract class LanguageTestBase extends ViewsKernelTestBase {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE): void {
|
||||
parent::setUp();
|
||||
$this->installConfig(['language']);
|
||||
|
||||
// Create another language beside English.
|
||||
ConfigurableLanguage::create(['id' => 'xx-lolspeak', 'label' => 'Lolspeak'])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function schemaDefinition() {
|
||||
$schema = parent::schemaDefinition();
|
||||
$schema['views_test_data']['fields']['langcode'] = [
|
||||
'description' => 'The {language}.langcode of this beatle.',
|
||||
'type' => 'varchar',
|
||||
'length' => 12,
|
||||
'default' => '',
|
||||
];
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function viewsData() {
|
||||
$data = parent::viewsData();
|
||||
$data['views_test_data']['langcode'] = [
|
||||
'title' => $this->t('Langcode'),
|
||||
'help' => $this->t('Langcode'),
|
||||
'field' => [
|
||||
'id' => 'language',
|
||||
],
|
||||
'argument' => [
|
||||
'id' => 'language',
|
||||
],
|
||||
'filter' => [
|
||||
'id' => 'language',
|
||||
],
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function dataSet() {
|
||||
$data = parent::dataSet();
|
||||
$data[0]['langcode'] = 'en';
|
||||
$data[1]['langcode'] = 'xx-lolspeak';
|
||||
$data[2]['langcode'] = '';
|
||||
$data[3]['langcode'] = '';
|
||||
$data[4]['langcode'] = '';
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Traits;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\language\ConfigurableLanguageInterface;
|
||||
use Drupal\language\ContentLanguageSettingsInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
|
||||
/**
|
||||
* Provides an API to programmatically manage languages in tests.
|
||||
*/
|
||||
trait LanguageTestTrait {
|
||||
|
||||
/**
|
||||
* Creates a configurable language object from a langcode.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code to use to create the object.
|
||||
*
|
||||
* @return \Drupal\Core\Language\ConfigurableLanguageInterface
|
||||
* The created language.
|
||||
*
|
||||
* @see \Drupal\Core\Language\LanguageManager::getStandardLanguageList()
|
||||
*/
|
||||
public static function createLanguageFromLangcode(string $langcode): ConfigurableLanguageInterface {
|
||||
$configurable_language = ConfigurableLanguage::createFromLangcode($langcode);
|
||||
$configurable_language->save();
|
||||
return $configurable_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables translations for the given entity type bundle.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The ID of the entity type.
|
||||
* @param string $bundle
|
||||
* The bundle name.
|
||||
* @param string|null $default_langcode
|
||||
* The language code to use as the default language.
|
||||
*
|
||||
* @return \Drupal\language\ContentLanguageSettingsInterface
|
||||
* The saved content language config entity.
|
||||
*/
|
||||
public static function enableBundleTranslation(string $entity_type_id, string $bundle, ?string $default_langcode = LanguageInterface::LANGCODE_SITE_DEFAULT): ContentLanguageSettingsInterface {
|
||||
$content_language_settings = ContentLanguageSettings::loadByEntityTypeBundle($entity_type_id, $bundle)
|
||||
->setDefaultLangcode($default_langcode)
|
||||
->setLanguageAlterable(TRUE);
|
||||
$content_language_settings->save();
|
||||
return $content_language_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables translations for the given entity type bundle.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The ID of the entity type.
|
||||
* @param string $bundle
|
||||
* The bundle name.
|
||||
*/
|
||||
public static function disableBundleTranslation(string $entity_type_id, string $bundle): void {
|
||||
// @todo Move to API call when it exists, to be added at
|
||||
// https://www.drupal.org/project/drupal/issues/3408046
|
||||
$content_language_settings = ContentLanguageSettings::loadByEntityTypeBundle($entity_type_id, $bundle);
|
||||
$content_language_settings->setLanguageAlterable(FALSE)
|
||||
->save();
|
||||
$content_language_settings->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and saves a given field instance translation status.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The ID of the entity type.
|
||||
* @param string $bundle
|
||||
* The bundle name.
|
||||
* @param string $field_name
|
||||
* The name of the field.
|
||||
* @param bool $status
|
||||
* Whether the field should be translatable or not.
|
||||
*/
|
||||
public static function setFieldTranslatable(string $entity_type_id, string $bundle, string $field_name, bool $status): void {
|
||||
FieldConfig::loadByName($entity_type_id, $bundle, $field_name)
|
||||
->setTranslatable($status)
|
||||
->save();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\Config;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\language\Config\LanguageConfigOverride;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Config\LanguageConfigOverride
|
||||
* @group Config
|
||||
* @group language
|
||||
*/
|
||||
class LanguageConfigOverrideTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Language configuration override.
|
||||
*
|
||||
* @var \Drupal\language\Config\LanguageConfigOverride
|
||||
*/
|
||||
protected $configTranslation;
|
||||
|
||||
/**
|
||||
* Storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\StorageInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* Event Dispatcher.
|
||||
*
|
||||
* @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
* Typed Config.
|
||||
*
|
||||
* @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $typedConfig;
|
||||
|
||||
/**
|
||||
* The mocked cache tags invalidator.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $cacheTagsInvalidator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->storage = $this->createMock('Drupal\Core\Config\StorageInterface');
|
||||
$this->eventDispatcher = $this->createMock('Symfony\Contracts\EventDispatcher\EventDispatcherInterface');
|
||||
$this->typedConfig = $this->createMock('\Drupal\Core\Config\TypedConfigManagerInterface');
|
||||
$this->configTranslation = new LanguageConfigOverride('config.test', $this->storage, $this->typedConfig, $this->eventDispatcher);
|
||||
$this->cacheTagsInvalidator = $this->createMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::save
|
||||
*/
|
||||
public function testSaveNew(): void {
|
||||
$this->cacheTagsInvalidator->expects($this->once())
|
||||
->method('invalidateTags')
|
||||
->with(['config:config.test']);
|
||||
$this->assertTrue($this->configTranslation->isNew());
|
||||
$this->configTranslation->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::save
|
||||
*/
|
||||
public function testSaveExisting(): void {
|
||||
$this->cacheTagsInvalidator->expects($this->once())
|
||||
->method('invalidateTags')
|
||||
->with(['config:config.test']);
|
||||
$this->configTranslation->initWithData([]);
|
||||
$this->configTranslation->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::delete
|
||||
*/
|
||||
public function testDelete(): void {
|
||||
$this->cacheTagsInvalidator->expects($this->once())
|
||||
->method('invalidateTags')
|
||||
->with(['config:config.test']);
|
||||
$this->configTranslation->initWithData([]);
|
||||
$this->configTranslation->delete();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests the ConfigurableLanguage entity class.
|
||||
*
|
||||
* @group language
|
||||
* @coversDefaultClass \Drupal\language\Entity\ConfigurableLanguage
|
||||
* @see \Drupal\language\Entity\ConfigurableLanguage.
|
||||
*/
|
||||
class ConfigurableLanguageUnitTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::getDirection
|
||||
*/
|
||||
public function testDirection(): void {
|
||||
// Direction of language writing, an integer. Usually either
|
||||
// ConfigurableLanguage::DIRECTION_LTR or
|
||||
// ConfigurableLanguage::DIRECTION_RTL.
|
||||
$configurableLanguage = new ConfigurableLanguage(['direction' => ConfigurableLanguage::DIRECTION_LTR], 'configurable_language');
|
||||
$this->assertEquals(ConfigurableLanguage::DIRECTION_LTR, $configurableLanguage->getDirection());
|
||||
|
||||
// Test direction again, setting direction to RTL.
|
||||
$configurableLanguage = new ConfigurableLanguage(['direction' => ConfigurableLanguage::DIRECTION_RTL], 'configurable_language');
|
||||
$this->assertEquals(ConfigurableLanguage::DIRECTION_RTL, $configurableLanguage->getDirection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getWeight
|
||||
* @covers ::setWeight
|
||||
*/
|
||||
public function testWeight(): void {
|
||||
// The weight, an integer. Used to order languages with larger positive
|
||||
// weights sinking items toward the bottom of lists.
|
||||
$configurableLanguage = new ConfigurableLanguage(['weight' => -5], 'configurable_language');
|
||||
$this->assertEquals(-5, $configurableLanguage->getWeight());
|
||||
$this->assertEquals(13, $configurableLanguage->setWeight(13)->getWeight());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeRepositoryInterface;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\TestTools\Random;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Entity\ContentLanguageSettings
|
||||
* @group language
|
||||
*/
|
||||
class ContentLanguageSettingsUnitTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The entity type used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The entity type manager used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The ID of the type of the entity under test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityTypeId;
|
||||
|
||||
/**
|
||||
* The UUID generator used for testing.
|
||||
*
|
||||
* @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The typed configuration manager used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $typedConfigManager;
|
||||
|
||||
/**
|
||||
* The typed configuration manager used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Entity\ConfigEntityStorage|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $configEntityStorageInterface;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->entityTypeId = $this->randomMachineName();
|
||||
$this->entityType = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface');
|
||||
|
||||
$this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
|
||||
|
||||
$this->uuid = $this->createMock('\Drupal\Component\Uuid\UuidInterface');
|
||||
|
||||
$this->typedConfigManager = $this->createMock('Drupal\Core\Config\TypedConfigManagerInterface');
|
||||
|
||||
$this->configEntityStorageInterface = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('entity_type.manager', $this->entityTypeManager);
|
||||
$container->set('uuid', $this->uuid);
|
||||
$container->set('config.typed', $this->typedConfigManager);
|
||||
$container->set('config.storage', $this->configEntityStorageInterface);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::calculateDependencies
|
||||
*/
|
||||
public function testCalculateDependencies(): void {
|
||||
// Mock the interfaces necessary to create a dependency on a bundle entity.
|
||||
$target_entity_type = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface');
|
||||
$target_entity_type->expects($this->any())
|
||||
->method('getBundleConfigDependency')
|
||||
->willReturn(['type' => 'config', 'name' => 'test.test_entity_type.id']);
|
||||
|
||||
$this->entityTypeManager->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with('test_entity_type')
|
||||
->willReturn($target_entity_type);
|
||||
|
||||
$config = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$dependencies = $config->calculateDependencies()->getDependencies();
|
||||
$this->assertContains('test.test_entity_type.id', $dependencies['config']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::id
|
||||
*/
|
||||
public function testId(): void {
|
||||
$config = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$this->assertSame('test_entity_type.test_bundle', $config->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getTargetEntityTypeId
|
||||
*/
|
||||
public function testTargetEntityTypeId(): void {
|
||||
$config = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$this->assertSame('test_entity_type', $config->getTargetEntityTypeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getTargetBundle
|
||||
*/
|
||||
public function testTargetBundle(): void {
|
||||
$config = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$this->assertSame('test_bundle', $config->getTargetBundle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getDefaultLangcode
|
||||
* @covers ::setDefaultLangcode
|
||||
*
|
||||
* @dataProvider providerDefaultLangcode
|
||||
*/
|
||||
public function testDefaultLangcode(ContentLanguageSettings $config, $expected): void {
|
||||
$this->assertSame($expected, $config->getDefaultLangcode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to testDefaultLangcode().
|
||||
*/
|
||||
public static function providerDefaultLangcode() {
|
||||
$langcode = Random::machineName();
|
||||
$config = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$config->setDefaultLangcode($langcode);
|
||||
|
||||
$defaultConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_default_language_bundle',
|
||||
], 'language_content_settings');
|
||||
|
||||
return [
|
||||
[$config, $langcode],
|
||||
[$defaultConfig, LanguageInterface::LANGCODE_SITE_DEFAULT],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setLanguageAlterable
|
||||
* @covers ::isLanguageAlterable
|
||||
*
|
||||
* @dataProvider providerLanguageAlterable
|
||||
*/
|
||||
public function testLanguageAlterable(ContentLanguageSettings $config, $expected): void {
|
||||
$this->assertSame($expected, $config->isLanguageAlterable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to testLanguageAlterable().
|
||||
*/
|
||||
public static function providerLanguageAlterable() {
|
||||
$alterableConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$alterableConfig->setLanguageAlterable(TRUE);
|
||||
|
||||
$nonAlterableConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_fixed_language_bundle',
|
||||
], 'language_content_settings');
|
||||
$nonAlterableConfig->setLanguageAlterable(FALSE);
|
||||
|
||||
$defaultConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_default_language_bundle',
|
||||
], 'language_content_settings');
|
||||
|
||||
return [
|
||||
[$alterableConfig, TRUE],
|
||||
[$nonAlterableConfig, FALSE],
|
||||
[$defaultConfig, FALSE],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isDefaultConfiguration
|
||||
*
|
||||
* @dataProvider providerIsDefaultConfiguration
|
||||
*/
|
||||
public function testIsDefaultConfiguration(ContentLanguageSettings $config, $expected): void {
|
||||
$this->assertSame($expected, $config->isDefaultConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to testIsDefaultConfiguration().
|
||||
*/
|
||||
public static function providerIsDefaultConfiguration() {
|
||||
$alteredLanguage = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$alteredLanguage->setLanguageAlterable(TRUE);
|
||||
|
||||
$alteredDefaultLangcode = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_fixed_language_bundle',
|
||||
], 'language_content_settings');
|
||||
$alteredDefaultLangcode->setDefaultLangcode(Random::machineName());
|
||||
|
||||
$defaultConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_default_language_bundle',
|
||||
], 'language_content_settings');
|
||||
|
||||
return [
|
||||
[$alteredLanguage, FALSE],
|
||||
[$alteredDefaultLangcode, FALSE],
|
||||
[$defaultConfig, TRUE],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::loadByEntityTypeBundle
|
||||
*
|
||||
* @dataProvider providerLoadByEntityTypeBundle
|
||||
*/
|
||||
public function testLoadByEntityTypeBundle($config_id, ?ContentLanguageSettings $existing_config, $expected_langcode, $expected_language_alterable): void {
|
||||
[$type, $bundle] = explode('.', $config_id);
|
||||
|
||||
$nullConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => $type,
|
||||
'target_bundle' => $bundle,
|
||||
], 'language_content_settings');
|
||||
$this->configEntityStorageInterface
|
||||
->expects($this->any())
|
||||
->method('load')
|
||||
->with($config_id)
|
||||
->willReturn($existing_config);
|
||||
$this->configEntityStorageInterface
|
||||
->expects($this->any())
|
||||
->method('create')
|
||||
->willReturn($nullConfig);
|
||||
|
||||
$this->entityTypeManager
|
||||
->expects($this->any())
|
||||
->method('getStorage')
|
||||
->with('language_content_settings')
|
||||
->willReturn($this->configEntityStorageInterface);
|
||||
|
||||
$entity_type_repository = $this->createMock(EntityTypeRepositoryInterface::class);
|
||||
$entity_type_repository->expects($this->any())
|
||||
->method('getEntityTypeFromClass')
|
||||
->with(ContentLanguageSettings::class)
|
||||
->willReturn('language_content_settings');
|
||||
|
||||
\Drupal::getContainer()->set('entity_type.repository', $entity_type_repository);
|
||||
|
||||
$config = ContentLanguageSettings::loadByEntityTypeBundle($type, $bundle);
|
||||
|
||||
$this->assertSame($expected_langcode, $config->getDefaultLangcode());
|
||||
$this->assertSame($expected_language_alterable, $config->isLanguageAlterable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to testLoadByEntityTypeBundle().
|
||||
*/
|
||||
public static function providerLoadByEntityTypeBundle() {
|
||||
$alteredLanguage = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_bundle',
|
||||
], 'language_content_settings');
|
||||
$alteredLanguage->setLanguageAlterable(TRUE);
|
||||
|
||||
$langcode = Random::machineName();
|
||||
$alteredDefaultLangcode = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_fixed_language_bundle',
|
||||
], 'language_content_settings');
|
||||
$alteredDefaultLangcode->setDefaultLangcode($langcode);
|
||||
|
||||
$defaultConfig = new ContentLanguageSettings([
|
||||
'target_entity_type_id' => 'test_entity_type',
|
||||
'target_bundle' => 'test_default_language_bundle',
|
||||
], 'language_content_settings');
|
||||
|
||||
return [
|
||||
['test_entity_type.test_bundle', $alteredLanguage, LanguageInterface::LANGCODE_SITE_DEFAULT, TRUE],
|
||||
['test_entity_type.test_fixed_language_bundle', $alteredDefaultLangcode, $langcode, FALSE],
|
||||
['test_entity_type.test_default_language_bundle', $defaultConfig, LanguageInterface::LANGCODE_SITE_DEFAULT, FALSE],
|
||||
['test_entity_type.null_bundle', NULL, LanguageInterface::LANGCODE_SITE_DEFAULT, FALSE],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationUrlTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* The test user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* An array of languages.
|
||||
*/
|
||||
protected array $languages;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Set up some languages to be used by the language-based path processor.
|
||||
$language_de = $this->createMock('\Drupal\Core\Language\LanguageInterface');
|
||||
$language_de->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn('de');
|
||||
$language_en = $this->createMock('\Drupal\Core\Language\LanguageInterface');
|
||||
$language_en->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn('en');
|
||||
$languages = [
|
||||
'de' => $language_de,
|
||||
'en' => $language_en,
|
||||
];
|
||||
$this->languages = $languages;
|
||||
|
||||
// Create a language manager stub.
|
||||
$language_manager = $this->getMockBuilder('Drupal\language\ConfigurableLanguageManagerInterface')
|
||||
->getMock();
|
||||
$language_manager->expects($this->any())
|
||||
->method('getLanguages')
|
||||
->willReturn($languages);
|
||||
$this->languageManager = $language_manager;
|
||||
|
||||
// Create a user stub.
|
||||
$this->user = $this->getMockBuilder('Drupal\Core\Session\AccountInterface')
|
||||
->getMock();
|
||||
|
||||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests path prefix language negotiation and outbound path processing.
|
||||
*
|
||||
* @dataProvider providerTestPathPrefix
|
||||
*/
|
||||
public function testPathPrefix($prefix, $prefixes, $expected_langcode): void {
|
||||
$this->languageManager->expects($this->any())
|
||||
->method('getCurrentLanguage')
|
||||
->willReturn($this->languages[(in_array($expected_langcode, [
|
||||
'en',
|
||||
'de',
|
||||
])) ? $expected_langcode : 'en']);
|
||||
|
||||
$config = $this->getConfigFactoryStub([
|
||||
'language.negotiation' => [
|
||||
'url' => [
|
||||
'source' => LanguageNegotiationUrl::CONFIG_PATH_PREFIX,
|
||||
'prefixes' => $prefixes,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$request = Request::create('/' . $prefix . '/foo', 'GET');
|
||||
$method = new LanguageNegotiationUrl();
|
||||
$method->setLanguageManager($this->languageManager);
|
||||
$method->setConfig($config);
|
||||
$method->setCurrentUser($this->user);
|
||||
$this->assertEquals($expected_langcode, $method->getLangcode($request));
|
||||
|
||||
$cacheability = new BubbleableMetadata();
|
||||
$options = [];
|
||||
$method->processOutbound('foo', $options, $request, $cacheability);
|
||||
$expected_cacheability = new BubbleableMetadata();
|
||||
if ($expected_langcode) {
|
||||
$this->assertSame($prefix . '/', $options['prefix']);
|
||||
$expected_cacheability->setCacheContexts(['languages:' . LanguageInterface::TYPE_URL]);
|
||||
}
|
||||
else {
|
||||
$this->assertFalse(isset($options['prefix']));
|
||||
}
|
||||
$this->assertEquals($expected_cacheability, $cacheability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for the path prefix test.
|
||||
*
|
||||
* @return array
|
||||
* An array of data for checking path prefix negotiation.
|
||||
*/
|
||||
public static function providerTestPathPrefix() {
|
||||
$path_prefix_configuration[] = [
|
||||
'prefix' => 'de',
|
||||
'prefixes' => [
|
||||
'de' => 'de',
|
||||
'en-uk' => 'en',
|
||||
],
|
||||
'expected_langcode' => 'de',
|
||||
];
|
||||
$path_prefix_configuration[] = [
|
||||
'prefix' => 'en-uk',
|
||||
'prefixes' => [
|
||||
'de' => 'de',
|
||||
'en' => 'en-uk',
|
||||
],
|
||||
'expected_langcode' => 'en',
|
||||
];
|
||||
// No configuration.
|
||||
$path_prefix_configuration[] = [
|
||||
'prefix' => 'de',
|
||||
'prefixes' => [],
|
||||
'expected_langcode' => FALSE,
|
||||
];
|
||||
// Non-matching prefix.
|
||||
$path_prefix_configuration[] = [
|
||||
'prefix' => 'de',
|
||||
'prefixes' => [
|
||||
'en-uk' => 'en',
|
||||
],
|
||||
'expected_langcode' => FALSE,
|
||||
];
|
||||
// Non-existing language.
|
||||
$path_prefix_configuration[] = [
|
||||
'prefix' => 'it',
|
||||
'prefixes' => [
|
||||
'it' => 'it',
|
||||
'en-uk' => 'en',
|
||||
],
|
||||
'expected_langcode' => FALSE,
|
||||
];
|
||||
return $path_prefix_configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests outbound path processing for neutral languages.
|
||||
*
|
||||
* @dataProvider providerNeutralLanguages
|
||||
*/
|
||||
public function testNeutralLanguages($langcode, $expected_langcode): void {
|
||||
if ($expected_langcode) {
|
||||
$this->languageManager->expects($this->once())
|
||||
->method('getCurrentLanguage')
|
||||
->willReturn($this->languages['en']);
|
||||
}
|
||||
|
||||
$config = $this->getConfigFactoryStub([
|
||||
'language.negotiation' => [
|
||||
'url' => [
|
||||
'source' => LanguageNegotiationUrl::CONFIG_PATH_PREFIX,
|
||||
'prefixes' => [
|
||||
'de' => 'de',
|
||||
'en' => 'en',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$request = Request::create('/foo', 'GET');
|
||||
$method = new LanguageNegotiationUrl();
|
||||
$method->setLanguageManager($this->languageManager);
|
||||
$method->setConfig($config);
|
||||
$method->setCurrentUser($this->user);
|
||||
$this->assertNull($method->getLangcode($request));
|
||||
|
||||
$language = $this->createMock(LanguageInterface::class);
|
||||
$language->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn($langcode);
|
||||
$cacheability = new BubbleableMetadata();
|
||||
$options = [
|
||||
'language' => $language,
|
||||
];
|
||||
$method->processOutbound('foo', $options, $request, $cacheability);
|
||||
$expected_cacheability = new BubbleableMetadata();
|
||||
if ($expected_langcode) {
|
||||
$this->assertSame($expected_langcode . '/', $options['prefix']);
|
||||
$expected_cacheability->setCacheContexts(['languages:' . LanguageInterface::TYPE_URL]);
|
||||
}
|
||||
else {
|
||||
$this->assertFalse(isset($options['prefix']));
|
||||
}
|
||||
$this->assertEquals($expected_cacheability, $cacheability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for the neutral language test.
|
||||
*
|
||||
* @return array
|
||||
* An array of data for checking path prefix negotiation for neutral
|
||||
* languages.
|
||||
*/
|
||||
public static function providerNeutralLanguages() {
|
||||
return [
|
||||
[LanguageInterface::LANGCODE_NOT_APPLICABLE, NULL],
|
||||
[LanguageInterface::LANGCODE_NOT_SPECIFIED, 'en'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests domain language negotiation and outbound path processing.
|
||||
*
|
||||
* @dataProvider providerTestDomain
|
||||
*/
|
||||
public function testDomain($http_host, $domains, $expected_langcode): void {
|
||||
$this->languageManager->expects($this->any())
|
||||
->method('getCurrentLanguage')
|
||||
->willReturn($this->languages['en']);
|
||||
|
||||
$config = $this->getConfigFactoryStub([
|
||||
'language.negotiation' => [
|
||||
'url' => [
|
||||
'source' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domains' => $domains,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$request = Request::create('', 'GET', [], [], [], ['HTTP_HOST' => $http_host]);
|
||||
$method = new LanguageNegotiationUrl();
|
||||
$method->setLanguageManager($this->languageManager);
|
||||
$method->setConfig($config);
|
||||
$method->setCurrentUser($this->user);
|
||||
$this->assertEquals($expected_langcode, $method->getLangcode($request));
|
||||
|
||||
$cacheability = new BubbleableMetadata();
|
||||
$options = [];
|
||||
$this->assertSame('foo', $method->processOutbound('foo', $options, $request, $cacheability));
|
||||
$expected_cacheability = new BubbleableMetadata();
|
||||
if ($expected_langcode !== FALSE && count($domains) > 1) {
|
||||
$expected_cacheability->setCacheMaxAge(
|
||||
Cache::PERMANENT)->setCacheContexts(['languages:' . LanguageInterface::TYPE_URL, 'url.site']);
|
||||
}
|
||||
$this->assertEquals($expected_cacheability, $cacheability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for the domain test.
|
||||
*
|
||||
* @return array
|
||||
* An array of data for checking domain negotiation.
|
||||
*/
|
||||
public static function providerTestDomain() {
|
||||
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.de',
|
||||
'domains' => [
|
||||
'de' => 'http://example.de',
|
||||
],
|
||||
'expected_langcode' => 'de',
|
||||
];
|
||||
// No configuration.
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.de',
|
||||
'domains' => [],
|
||||
'expected_langcode' => FALSE,
|
||||
];
|
||||
// HTTP host with a port.
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.de:8080',
|
||||
'domains' => [
|
||||
'de' => 'http://example.de',
|
||||
],
|
||||
'expected_langcode' => 'de',
|
||||
];
|
||||
// Domain configuration with https://.
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.de',
|
||||
'domains' => [
|
||||
'de' => 'https://example.de',
|
||||
],
|
||||
'expected_langcode' => 'de',
|
||||
];
|
||||
// Non-matching HTTP host.
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.com',
|
||||
'domains' => [
|
||||
'de' => 'http://example.com',
|
||||
],
|
||||
'expected_langcode' => 'de',
|
||||
];
|
||||
// Testing a non-existing language.
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.com',
|
||||
'domains' => [
|
||||
'it' => 'http://example.it',
|
||||
],
|
||||
'expected_langcode' => FALSE,
|
||||
];
|
||||
// Multiple domain configurations.
|
||||
$domain_configuration[] = [
|
||||
'http_host' => 'example.com',
|
||||
'domains' => [
|
||||
'de' => 'http://example.de',
|
||||
'en' => 'http://example.com',
|
||||
],
|
||||
'expected_langcode' => 'en',
|
||||
];
|
||||
return $domain_configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests path outbound processing correctly setting relative/absolute paths.
|
||||
*/
|
||||
public function testProcessOutboundOutputsRelativePathsForSameDomain(): void {
|
||||
$this->languageManager->expects($this->any())
|
||||
->method('getCurrentLanguage')
|
||||
->willReturn($this->languages['en']);
|
||||
|
||||
$config = $this->getConfigFactoryStub([
|
||||
'language.negotiation' => [
|
||||
'url' => [
|
||||
'source' => LanguageNegotiationUrl::CONFIG_DOMAIN,
|
||||
'domains' => [
|
||||
'de' => 'example.de',
|
||||
'en' => 'example.com',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$request = Request::create('', 'GET', [], [], [], ['HTTP_HOST' => 'example.com']);
|
||||
$method = new LanguageNegotiationUrl();
|
||||
$method->setLanguageManager($this->languageManager);
|
||||
$method->setConfig($config);
|
||||
$method->setCurrentUser($this->user);
|
||||
|
||||
// Check relative paths are used when the language
|
||||
// is the current language.
|
||||
$options = [
|
||||
'language' => $this->languages['en'],
|
||||
];
|
||||
$method->processOutbound('foo', $options, $request);
|
||||
// $options['absolute'] not set or null equals to FALSE.
|
||||
$this->assertFalse($options['absolute'] ?? FALSE);
|
||||
|
||||
// Check absolute paths are used when the language
|
||||
// is not the current language.
|
||||
$options = [
|
||||
'language' => $this->languages['de'],
|
||||
];
|
||||
$method->processOutbound('foo', $options, $request);
|
||||
$this->assertTrue($options['absolute']);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @todo Remove as part of https://www.drupal.org/node/2481833.
|
||||
namespace Drupal\language\Plugin\LanguageNegotiation;
|
||||
|
||||
if (!function_exists('base_path')) {
|
||||
|
||||
/**
|
||||
* Returns the base path.
|
||||
*/
|
||||
function base_path() {
|
||||
return '/';
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\Menu;
|
||||
|
||||
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTestBase;
|
||||
|
||||
/**
|
||||
* Tests existence of language local tasks.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
class LanguageLocalTasksTest extends LocalTaskIntegrationTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->directoryList = [
|
||||
'language' => 'core/modules/language',
|
||||
];
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language admin overview local tasks existence.
|
||||
*
|
||||
* @dataProvider getLanguageAdminOverviewRoutes
|
||||
*/
|
||||
public function testLanguageAdminLocalTasks($route, $expected): void {
|
||||
$this->assertLocalTasks($route, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of routes to test.
|
||||
*/
|
||||
public static function getLanguageAdminOverviewRoutes() {
|
||||
return [
|
||||
['entity.configurable_language.collection', [['entity.configurable_language.collection', 'language.negotiation']]],
|
||||
['language.negotiation', [['entity.configurable_language.collection', 'language.negotiation']]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language edit local tasks existence.
|
||||
*/
|
||||
public function testLanguageEditLocalTasks(): void {
|
||||
$this->assertLocalTasks('entity.configurable_language.edit_form', [
|
||||
0 => ['entity.configurable_language.edit_form'],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\Plugin\LanguageNegotiation;
|
||||
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\EntityTypeManager;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\ConfigurableLanguageManagerInterface;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity;
|
||||
use Symfony\Component\HttpFoundation\InputBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\ServerBag;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Tests the LanguageNegotiationContentEntity plugin class.
|
||||
*
|
||||
* @group language
|
||||
* @coversDefaultClass \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity
|
||||
* @see \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity
|
||||
*/
|
||||
class LanguageNegotiationContentEntityTest extends LanguageNegotiationTestBase {
|
||||
|
||||
/**
|
||||
* An array of mock LanguageInterface objects.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageInterface
|
||||
*/
|
||||
protected array $languages;
|
||||
|
||||
/**
|
||||
* A mock LanguageManager object.
|
||||
*
|
||||
* @var \Drupal\language\ConfigurableLanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getPluginClass(): string {
|
||||
return LanguageNegotiationContentEntity::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Set up some languages to be used by the language-based path processor.
|
||||
$language_de = $this->createMock(LanguageInterface::class);
|
||||
$language_de->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn('de');
|
||||
$language_de->expects($this->any())
|
||||
->method('getName')
|
||||
->willReturn('German');
|
||||
$language_en = $this->createMock(LanguageInterface::class);
|
||||
$language_en->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn('en');
|
||||
$language_en->expects($this->any())
|
||||
->method('getName')
|
||||
->willReturn('English');
|
||||
$this->languages = [
|
||||
'de' => $language_de,
|
||||
'en' => $language_en,
|
||||
];
|
||||
|
||||
$language_manager = $this->createMock(ConfigurableLanguageManagerInterface::class);
|
||||
$language_manager->expects($this->any())
|
||||
->method('getLanguages')
|
||||
->willReturn($this->languages);
|
||||
$language_manager->expects($this->any())
|
||||
->method('getNativeLanguages')
|
||||
->willReturn($this->languages);
|
||||
$this->languageManager = $language_manager;
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$cache_contexts_manager = $this->createMock(CacheContextsManager::class);
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
|
||||
$entityTypeManager = $this->createMock(EntityTypeManager::class);
|
||||
$container->set('entity_type.manager', $entityTypeManager);
|
||||
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getLangcode
|
||||
*/
|
||||
public function testGetLangcode(): void {
|
||||
$languageNegotiationContentEntity = $this->createLanguageNegotiationPlugin();
|
||||
|
||||
// Case 1: Empty request.
|
||||
$this->assertEquals(NULL, $languageNegotiationContentEntity->getLangcode());
|
||||
|
||||
// Case 2: A request is available, but the languageManager is not set and
|
||||
// the static::QUERY_PARAMETER is not provided as a named parameter.
|
||||
$request = Request::create('/de/foo', 'GET');
|
||||
$request->query = new InputBag();
|
||||
$this->assertEquals(NULL, $languageNegotiationContentEntity->getLangcode($request));
|
||||
|
||||
// Case 3: A request is available, the languageManager is set, but the
|
||||
// static::QUERY_PARAMETER is not provided as a named parameter.
|
||||
$languageNegotiationContentEntity->setLanguageManager($this->languageManager);
|
||||
$this->assertEquals(NULL, $languageNegotiationContentEntity->getLangcode($request));
|
||||
|
||||
// Case 4: A request is available, the languageManager is set and the
|
||||
// static::QUERY_PARAMETER is provided as a named parameter.
|
||||
$expectedLangcode = 'de';
|
||||
$request->query->set(LanguageNegotiationContentEntity::QUERY_PARAMETER, $expectedLangcode);
|
||||
$this->assertEquals($expectedLangcode, $languageNegotiationContentEntity->getLangcode($request));
|
||||
|
||||
// Case 5: A request is available, the languageManager is set and the
|
||||
// static::QUERY_PARAMETER is provided as a named parameter with a given
|
||||
// langcode that is not one of the system supported ones.
|
||||
$unknownLangcode = 'xx';
|
||||
$request->query->set(LanguageNegotiationContentEntity::QUERY_PARAMETER, $unknownLangcode);
|
||||
$this->assertNull($languageNegotiationContentEntity->getLangcode($request));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::processOutbound
|
||||
*/
|
||||
public function testProcessOutbound(): void {
|
||||
|
||||
// Case 1: Not all processing conditions are met.
|
||||
$languageNegotiationContentEntityMock = $this->createPartialMock($this->getPluginClass(),
|
||||
['hasLowerLanguageNegotiationWeight', 'meetsContentEntityRoutesCondition']);
|
||||
$languageNegotiationContentEntityMock->expects($this->exactly(2))
|
||||
->method('hasLowerLanguageNegotiationWeight')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
FALSE,
|
||||
TRUE
|
||||
);
|
||||
$languageNegotiationContentEntityMock->expects($this->once())
|
||||
->method('meetsContentEntityRoutesCondition')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
FALSE
|
||||
);
|
||||
$options = [];
|
||||
$path = $this->randomMachineName();
|
||||
|
||||
// Case 1a: Empty request.
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path));
|
||||
$request = Request::create('/foo', 'GET');
|
||||
$request->server = new ServerBag();
|
||||
// Case 1b: Missing the route key in $options.
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));
|
||||
$options = ['route' => $this->createMock(Route::class)];
|
||||
// Case 1c: hasLowerLanguageNegotiationWeight() returns FALSE.
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));
|
||||
// Case 1d: meetsContentEntityRoutesCondition() returns FALSE.
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));
|
||||
|
||||
// Case 2: Cannot figure out the langcode.
|
||||
$languageNegotiationContentEntityMock = $this->createPartialMock($this->getPluginClass(),
|
||||
['hasLowerLanguageNegotiationWeight', 'meetsContentEntityRoutesCondition', 'getLangcode']);
|
||||
$languageNegotiationContentEntityMock->expects($this->any())
|
||||
->method('hasLowerLanguageNegotiationWeight')
|
||||
->willReturn(TRUE);
|
||||
$languageNegotiationContentEntityMock->expects($this->any())
|
||||
->method('meetsContentEntityRoutesCondition')
|
||||
->willReturn(TRUE);
|
||||
$languageNegotiationContentEntityMock->expects($this->exactly(2))
|
||||
->method('getLangcode')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
NULL,
|
||||
'de'
|
||||
);
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request));
|
||||
|
||||
// Case 3: Can figure out the langcode.
|
||||
// Case 3a: via $options['language'].
|
||||
$options['language'] = $this->languages['en'];
|
||||
$options['query'] = NULL;
|
||||
$bubbleableMetadataMock = $this->createMock(BubbleableMetadata::class);
|
||||
$bubbleableMetadataMock->expects($this->exactly(3))
|
||||
->method('addCacheContexts')
|
||||
->with(['url.query_args:' . LanguageNegotiationContentEntity::QUERY_PARAMETER]);
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request, $bubbleableMetadataMock));
|
||||
$this->assertFalse(isset($options['language']));
|
||||
$this->assertTrue(isset($options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]));
|
||||
$this->assertEquals('en', $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);
|
||||
|
||||
// Case 3a1: via $options['language'] with an additional
|
||||
// $options['query'][static::QUERY_PARAMETER].
|
||||
$options['language'] = $this->languages['en'];
|
||||
$options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER] = 'xx';
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request, $bubbleableMetadataMock));
|
||||
$this->assertFalse(isset($options['language']));
|
||||
$this->assertEquals('xx', $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);
|
||||
|
||||
// Case 3b: via getLangcode().
|
||||
unset($options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);
|
||||
$this->assertEquals($path, $languageNegotiationContentEntityMock->processOutbound($path, $options, $request, $bubbleableMetadataMock));
|
||||
$this->assertEquals('de', $options['query'][LanguageNegotiationContentEntity::QUERY_PARAMETER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getLanguageSwitchLinks
|
||||
*/
|
||||
public function testGetLanguageSwitchLinks(): void {
|
||||
$languageNegotiationContentEntity = $this->createLanguageNegotiationPlugin();
|
||||
$languageNegotiationContentEntity->setLanguageManager($this->languageManager);
|
||||
|
||||
$request = Request::create('/foo', 'GET', ['param1' => 'xyz']);
|
||||
$url = Url::fromUri('base:' . $this->randomMachineName());
|
||||
|
||||
$expectedLanguageSwitchLinksArray = [
|
||||
'de' => [
|
||||
'url' => $url,
|
||||
'title' => $this->languages['de']->getName(),
|
||||
'attributes' => ['class' => ['language-link']],
|
||||
'query' => [
|
||||
LanguageNegotiationContentEntity::QUERY_PARAMETER => 'de',
|
||||
'param1' => 'xyz',
|
||||
],
|
||||
],
|
||||
'en' => [
|
||||
'url' => $url,
|
||||
'title' => $this->languages['en']->getName(),
|
||||
'attributes' => ['class' => ['language-link']],
|
||||
'query' => [
|
||||
LanguageNegotiationContentEntity::QUERY_PARAMETER => 'en',
|
||||
'param1' => 'xyz',
|
||||
],
|
||||
],
|
||||
];
|
||||
$providedLanguageSwitchLinksArray = $languageNegotiationContentEntity->getLanguageSwitchLinks($request, $this->randomMachineName(), $url);
|
||||
$this->assertEquals(
|
||||
$expectedLanguageSwitchLinksArray,
|
||||
$providedLanguageSwitchLinksArray
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\Plugin\LanguageNegotiation;
|
||||
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Base class used for testing the various LanguageNegotiation plugins.
|
||||
*
|
||||
* @group language
|
||||
*/
|
||||
abstract class LanguageNegotiationTestBase extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Returns the plugin class to use for creating the language negotiation plugin.
|
||||
*
|
||||
* @return string
|
||||
* The plugin class name.
|
||||
*/
|
||||
abstract protected function getPluginClass(): string;
|
||||
|
||||
/**
|
||||
* Creates a @LanguageNegotiation plugin using the factory ::create method.
|
||||
*
|
||||
* @return \Drupal\language\LanguageNegotiationMethodInterface
|
||||
* The created language negotiation plugin.
|
||||
*/
|
||||
protected function createLanguageNegotiationPlugin(array $configuration = [], $plugin_definition = NULL) {
|
||||
$class = $this->getPluginClass();
|
||||
$this->assertTrue(in_array(ContainerFactoryPluginInterface::class, class_implements($class)));
|
||||
return $class::create(\Drupal::getContainer(), $configuration, $class::METHOD_ID, $plugin_definition);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\process;
|
||||
|
||||
use Drupal\language\Plugin\migrate\process\LanguageDomains;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\migrate\process\LanguageDomains
|
||||
* @group language
|
||||
*/
|
||||
class LanguageDomainsTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$configuration = [
|
||||
'key' => 'language',
|
||||
'value' => 'domain',
|
||||
];
|
||||
$this->plugin = new LanguageDomains($configuration, 'map', []);
|
||||
parent::setUp();
|
||||
|
||||
// The language_domains plugin calls getSourceProperty() to check if domain
|
||||
// negotiation is used. If it is the values will be processed so we need it
|
||||
// to return TRUE to be able to test the process.
|
||||
$this->row->expects($this->once())
|
||||
->method('getSourceProperty')
|
||||
->willReturn(TRUE);
|
||||
|
||||
// The language_domains plugin use $base_url to fill empty domains.
|
||||
global $base_url;
|
||||
$base_url = 'http://example.com';
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransform(): void {
|
||||
$source = [
|
||||
['language' => 'en', 'domain' => ''],
|
||||
['language' => 'fr', 'domain' => 'fr.example.com'],
|
||||
['language' => 'es', 'domain' => 'http://es.example.com'],
|
||||
['language' => 'hu', 'domain' => 'https://hu.example.com'],
|
||||
];
|
||||
$expected = [
|
||||
'en' => 'example.com',
|
||||
'fr' => 'fr.example.com',
|
||||
'es' => 'es.example.com',
|
||||
'hu' => 'hu.example.com',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\process;
|
||||
|
||||
use Drupal\language\Plugin\migrate\process\LanguageNegotiation;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\migrate\process\LanguageNegotiation
|
||||
* @group language
|
||||
*/
|
||||
class LanguageNegotiationTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->plugin = new LanguageNegotiation([], 'map', []);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation without weights.
|
||||
*/
|
||||
public function testTransformWithWeights(): void {
|
||||
$source = [
|
||||
[
|
||||
'locale-url' => [],
|
||||
'language-default' => [],
|
||||
],
|
||||
[
|
||||
'locale-url' => -10,
|
||||
'locale-session' => -9,
|
||||
'locale-user' => -8,
|
||||
'locale-browser' => -7,
|
||||
'language-default' => -6,
|
||||
],
|
||||
];
|
||||
$expected = [
|
||||
'enabled' => [
|
||||
'language-url' => -10,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
'method_weights' => [
|
||||
'language-url' => -10,
|
||||
'language-session' => -9,
|
||||
'language-user' => -8,
|
||||
'language-browser' => -7,
|
||||
'language-selected' => -6,
|
||||
],
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation without weights.
|
||||
*/
|
||||
public function testTransformWithoutWeights(): void {
|
||||
$source = [
|
||||
[
|
||||
'locale-url' => [],
|
||||
'locale-url-fallback' => [],
|
||||
],
|
||||
];
|
||||
$expected = [
|
||||
'enabled' => [
|
||||
'language-url' => 0,
|
||||
'language-url-fallback' => 1,
|
||||
],
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests string input.
|
||||
*/
|
||||
public function testStringInput(): void {
|
||||
$this->plugin = new LanguageNegotiation([], 'map', []);
|
||||
$this->expectException(MigrateException::class);
|
||||
$this->expectExceptionMessage('The input should be an array');
|
||||
$this->plugin->transform('foo', $this->migrateExecutable, $this->row, 'destination_property');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\language\Unit\process;
|
||||
|
||||
use Drupal\language\Plugin\migrate\process\LanguageTypes;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\language\Plugin\migrate\process\LanguageTypes
|
||||
* @group language
|
||||
*/
|
||||
class LanguageTypesTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* Tests successful transformation of all language types.
|
||||
*/
|
||||
public function testTransformAll(): void {
|
||||
$this->plugin = new LanguageTypes([], 'map', []);
|
||||
$source = [
|
||||
'language' => TRUE,
|
||||
'language_url' => FALSE,
|
||||
'language_content' => FALSE,
|
||||
];
|
||||
$expected = [
|
||||
0 => 'language_url',
|
||||
1 => 'language_content',
|
||||
2 => 'language_interface',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation of configurable language types.
|
||||
*/
|
||||
public function testTransformConfigurable(): void {
|
||||
$this->plugin = new LanguageTypes(['filter_configurable' => TRUE], 'map', []);
|
||||
$source = [
|
||||
'language' => TRUE,
|
||||
'language_url' => FALSE,
|
||||
'language_content' => FALSE,
|
||||
];
|
||||
$expected = [
|
||||
0 => 'language_interface',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests string input.
|
||||
*/
|
||||
public function testStringInput(): void {
|
||||
$this->plugin = new LanguageTypes([], 'map', []);
|
||||
$this->expectException(MigrateException::class);
|
||||
$this->expectExceptionMessage('The input should be an array');
|
||||
$this->plugin->transform('foo', $this->migrateExecutable, $this->row, 'destination_property');
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user