Issue #1879930 by fran seva, Gábor Hojtsy, martin107, markie, Schnitzel, alexpott, Sutharsan, mon_franco, YesCT, spearhead93, herom, Désiré: Fixed Language selectors are not showing localized to the page language.
parent
ed4cedc09a
commit
51fcd31ce5
|
@ -80,7 +80,9 @@ class Language implements LanguageInterface {
|
||||||
public function __construct(array $values = array()) {
|
public function __construct(array $values = array()) {
|
||||||
// Set all the provided properties for the language.
|
// Set all the provided properties for the language.
|
||||||
foreach ($values as $key => $value) {
|
foreach ($values as $key => $value) {
|
||||||
$this->{$key} = $value;
|
if (property_exists($this, $key)) {
|
||||||
|
$this->{$key} = $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If some values were not set, set sane defaults of a predefined language.
|
// If some values were not set, set sane defaults of a predefined language.
|
||||||
if (!isset($values['name']) || !isset($values['direction'])) {
|
if (!isset($values['name']) || !isset($values['direction'])) {
|
||||||
|
|
|
@ -27,11 +27,17 @@ class LanguageManager implements LanguageManagerInterface {
|
||||||
protected $translation;
|
protected $translation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of all the available languages keyed by language code.
|
* A static cache of translated language lists.
|
||||||
|
*
|
||||||
|
* Array of arrays to cache the result of self::getLanguages() keyed by the
|
||||||
|
* language the list is translated to (first level) and the flags provided to
|
||||||
|
* the method (second level).
|
||||||
*
|
*
|
||||||
* @var \Drupal\Core\Language\LanguageInterface[]
|
* @var \Drupal\Core\Language\LanguageInterface[]
|
||||||
|
*
|
||||||
|
* @see \Drupal\Core\Language\LanguageManager::getLanguages()
|
||||||
*/
|
*/
|
||||||
protected $languages;
|
protected $languages = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default language object.
|
* The default language object.
|
||||||
|
@ -130,35 +136,19 @@ class LanguageManager implements LanguageManagerInterface {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
|
public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
|
||||||
// Initialize master language list.
|
$static_cache_id = $this->getCurrentLanguage()->getId();
|
||||||
if (!isset($this->languages)) {
|
if (!isset($this->languages[$static_cache_id][$flags])) {
|
||||||
// No language module, so use the default language only.
|
// If this language manager is used, there are no configured languages.
|
||||||
|
// The default language and locked languages comprise the full language
|
||||||
|
// list.
|
||||||
$default = $this->getDefaultLanguage();
|
$default = $this->getDefaultLanguage();
|
||||||
$this->languages = array($default->getId() => $default);
|
$languages = array($default->getId() => $default);
|
||||||
// Add the special languages, they will be filtered later if needed.
|
$languages += $this->getDefaultLockedLanguages($default->getWeight());
|
||||||
$this->languages += $this->getDefaultLockedLanguages($default->getWeight());
|
|
||||||
|
// Filter the full list of languages based on the value of $flags.
|
||||||
|
$this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
|
||||||
}
|
}
|
||||||
|
return $this->languages[$static_cache_id][$flags];
|
||||||
// Filter the full list of languages based on the value of the $all flag. By
|
|
||||||
// default we remove the locked languages, but the caller may request for
|
|
||||||
// those languages to be added as well.
|
|
||||||
$filtered_languages = array();
|
|
||||||
|
|
||||||
// Add the site's default language if flagged as allowed value.
|
|
||||||
if ($flags & LanguageInterface::STATE_SITE_DEFAULT) {
|
|
||||||
// Setup a language to have the defaults, but with overridden name.
|
|
||||||
$default = $this->getDefaultLanguage();
|
|
||||||
$default->setName($this->t("Site's default language (@lang_name)", array('@lang_name' => $default->getName())));
|
|
||||||
$filtered_languages[LanguageInterface::LANGCODE_SITE_DEFAULT] = $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->languages as $id => $language) {
|
|
||||||
if (($language->isLocked() && ($flags & LanguageInterface::STATE_LOCKED)) || (!$language->isLocked() && ($flags & LanguageInterface::STATE_CONFIGURABLE))) {
|
|
||||||
$filtered_languages[$id] = $language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $filtered_languages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -382,4 +372,44 @@ class LanguageManager implements LanguageManagerInterface {
|
||||||
return $this->getCurrentLanguage();
|
return $this->getCurrentLanguage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the full list of languages based on the value of the flag.
|
||||||
|
*
|
||||||
|
* The locked languages are removed by default.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Language\LanguageInterface[] $languages
|
||||||
|
* Array with languages to be filtered.
|
||||||
|
* @param int $flags
|
||||||
|
* (optional) Specifies the state of the languages that have to be returned.
|
||||||
|
* It can be: LanguageInterface::STATE_CONFIGURABLE,
|
||||||
|
* LanguageInterface::STATE_LOCKED, or LanguageInterface::STATE_ALL.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Language\LanguageInterface[]
|
||||||
|
* An associative array of languages, keyed by the language code.
|
||||||
|
*/
|
||||||
|
protected function filterLanguages(array $languages, $flags = LanguageInterface::STATE_CONFIGURABLE) {
|
||||||
|
// STATE_ALL means we don't actually filter, so skip the rest of the method.
|
||||||
|
if ($flags == LanguageInterface::STATE_ALL) {
|
||||||
|
return $languages;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filtered_languages = array();
|
||||||
|
// Add the site's default language if requested.
|
||||||
|
if ($flags & LanguageInterface::STATE_SITE_DEFAULT) {
|
||||||
|
// Setup a language to have the defaults, but with overridden name.
|
||||||
|
$default = $this->getDefaultLanguage();
|
||||||
|
$default->setName($this->t("Site's default language (@lang_name)", array('@lang_name' => $default->getName())));
|
||||||
|
$filtered_languages[LanguageInterface::LANGCODE_SITE_DEFAULT] = $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($languages as $id => $language) {
|
||||||
|
if (($language->isLocked() && ($flags & LanguageInterface::STATE_LOCKED)) || (!$language->isLocked() && ($flags & LanguageInterface::STATE_CONFIGURABLE))) {
|
||||||
|
$filtered_languages[$id] = $language;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $filtered_languages;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ use Drupal\Core\Language\LanguageManager;
|
||||||
use Drupal\Core\Url;
|
use Drupal\Core\Url;
|
||||||
use Drupal\language\Config\LanguageConfigFactoryOverrideInterface;
|
use Drupal\language\Config\LanguageConfigFactoryOverrideInterface;
|
||||||
use Drupal\language\Entity\ConfigurableLanguage;
|
use Drupal\language\Entity\ConfigurableLanguage;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -247,7 +246,7 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl
|
||||||
$this->negotiatedMethods = array();
|
$this->negotiatedMethods = array();
|
||||||
$this->languageTypes = NULL;
|
$this->languageTypes = NULL;
|
||||||
$this->languageTypesInfo = NULL;
|
$this->languageTypesInfo = NULL;
|
||||||
$this->languages = NULL;
|
$this->languages = array();
|
||||||
if ($this->negotiator) {
|
if ($this->negotiator) {
|
||||||
$this->negotiator->reset();
|
$this->negotiator->reset();
|
||||||
}
|
}
|
||||||
|
@ -279,37 +278,47 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
|
public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
|
||||||
if (!isset($this->languages)) {
|
// If a config override is set, cache using that language's ID.
|
||||||
// Prepopulate the language list with the default language to keep things
|
if ($override_language = $this->getConfigOverrideLanguage()) {
|
||||||
// working even if we have no configuration.
|
$static_cache_id = $override_language->getId();
|
||||||
$default = $this->getDefaultLanguage();
|
}
|
||||||
$this->languages = array($default->getId() => $default);
|
else {
|
||||||
|
$static_cache_id = $this->getCurrentLanguage()->getId();
|
||||||
// Retrieve the list of languages defined in configuration.
|
|
||||||
$prefix = 'language.entity.';
|
|
||||||
$config_ids = $this->configFactory->listAll($prefix);
|
|
||||||
|
|
||||||
// Instantiate languages from config objects.
|
|
||||||
$weight = 0;
|
|
||||||
foreach ($this->configFactory->loadMultiple($config_ids) as $config) {
|
|
||||||
$data = $config->get();
|
|
||||||
$langcode = $data['id'];
|
|
||||||
// Initialize default property so callers have an easy reference and can
|
|
||||||
// save the same object without data loss.
|
|
||||||
$data['default'] = ($langcode == $default->getId());
|
|
||||||
$data['name'] = $data['label'];
|
|
||||||
$this->languages[$langcode] = new Language($data);
|
|
||||||
$weight = max(array($weight, $this->languages[$langcode]->getWeight()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add locked languages, they will be filtered later if needed.
|
|
||||||
$this->languages += $this->getDefaultLockedLanguages($weight);
|
|
||||||
|
|
||||||
// Sort the language list by weight then title.
|
|
||||||
Language::sort($this->languages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::getLanguages($flags);
|
if (!isset($this->languages[$static_cache_id][$flags])) {
|
||||||
|
// Initialize the language list with the default language and default
|
||||||
|
// locked languages. These cannot be removed. This serves as a fallback
|
||||||
|
// list if this method is invoked while the language module is installed
|
||||||
|
// and the configuration entities for languages are not yet fully
|
||||||
|
// imported.
|
||||||
|
$default = $this->getDefaultLanguage();
|
||||||
|
$languages = array($default->getId() => $default);
|
||||||
|
$languages += $this->getDefaultLockedLanguages($default->getWeight());
|
||||||
|
|
||||||
|
// Load configurable languages on top of the defaults. Ideally this could
|
||||||
|
// use the entity API to load and instantiate ConfigurableLanguage
|
||||||
|
// objects. However the entity API depends on the language system, so that
|
||||||
|
// would result in infinite loops. We use the configuration system
|
||||||
|
// directly and instantiate runtime Language objects. When language
|
||||||
|
// entities are imported those cover the default and locked languages, so
|
||||||
|
// site-specific configuration will prevail over the fallback values.
|
||||||
|
// Having them in the array already ensures if this is invoked in the
|
||||||
|
// middle of importing language configuration entities, the defaults are
|
||||||
|
// always present.
|
||||||
|
$config_ids = $this->configFactory->listAll('language.entity.');
|
||||||
|
foreach ($this->configFactory->loadMultiple($config_ids) as $config) {
|
||||||
|
$data = $config->get();
|
||||||
|
$data['name'] = $data['label'];
|
||||||
|
$languages[$data['id']] = new Language($data);
|
||||||
|
}
|
||||||
|
Language::sort($languages);
|
||||||
|
|
||||||
|
// Filter the full list of languages based on the value of $flags.
|
||||||
|
$this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->languages[$static_cache_id][$flags];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\language\Tests\LanguageSelectorTranslatableTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\language\Tests;
|
||||||
|
|
||||||
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the content translation settings language selector options.
|
||||||
|
*
|
||||||
|
* @group language
|
||||||
|
*/
|
||||||
|
class LanguageSelectorTranslatableTest extends WebTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modules to enable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $modules = array(
|
||||||
|
'language',
|
||||||
|
'content_translation',
|
||||||
|
'node',
|
||||||
|
'comment',
|
||||||
|
'field_ui',
|
||||||
|
'entity_test',
|
||||||
|
'locale',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user with administrator privileges.
|
||||||
|
*
|
||||||
|
* @var \Drupal\user\Entity\User;
|
||||||
|
*/
|
||||||
|
public $administrator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() {
|
||||||
|
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(
|
||||||
|
array('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() {
|
||||||
|
// Add another language.
|
||||||
|
$edit = array('predefined_langcode' => 'es');
|
||||||
|
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
$elements = $this->xpath('//select[@id=:id]//option[@value=:option]', array(':id' => 'edit-settings-node-node-settings-language-langcode', ':option' => 'en'));
|
||||||
|
|
||||||
|
// Check that the language text is translated.
|
||||||
|
$this->assertEqual((string) $elements[0], $name_translation, 'Checking the option string English is translated to Spanish.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,20 @@ use Drupal\Tests\UnitTestCase;
|
||||||
*/
|
*/
|
||||||
class LanguageUnitTest extends UnitTestCase {
|
class LanguageUnitTest extends UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::__construct
|
||||||
|
*/
|
||||||
|
public function testConstruct() {
|
||||||
|
$name = $this->randomMachineName();
|
||||||
|
$language_code = $this->randomMachineName(2);
|
||||||
|
$uuid = $this->randomMachineName();
|
||||||
|
$language = new Language(array('id' => $language_code, 'name' => $name, 'uuid' => $uuid));
|
||||||
|
// Test that nonexistent properties are not added to the language object.
|
||||||
|
$this->assertTrue(property_exists($language, 'id'));
|
||||||
|
$this->assertTrue(property_exists($language, 'name'));
|
||||||
|
$this->assertFalse(property_exists($language, 'uuid'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers ::getName()
|
* @covers ::getName()
|
||||||
* @covers ::setName()
|
* @covers ::setName()
|
||||||
|
|
Loading…
Reference in New Issue