diff -u b/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php --- b/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -87,25 +87,18 @@ /** * {@inheritdoc} */ - public function installDefaultConfig($type, $name) { + public function getConfigToInstall($type, $name, $collection = StorageInterface::DEFAULT_COLLECTION) { // Get all default configuration owned by this extension. - $source_storage = $this->getSourceStorage(); + $source_storage = $this->getSourceStorage($collection); $config_to_install = $source_storage->listAll($name . '.'); $extension_path = drupal_get_path($type, $name); - // If the extension provides configuration schema clear the definitions. - if (is_dir($extension_path . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY)) { - // Refresh the schema cache if installing default configuration and the - // extension has a configuration schema directory. - $this->typedConfig->clearCachedDefinitions(); - } - // If not installing the core base system default configuration, work out if // this extension provides default configuration for any other enabled // extensions. if ($type !== 'core' && is_dir($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY)) { $enabled_extensions = $other_module_config = array(); - $default_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY); + $default_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection); $other_module_config = array_filter($default_storage->listAll(), function ($value) use ($name) { return !preg_match('/^' . $name . '\./', $value); }); @@ -123,10 +116,26 @@ $config_to_install = array_merge($config_to_install, $other_module_config); } + return $config_to_install; + } + + /** + * {@inheritdoc} + */ + public function installDefaultConfig($type, $name) { + $extension_path = drupal_get_path($type, $name); + // If the extension provides configuration schema clear the definitions. + if (is_dir($extension_path . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY)) { + // Refresh the schema cache if installing default configuration and the + // extension has a configuration schema directory. + $this->typedConfig->clearCachedDefinitions(); + } + + $config_to_install = $this->getConfigToInstall($type, $name); if (!empty($config_to_install)) { // Order the configuration to install in the order of dependencies. - $data = $source_storage->readMultiple($config_to_install); + $data = $this->getSourceStorage()->readMultiple($config_to_install); $dependency_manager = new ConfigDependencyManager(); $sorted_config = $dependency_manager ->setData($data) @@ -206,16 +215,16 @@ } /** - * Gets the configuration storage that provides the default configuration. - * - * @return \Drupal\Core\Config\StorageInterface - * The configuration storage that provides the default configuration. + * {@inheritdoc} */ - public function getSourceStorage() { + public function getSourceStorage($collection = StorageInterface::DEFAULT_COLLECTION) { if (!isset($this->sourceStorage)) { // Default to using the ExtensionInstallStorage which searches extension's // config directories for default configuration. - $this->sourceStorage = new ExtensionInstallStorage($this->activeStorage); + $this->sourceStorage = new ExtensionInstallStorage($this->activeStorage, ExtensionInstallStorage::CONFIG_INSTALL_DIRECTORY, $collection); + } + if ($this->sourceStorage->getCollectionName() != $collection) { + $this->sourceStorage = $this->sourceStorage->createCollection($collection); } return $this->sourceStorage; } diff -u b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php --- b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php @@ -75,4 +75,16 @@ return $this->folders; } + + /** + * {@inheritdoc} + */ + public function createCollection($collection) { + return new static( + $this->configStorage, + $this->directory, + $collection + ); + } + } reverted: --- b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php +++ a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php @@ -32,14 +32,6 @@ public function setUp() { parent::setUp(); - language_save(new Language(array( - 'name' => 'French', - 'id' => 'fr', - ))); - language_save(new Language(array( - 'name' => 'German', - 'id' => 'de', - ))); $this->installConfig(array('config_test')); } @@ -58,6 +50,15 @@ $raw = $config->getRawData(); $this->assertIdentical($raw['foo'], 'bar'); + language_save(new Language(array( + 'name' => 'French', + 'id' => 'fr', + ))); + language_save(new Language(array( + 'name' => 'German', + 'id' => 'de', + ))); + \Drupal::languageManager()->setConfigOverrideLanguage(language_load('fr')); $config = \Drupal::config('config_test.system'); $this->assertIdentical($config->get('foo'), 'fr bar'); diff -u b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php --- b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php @@ -7,8 +7,8 @@ namespace Drupal\language\Config; +use Drupal\Component\Utility\Unicode; use Drupal\Core\Config\ExtensionInstallStorage; -use Drupal\Core\Config\FileStorage; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Language\Language; @@ -142,14 +142,18 @@ * {@inheritdoc} */ public function install($type, $name) { + $config_installer = \Drupal::service('config.installer'); // Work out if this extension provides default language overrides. foreach (\Drupal::languageManager()->getLanguages() as $language) { - $install_storage = new ExtensionInstallStorage($this->baseStorage, ExtensionInstallStorage::CONFIG_INSTALL_DIRECTORY, $this->createConfigCollectionName($language->getId())); + $collection = $this->createConfigCollectionName($language->getId()); + $config_to_install = $config_installer->getConfigToInstall($type, $name, $collection); $storage = $this->getStorage($language->getId()); - foreach ($install_storage->listAll() as $config_name) { - $data = $install_storage->read($config_name); + // Remove configuration that already exists in the active storage. + $config_to_install = array_diff($config_to_install, $storage->listAll()); + $data = $config_installer->getSourceStorage($collection)->readMultiple($config_to_install); + foreach ($data as $config_name => $config_data) { $config = new LanguageConfigOverride($config_name, $storage, $this->typedConfigManager); - $config->setData($data)->save(); + $config->setData($config_data)->save(); } } } @@ -157,6 +161,31 @@ /** * {@inheritdoc} */ + public function installLanguageOverrides($langcode) { + $enabled_extensions = array(); + $extension_config = $this->baseStorage->read('core.extension'); + $enabled_extensions += array_keys($extension_config['module']); + $enabled_extensions += array_keys($extension_config['theme']); + + $install_storage = new ExtensionInstallStorage($this->baseStorage, ExtensionInstallStorage::CONFIG_INSTALL_DIRECTORY, $this->createConfigCollectionName($langcode)); + $storage = $this->getStorage($langcode); + + $config_to_install = $install_storage->listAll(); + // Only install language overrides for enable modules. + $config_to_install = array_filter($config_to_install, function ($config_name) use ($enabled_extensions) { + $provider = Unicode::substr($config_name, 0, strpos($config_name, '.')); + return in_array($provider, $enabled_extensions); + }); + foreach ($config_to_install as $config_name) { + $data = $install_storage->read($config_name); + $config = new LanguageConfigOverride($config_name, $storage, $this->typedConfigManager); + $config->setData($data)->save(); + } + } + + /** + * {@inheritdoc} + */ public function uninstall($type, $name) { foreach (\Drupal::languageManager()->getLanguages() as $language) { $storage = $this->getStorage($language->getId()); diff -u b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php --- b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php +++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php @@ -70,2 +70,10 @@ + /** + * Installs available language configuration overrides for a given langcode. + * + * @param string $langcode + * Language code. + */ + public function installLanguageOverrides($langcode); + } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php +++ b/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php @@ -13,6 +13,28 @@ interface ConfigInstallerInterface { /** + * Gets a list of configuration object names to install. + * + * It searches all the default configuration directories for all installed + * extensions to locate any configuration with its name prefix. Additionally, + * the default configuration directory for the extension being installed is + * searched to discover if it contains default configuration that is owned by + * other enabled extensions. + * + * @param string $type + * The extension type; e.g., 'module' or 'theme'. + * @param string $name + * The name of the module or theme to install default configuration for. + * @param string $collection + * (optional) The configuration collection. Defaults to the default + * collection. + * + * @return array + * The list of configuration object names to install. + */ + public function getConfigToInstall($type, $name, $collection = StorageInterface::DEFAULT_COLLECTION); + + /** * Installs the default configuration of a given extension. * * When an extension is installed, it searches all the default configuration @@ -48,6 +70,17 @@ public function installDefaultConfig($type, $name); public function setSourceStorage(StorageInterface $storage); /** + * Gets the configuration storage that provides the default configuration. + * + * @param string $collection + * The configuration collection. + * + * @return \Drupal\Core\Config\StorageInterface + * The configuration storage that provides the default configuration. + */ + public function getSourceStorage($collection = StorageInterface::DEFAULT_COLLECTION); + + /** * Resets the configuration storage that provides the default configuration. * * @return self only in patch2: unchanged: --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -441,6 +441,8 @@ function language_save($language) { $language_entity->save(); $t_args = array('%language' => $language->name, '%langcode' => $language->id); if ($language->is_new) { + // Install any available language configuration overrides for the language. + \Drupal::service('language.config_factory_override')->installLanguageOverrides($language->getId()); watchdog('language', 'The %language (%langcode) language has been created.', $t_args); } else { only in patch2: unchanged: --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php @@ -42,7 +42,7 @@ public function testHasTranslation() { $this->installConfig(array('locale_test')); $locale_config_manager = \Drupal::service('locale.config.typed'); - $language = new Language(array('id' => 'de')); + $language = language_save(new Language(array('id' => 'de'))); $result = $locale_config_manager->hasTranslation('locale_test.no_translation', $language); $this->assertFalse($result, 'There is no translation for locale_test.no_translation configuration.');