diff --git a/core/modules/language/language.module b/core/modules/language/language.module index 6a17f735e2bf6fb4a34c615df02a12fd132ab805..845407d4d1b1d1f732eec57e5cc916d75b55b422 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -431,9 +431,7 @@ function language_save($language) { $language_entity->direction = isset($language->direction) ? $language->direction : '0'; $language_entity->locked = !empty($language->locked); $language_entity->weight = isset($language->weight) ? $language->weight : 0; - - // Save the record and inform others about the change. - $multilingual = \Drupal::languageManager()->isMultilingual(); + $language_entity->setDefault(!empty($language->default)); $language_entity->save(); $t_args = array('%language' => $language->name, '%langcode' => $language->id); if ($language->is_new) { @@ -443,30 +441,6 @@ function language_save($language) { watchdog('language', 'The %language (%langcode) language has been updated.', $t_args); } - if (!empty($language->default)) { - // Update the config. Saving the configuration fires and event that causes - // the container to be rebuilt. - \Drupal::config('system.site')->set('langcode', $language->id)->save(); - \Drupal::service('language.default')->set($language); - } - - $language_manager = \Drupal::languageManager(); - $language_manager->reset(); - if ($language_manager instanceof ConfigurableLanguageManagerInterface) { - $language_manager->updateLockedLanguageWeights(); - } - - // Update URL Prefixes for all languages after the new default language is - // propagated and the LanguageManagerInterface::getLanguages() cache is - // flushed. - language_negotiation_url_prefixes_update(); - - // If after adding this language the site will become multilingual, we need to - // rebuild language services. - if (!$multilingual && $language->is_new) { - ConfigurableLanguageManager::rebuildServices(); - } - return $language; } diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php index b164cd579bdfd189f729b3dbfac910cf69132b50..a4141192053adaf9a4f4d3a0ce6f219538936535 100644 --- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php +++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php @@ -92,7 +92,7 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl protected $initializing = FALSE; /** - * Rebuild the container to register services needed on multilingual sites. + * {@inheritdoc} */ public static function rebuildServices() { PhpStorageFactory::get('service_container')->deleteAll(); diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php index d2f4f360663b2dabef952029b823e269f00ae8dd..9ec0d912819aa9e086a017c38123d8ad5f05232d 100644 --- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php +++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php @@ -16,6 +16,11 @@ */ interface ConfigurableLanguageManagerInterface extends LanguageManagerInterface { + /** + * Rebuild the container to register services needed on multilingual sites. + */ + public static function rebuildServices(); + /** * Injects the request object. * diff --git a/core/modules/language/lib/Drupal/language/Entity/Language.php b/core/modules/language/lib/Drupal/language/Entity/Language.php index 77015cdfb870555c90fd35aa1463b5ad7095bfb7..8a2f9fe061127ae81a07527f8dcfad93828977f1 100644 --- a/core/modules/language/lib/Drupal/language/Entity/Language.php +++ b/core/modules/language/lib/Drupal/language/Entity/Language.php @@ -7,8 +7,10 @@ namespace Drupal\language\Entity; +use Drupal\Core\Language\Language as LanguageObject; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\language\ConfigurableLanguageManagerInterface; use Drupal\language\Exception\DeleteDefaultLanguageException; use Drupal\language\LanguageInterface; @@ -77,28 +79,160 @@ class Language extends ConfigEntityBase implements LanguageInterface { */ public $locked = FALSE; + /** + * Flag to indicate if the language entity is the default site language. + * + * This property is not saved to the language entity since there can be only + * one default language. It is saved to system.site:langcode and set on the + * container using the language.default service in when the entity is saved. + * The value is set correctly when a language entity is created or loaded. + * + * @see \Drupal\language\Entity\Language::postSave() + * @see \Drupal\language\Entity\Language::isDefault() + * @see \Drupal\language\Entity\Language::setDefault() + * + * @var bool + */ + protected $default; + + /** + * Used during saving to detect when the site becomes multilingual. + * + * This property is not saved to the language entity, but is needed for + * detecting when to rebuild the services. + * + * @see \Drupal\language\Entity\Language::preSave() + * @see \Drupal\language\Entity\Language::postSave() + * + * @var bool + */ + protected $preSaveMultilingual; + + /** + * Sets the default flag on the language entity. + * + * @param bool $default + */ + public function setDefault($default) { + $this->default = $default; + } + + /** + * Checks if the language entity is the site default language. + * + * @return bool + * TRUE if the language entity is the site default language, FALSE if not. + */ + public function isDefault() { + if (!isset($this->default)) { + return static::getDefaultLangcode() == $this->id(); + } + return $this->default; + } + /** * {@inheritdoc} */ public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); + // Store whether or not the site is already multilingual so that we can + // rebuild services if necessary during + // \Drupal\language\Entity\Language::postSave(). + $this->preSaveMultilingual = \Drupal::languageManager()->isMultilingual(); // Languages are picked from a predefined list which is given in English. // For the uncommon case of custom languages the label should be given in // English. $this->langcode = 'en'; } + /** + * {@inheritdoc} + */ + public function postSave(EntityStorageInterface $storage, $update = TRUE) { + parent::postSave($storage, $update); + + // Only set the default language and save it to system.site configuration if + // it needs to updated. + if ($this->isDefault() && static::getDefaultLangcode() != $this->id()) { + // Update the config. Saving the configuration fires and event that causes + // the container to be rebuilt. + \Drupal::config('system.site')->set('langcode', $this->id())->save(); + \Drupal::service('language.default')->set($this->toLanguageObject()); + } + + $language_manager = \Drupal::languageManager(); + $language_manager->reset(); + if ($language_manager instanceof ConfigurableLanguageManagerInterface) { + $language_manager->updateLockedLanguageWeights(); + } + + // Update URL Prefixes for all languages after the new default language is + // propagated and the LanguageManagerInterface::getLanguages() cache is + // flushed. + language_negotiation_url_prefixes_update(); + + // If after adding this language the site will become multilingual, we need + // to rebuild language services. + if (!$this->preSaveMultilingual && !$update && $language_manager instanceof ConfigurableLanguageManagerInterface) { + $language_manager::rebuildServices(); + } + } + + /** + * Converts the Language entity to a Language value object. + * + * @todo fix return type hint after https://drupal.org/node/2246665 and + * https://drupal.org/node/2246679. + * + * @return \Drupal\Core\Language\Language + * The language configuration entity expressed as a Language value object. + */ + protected function toLanguageObject() { + return new LanguageObject(array( + 'id' => $this->id(), + 'name' => $this->label(), + 'direction' => $this->direction, + 'weight' => $this->weight, + 'locked' => $this->locked, + 'default' => $this->default, + )); + } + /** * {@inheritdoc} * * @throws \RuntimeException */ public static function preDelete(EntityStorageInterface $storage, array $entities) { - $default_language = \Drupal::service('language.default')->get(); + $default_langcode = static::getDefaultLangcode(); foreach ($entities as $entity) { - if ($entity->id() == $default_language->id && !$entity->isUninstalling()) { + if ($entity->id() == $default_langcode && !$entity->isUninstalling()) { throw new DeleteDefaultLanguageException('Can not delete the default language'); } } } + + /** + * {@inheritdoc} + */ + public function get($property_name) { + if ($property_name == 'default') { + return $this->isDefault(); + } + else { + return parent::get($property_name); + } + } + + /** + * Gets the default langcode. + * + * @return string + * The current default langcode. + */ + protected static function getDefaultLangcode() { + $language = \Drupal::service('language.default')->get(); + return $language->getId(); + } + } diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php index 0a507f20cf373d325f4f2ea44e852fcee8558cf8..c7c85f150440392204075090515d765853c711ec 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php @@ -88,6 +88,9 @@ public function testDefaultLangcode() { // Site's default. $old_default = \Drupal::languageManager()->getDefaultLanguage(); + // Ensure the language entity default value is correct. + $language_entity = entity_load('language_entity', $old_default->getId()); + $this->assertTrue($language_entity->get('default'), 'The en language entity is flagged as the default language.'); $old_default->default = FALSE; language_save($old_default); $new_default = \Drupal::languageManager()->getLanguage('cc'); @@ -97,6 +100,14 @@ public function testDefaultLangcode() { $langcode = language_get_default_langcode('custom_type', 'custom_bundle'); $this->assertEqual($langcode, 'cc'); + // Ensure the language entity default value is correct. + $language_entity = entity_load('language_entity', $old_default->getId()); + $this->assertFalse($language_entity->get('default'), 'The en language entity is not flagged as the default language.'); + $language_entity = entity_load('language_entity', 'cc'); + // Check calling the Drupal\language\Entity\Language::isDefault() method + // directly. + $this->assertTrue($language_entity->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. // Create first an user and assign a preferred langcode to him.