diff -u b/core/core.services.yml b/core/core.services.yml --- b/core/core.services.yml +++ b/core/core.services.yml @@ -227,7 +227,7 @@ class: Drupal\Core\Language\LanguageManager arguments: ['@language.default'] language.default: - class: Drupal\Core\Language\Language + class: Drupal\Core\Language\LanguageDefault arguments: ['%language.default_values%'] string_translator.custom_strings: class: Drupal\Core\StringTranslation\Translator\CustomStrings @@ -278,8 +278,6 @@ calls: - [setRequest, ['@?request']] - [setContext, ['@?router.request_context']] - tags: - - { name: persist } link_generator: class: Drupal\Core\Utility\LinkGenerator arguments: ['@url_generator', '@module_handler', '@language_manager'] diff -u b/core/includes/install.core.inc b/core/includes/install.core.inc --- b/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -311,7 +311,7 @@ } // Register the 'language_manager' service. $container->setParameter('language.default_values', $default_language_values); - $container->register('language.default', 'Drupal\Core\Language\Language') + $container->register('language.default', 'Drupal\Core\Language\LanguageDefault') ->addArgument('%language.default_values%'); $container->register('language_manager', 'Drupal\Core\Language\LanguageManager') ->addArgument(new Reference('language.default')); @@ -384,7 +384,7 @@ ->addArgument(new Reference('cache.config')); $container->setParameter('language.default_values', Language::$defaultValues); - $container->register('language.default', 'Drupal\Core\Language\Language') + $container->register('language.default', 'Drupal\Core\Language\LanguageDefault') ->addArgument('%language.default_values%'); $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') diff -u b/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php --- b/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Language\Language; +use Drupal\Core\Language\LanguageDefault; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -82,16 +83,16 @@ * An event dispatcher instance to use for configuration events. * @param \Drupal\Core\Config\TypedConfigManager $typed_config * The typed configuration manager. - * @param \Drupal\Core\Language\Language - * (optional) The language for this configuration. The config factory will - * use it to override configuration data if language overrides are - * available. + * @param \Drupal\Core\Language\LanguageDefault + * The default language service. This sets the initial language on the + * config factory to the site's default. The language can be used to + * override configuration data if language overrides are available. */ - public function __construct(StorageInterface $storage, EventDispatcher $event_dispatcher, TypedConfigManager $typed_config, Language $language) { + public function __construct(StorageInterface $storage, EventDispatcher $event_dispatcher, TypedConfigManager $typed_config, LanguageDefault $default_language) { $this->storage = $storage; $this->eventDispatcher = $event_dispatcher; $this->typedConfigManager = $typed_config; - $this->language = $language; + $this->language = $default_language->get(); } /** @@ -145,12 +146,7 @@ if ($this->canOverride($name)) { // Get and apply any language overrides. - if ($this->language) { - $language_overrides = $this->storage->read($this->getLanguageConfigName($this->language->id, $name)); - } - else { - $language_overrides = FALSE; - } + $language_overrides = $this->storage->read($this->getLanguageConfigName($this->language->id, $name)); if (is_array($language_overrides)) { $this->cache[$cache_key]->setLanguageOverride($language_overrides); } @@ -326,7 +322,7 @@ $can_override = $this->canOverride($name); $cache_key = $name . ':' . ($can_override ? 'overrides' : 'raw'); - if ($can_override && isset($this->language)) { + if ($can_override) { $cache_key = $cache_key . ':' . $this->language->id; } return $cache_key; @@ -369,7 +365,7 @@ * @return \Drupal\Core\Config\ConfigFactory * The config factory object. */ - public function setLanguage(Language $language = NULL) { + public function setLanguage(Language $language) { $this->language = $language; return $this; } @@ -397,11 +393,9 @@ */ public function getLanguageConfigNames(array $names) { $language_names = array(); - if (isset($this->language)) { - foreach ($names as $name) { - if ($language_name = $this->getLanguageConfigName($this->language->id, $name)) { - $language_names[$name] = $language_name; - } + foreach ($names as $name) { + if ($language_name = $this->getLanguageConfigName($this->language->id, $name)) { + $language_names[$name] = $language_name; } } return $language_names; diff -u b/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php --- b/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -517,6 +517,9 @@ } $container->setParameter('container.namespaces', $namespaces); + // Store the default language values on the container. This is so that the + // default language can be configured and the configuration factory can + // depend on it. $system = BootstrapConfigStorageFactory::get()->read('system.site'); $default_language_values = Language::$defaultValues; if ($default_language_values['id'] != $system['langcode']) { diff -u b/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php --- b/core/lib/Drupal/Core/Language/LanguageManager.php +++ b/core/lib/Drupal/Core/Language/LanguageManager.php @@ -32,7 +32,7 @@ /** * The default language object. * - * @var \Drupal\Core\Language\Language + * @var \Drupal\Core\Language\LanguageDefault */ protected $defaultLanguage; @@ -42,7 +42,7 @@ * @param \Drupal\Core\Language\Language $default_language * The default language. */ - public function __construct(Language $default_language) { + public function __construct(LanguageDefault $default_language) { $this->defaultLanguage = $default_language; } @@ -99,7 +99,7 @@ * {@inheritdoc} */ public function getDefaultLanguage() { - return $this->defaultLanguage; + return $this->defaultLanguage->get(); } /** diff -u b/core/modules/language/language.module b/core/modules/language/language.module --- b/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -473,6 +473,7 @@ // 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(); diff -u b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php --- b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php +++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php @@ -12,6 +12,7 @@ use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\Language; +use Drupal\Core\Language\LanguageDefault; use Drupal\Core\Language\LanguageManager; use Symfony\Component\HttpFoundation\Request; @@ -98,7 +99,7 @@ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler service. */ - public function __construct(Language $default_language, ConfigFactory $config_factory, ModuleHandlerInterface $module_handler) { + public function __construct(LanguageDefault $default_language, ConfigFactory $config_factory, ModuleHandlerInterface $module_handler) { $this->defaultLanguage = $default_language; $this->configFactory = $config_factory; $this->moduleHandler = $module_handler; diff -u b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php --- b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php @@ -9,6 +9,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Language\Language; +use Drupal\language\Exception\DeleteDefaultLanguageException; /** * Test for dependency injected language object. @@ -49,6 +50,7 @@ * @see \Drupal\Core\Language\Language */ function testDependencyInjectedNewDefaultLanguage() { + $default_language = language_default(); // Change the language default object to different values. $new_language_default = new Language(array( 'id' => 'fr', @@ -59,12 +61,6 @@ 'default' => TRUE, )); language_save($new_language_default); - // Saving a new default language will have deleted the container from PHP - // storage but we need to rebuild it to update the container in memory. - $this->rebuildContainer(); - - // Initialize the language system. - $this->languageManager->init(); // The language system creates a Language object which contains the // same properties as the new default language object. @@ -72,10 +68,19 @@ $this->assertIdentical($result->id, 'fr'); // Delete the language to check that we fallback to the default. + try { + language_delete('fr'); + $this->fail('Expected DeleteDefaultLanguageException thrown.'); + } + catch (DeleteDefaultLanguageException $e) { + $this->pass('Expected DeleteDefaultLanguageException thrown.'); + } + + // Re-save the previous default language and the delete should work. + language_save($default_language); language_delete('fr'); - $this->rebuildContainer(); $result = \Drupal::languageManager()->getCurrentLanguage(); - $this->assertIdentical($result->id, 'en'); + $this->assertIdentical($result->id, $default_language->id); } } diff -u b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php --- b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php @@ -98,6 +98,7 @@ // 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 = language_default(); $language = new Language(array( 'id' => $langcode_browser_fallback, 'default' => TRUE, @@ -108,10 +109,6 @@ )); language_save($language); - // Saving a new default language will have deleted the container from PHP - // storage but we need to rebuild it to update the container in memory. - $this->rebuildContainer(); - // We will look for this string in the admin/config screen to see if the // corresponding translated string is shown. $default_string = 'Configure languages for content and the user interface'; @@ -120,7 +117,10 @@ $this->drupalGet('admin/config'); // Now the t()'ed string is in db so switch the language back to default. - \Drupal::config('system.site')->set('langcode', 'en')->save(); + // This will rebuild the container so we need to rebuild the container in + // the test environment. + language_save($default_language); + \Drupal::config('language.negotiation')->set('url.prefixes.en', '')->save(); $this->rebuildContainer(); // Translate the string. diff -u b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php --- b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php @@ -9,6 +9,7 @@ use Drupal\Component\Utility\String; use Drupal\Core\Language\Language; +use Drupal\Core\Language\LanguageDefault; use Drupal\Core\Language\LanguageManager; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl; @@ -95,7 +96,7 @@ // Change language negotiation options. drupal_load('module', 'locale'); // Pick only core language types. - $language_manager = new LanguageManager(new Language(Language::$defaultValues)); + $language_manager = new LanguageManager(new LanguageDefault(Language::$defaultValues)); $default_types = $language_manager->getLanguageTypes(); \Drupal::config('language.types')->set('configurable', $default_types + array('language_custom' => TRUE))->save(); $config = array_flip(array_keys(\Drupal::service('plugin.manager.language_negotiation_method')->getDefinitions())); diff -u b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php --- b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -973,7 +973,7 @@ // @todo Remove this once this class has no calls to t() and format_plural() $this->container->setParameter('language.default_values', Language::$defaultValues); - $this->container->register('language.default', 'Drupal\Core\Language\Language') + $this->container->register('language.default', 'Drupal\Core\Language\LanguageDefault') ->addArgument('%language.default_values%'); $this->container->register('language_manager', 'Drupal\Core\Language\LanguageManager') ->addArgument(new Reference('language.default')); only in patch2: unchanged: --- /dev/null +++ b/core/lib/Drupal/Core/Language/LanguageDefault.php @@ -0,0 +1,54 @@ +set(new Language($default_values)); + } + + /** + * Gets the default language. + * + * @return \Drupal\Core\Language\Language + * The default language. + */ + public function get() { + return $this->language; + } + + /** + * Sets the default language. + * + * @param \Drupal\Core\Language\Language $language + * The default language. + */ + public function set(Language $language) { + $language->default = TRUE; + $this->language = $language; + } + +} only in patch2: unchanged: --- a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php @@ -73,8 +73,6 @@ public function testLanguageBlockVisibility() { ); $this->drupalPostForm('admin/config/regional/settings', $edit, t('Save configuration')); - // Reset the static cache of the language list. - $this->container->get('language_manager')->reset(); // Check that a page has a block. $this->drupalGet('en'); $this->assertText('Powered by Drupal', 'The body of the custom block appears on the page.'); only in patch2: unchanged: --- a/core/modules/language/lib/Drupal/language/Entity/Language.php +++ b/core/modules/language/lib/Drupal/language/Entity/Language.php @@ -9,6 +9,7 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\language\Exception\DeleteDefaultLanguageException; use Drupal\language\LanguageInterface; /** @@ -97,4 +98,17 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { $this->langcode = 'en'; } + /** + * {@inheritdoc} + * + * @throws \RuntimeException + */ + public static function preDelete(EntityStorageControllerInterface $storage_controller, array $entities) { + $default_language = \Drupal::service('language.default')->get(); + foreach ($entities as $entity) { + if ($entity->id() == $default_language->id) { + throw new DeleteDefaultLanguageException('Can not delete the default language'); + } + } + } } only in patch2: unchanged: --- /dev/null +++ b/core/modules/language/lib/Drupal/language/Exception/DeleteDefaultLanguageException.php @@ -0,0 +1,13 @@ +assert(language_delete('en'), 'Deleted English language.'); + $this->drupalPostForm('admin/config/regional/language/delete/en', array(), t('Delete')); + $this->assertRaw(t('The %language (%langcode) language has been removed.', array('%language' => 'English', '%langcode' => 'en'))); $edit = array( 'predefined_langcode' => 'de', ); only in patch2: unchanged: --- a/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php @@ -50,6 +50,10 @@ function setUp() { // Delete English. $this->drupalPostForm('admin/config/regional/language/delete/en', array(), t('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'); only in patch2: unchanged: --- a/core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php @@ -80,11 +80,10 @@ protected function setUp() { $this->installLanguages(); // Assign Lolspeak (xx) to be the default language. - $edit = array('site_default_language' => 'xx'); - $this->drupalPostForm('admin/config/regional/settings', $edit, t('Save configuration')); - - // Reset the static cache of the language list. - $this->container->get('language_manager')->reset(); + $language = \Drupal::languageManager()->getLanguage('xx'); + $language->default = TRUE; + language_save($language); + $this->rebuildContainer(); // Check that lolspeak is the default language for the site. $this->assertEqual(language_default()->id, 'xx', 'Lolspeak is the default language');