Commit 51fcd31c authored by catch's avatar catch

Issue #1879930 by fran seva, Gábor Hojtsy, martin107, markie, Schnitzel,...

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 ed4cedc0
......@@ -80,7 +80,9 @@ class Language implements LanguageInterface {
public function __construct(array $values = array()) {
// Set all the provided properties for the language.
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 (!isset($values['name']) || !isset($values['direction'])) {
......
......@@ -27,11 +27,17 @@ class LanguageManager implements LanguageManagerInterface {
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[]
*
* @see \Drupal\Core\Language\LanguageManager::getLanguages()
*/
protected $languages;
protected $languages = array();
/**
* The default language object.
......@@ -130,35 +136,19 @@ public function getDefaultLanguage() {
* {@inheritdoc}
*/
public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
// Initialize master language list.
if (!isset($this->languages)) {
// No language module, so use the default language only.
$static_cache_id = $this->getCurrentLanguage()->getId();
if (!isset($this->languages[$static_cache_id][$flags])) {
// 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();
$this->languages = array($default->getId() => $default);
// Add the special languages, they will be filtered later if needed.
$this->languages += $this->getDefaultLockedLanguages($default->getWeight());
}
$languages = array($default->getId() => $default);
$languages += $this->getDefaultLockedLanguages($default->getWeight());
// 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;
// Filter the full list of languages based on the value of $flags.
$this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
}
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;
return $this->languages[$static_cache_id][$flags];
}
/**
......@@ -382,4 +372,44 @@ public function getConfigOverrideLanguage() {
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\Url;
use Drupal\language\Config\LanguageConfigFactoryOverrideInterface;
use Drupal\language\Entity\ConfigurableLanguage;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
......@@ -247,7 +246,7 @@ public function reset($type = NULL) {
$this->negotiatedMethods = array();
$this->languageTypes = NULL;
$this->languageTypesInfo = NULL;
$this->languages = NULL;
$this->languages = array();
if ($this->negotiator) {
$this->negotiator->reset();
}
......@@ -279,37 +278,47 @@ public function setNegotiator(LanguageNegotiatorInterface $negotiator) {
* {@inheritdoc}
*/
public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
if (!isset($this->languages)) {
// Prepopulate the language list with the default language to keep things
// working even if we have no configuration.
$default = $this->getDefaultLanguage();
$this->languages = array($default->getId() => $default);
// Retrieve the list of languages defined in configuration.
$prefix = 'language.entity.';
$config_ids = $this->configFactory->listAll($prefix);
// If a config override is set, cache using that language's ID.
if ($override_language = $this->getConfigOverrideLanguage()) {
$static_cache_id = $override_language->getId();
}
else {
$static_cache_id = $this->getCurrentLanguage()->getId();
}
// Instantiate languages from config objects.
$weight = 0;
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();
$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()));
$languages[$data['id']] = new Language($data);
}
Language::sort($languages);
// 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);
// Filter the full list of languages based on the value of $flags.
$this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
}
return parent::getLanguages($flags);
return $this->languages[$static_cache_id][$flags];
}
/**
......
<?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 @@
*/
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 ::setName()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment