summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2014-11-03 13:33:38 (GMT)
committerNathaniel Catchpole2014-11-03 13:33:38 (GMT)
commit51fcd31ce5a85dff1dd46ca39f79f7a9f79da7ff (patch)
tree9db457070e17cbf433aae37e412138da78eaa914
parented4cedc09a00cbfd9c2c37cdeaae215ae069f3b6 (diff)
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.
-rw-r--r--core/lib/Drupal/Core/Language/Language.php4
-rw-r--r--core/lib/Drupal/Core/Language/LanguageManager.php86
-rw-r--r--core/modules/language/src/ConfigurableLanguageManager.php59
-rw-r--r--core/modules/language/src/Tests/LanguageSelectorTranslatableTest.php93
-rw-r--r--core/tests/Drupal/Tests/Core/Language/LanguageUnitTest.php14
5 files changed, 202 insertions, 54 deletions
diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php
index ec3ce71..7702496 100644
--- a/core/lib/Drupal/Core/Language/Language.php
+++ b/core/lib/Drupal/Core/Language/Language.php
@@ -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'])) {
diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php
index e0916e4..aac3c65 100644
--- a/core/lib/Drupal/Core/Language/LanguageManager.php
+++ b/core/lib/Drupal/Core/Language/LanguageManager.php
@@ -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 @@ class LanguageManager implements LanguageManagerInterface {
* {@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 @@ class LanguageManager implements LanguageManagerInterface {
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;
+ }
+
}
diff --git a/core/modules/language/src/ConfigurableLanguageManager.php b/core/modules/language/src/ConfigurableLanguageManager.php
index 534f232..e17b3d2 100644
--- a/core/modules/language/src/ConfigurableLanguageManager.php
+++ b/core/modules/language/src/ConfigurableLanguageManager.php
@@ -17,7 +17,6 @@ use Drupal\Core\Language\LanguageManager;
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 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl
$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 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl
* {@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];
}
/**
diff --git a/core/modules/language/src/Tests/LanguageSelectorTranslatableTest.php b/core/modules/language/src/Tests/LanguageSelectorTranslatableTest.php
new file mode 100644
index 0000000..15290fd
--- /dev/null
+++ b/core/modules/language/src/Tests/LanguageSelectorTranslatableTest.php
@@ -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.');
+ }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Language/LanguageUnitTest.php b/core/tests/Drupal/Tests/Core/Language/LanguageUnitTest.php
index e21ab6f..49a9dbf 100644
--- a/core/tests/Drupal/Tests/Core/Language/LanguageUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Language/LanguageUnitTest.php
@@ -18,6 +18,20 @@ use Drupal\Tests\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 ::setName()
*/