diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 02c97f5edbe4eaedee5908163bdaa97a143b9233..260e4772f3cf0e97e6f08bdb66d35124e513621f 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -916,6 +916,7 @@ protected function initializeContainer() { // new session into the master request if one was present before. if (($request_stack = $this->container->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE))) { if ($request = $request_stack->getMasterRequest()) { + $subrequest = TRUE; if ($request->hasSession()) { $request->setSession($this->container->get('session')); } @@ -928,6 +929,12 @@ protected function initializeContainer() { \Drupal::setContainer($this->container); + // Allow other parts of the codebase to react on container initialization in + // subrequest. + if (!empty($subrequest)) { + $this->container->get('event_dispatcher')->dispatch(self::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED); + } + // If needs dumping flag was set, dump the container. if ($this->containerNeedsDumping && !$this->cacheDrupalContainer($container_definition)) { $this->container->get('logger.factory')->get('DrupalKernel')->error('Container cannot be saved to cache.'); diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php index c38fff5db938b71caf0a0e6759e6066c9eb22372..ff065a8f8240c2409479704b00b31391ab5a95ab 100644 --- a/core/lib/Drupal/Core/DrupalKernelInterface.php +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php @@ -14,6 +14,16 @@ */ interface DrupalKernelInterface extends HttpKernelInterface, ContainerAwareInterface { + /** + * Event fired when the service container finished initializing in subrequest. + * + * This event allows you to initialize overrides such as language to the + * services. + * + * @var string + */ + const CONTAINER_INITIALIZE_SUBREQUEST_FINISHED = 'kernel.container.finish_container_initialize_subrequest'; + /** * Boots the current kernel. * diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationCacheTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationCacheTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4abfd57d392f85b4f2db36762b3f5f74e0da8568 --- /dev/null +++ b/core/modules/config_translation/src/Tests/ConfigTranslationCacheTest.php @@ -0,0 +1,176 @@ +getPermissionName(), + $full_html_format->getPermissionName(), + $filter_test_format->getPermissionName(), + 'access site-wide contact form', + 'access contextual links', + 'administer account settings', + 'administer themes', + 'bypass node access', + 'administer content types', + 'translate interface', + 'administer entity_test fields', + ]); + // Create and login user. + $this->translatorUser = $this->drupalCreateUser($translator_permissions); + $this->adminUser = $this->drupalCreateUser($admin_permissions); + + // Add languages. + foreach ($this->langcodes as $langcode) { + ConfigurableLanguage::createFromLangcode($langcode)->save(); + } + $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); + } + + /** + * Tests the translation of field and field storage configuration. + */ + public function testFieldConfigTranslation() { + // Add a test field which has a translatable field setting and a + // translatable field storage setting. + $field_name = strtolower($this->randomMachineName()); + $field_storage = FieldStorageConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ]); + + $translatable_storage_setting = $this->randomString(); + $field_storage->setSetting('translatable_storage_setting', $translatable_storage_setting); + $field_storage->save(); + + $bundle = strtolower($this->randomMachineName()); + entity_test_create_bundle($bundle); + $field = FieldConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'bundle' => $bundle, + ]); + + $translatable_field_setting = $this->randomString(); + $field->setSetting('translatable_field_setting', $translatable_field_setting); + $field->save(); + + $this->drupalLogin($this->translatorUser); + + $this->drupalGet("/entity_test/structure/$bundle/fields/entity_test.$bundle.$field_name/translate"); + $this->clickLink('Add'); + + $this->assertText('Translatable field setting'); + $this->assertEscaped($translatable_field_setting); + $this->assertText('Translatable storage setting'); + $this->assertEscaped($translatable_storage_setting); + + // Add translation for label. + $field_label_fr = $this->randomString(); + $edit = [ + "translation[config_names][field.field.entity_test.$bundle.$field_name][label]" => $field_label_fr, + ]; + $this->drupalPostForm(NULL, $edit, 'Save translation'); + $this->drupalLogout(); + + // Check if the translated label appears. + $this->drupalLogin($this->adminUser); + $this->drupalGet("/fr/entity_test/structure/$bundle/fields"); + $this->assertEscaped($field_label_fr); + + // Clear cache on French version and check for translated label. + $this->drupalPostForm('/fr/admin/config/development/performance', [], 'Clear all caches'); + $this->drupalGet("/fr/entity_test/structure/$bundle/fields"); + // Check if the translation is still there. + $this->assertEscaped($field_label_fr); + + // Clear cache on default version and check for translated label. + $this->drupalPostForm('/admin/config/development/performance', [], 'Clear all caches'); + $this->drupalGet("/fr/entity_test/structure/$bundle/fields"); + // Check if the translation is still there. + $this->assertEscaped($field_label_fr); + } + +} diff --git a/core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php b/core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php index 37a6048a6645d084cefa80f3019d3d8099fe44c7..9e5729aff7f3b3fe830e0361e1829b17ffffc3a1 100644 --- a/core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php +++ b/core/modules/language/src/EventSubscriber/LanguageRequestSubscriber.php @@ -2,6 +2,7 @@ namespace Drupal\language\EventSubscriber; +use Drupal\Core\DrupalKernelInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\Translator\TranslatorInterface; use Drupal\language\ConfigurableLanguageManagerInterface; @@ -64,25 +65,39 @@ public function __construct(ConfigurableLanguageManagerInterface $language_manag } /** - * Sets the default language and initializes configuration overrides. + * Initializes the language manager at the beginning of the request. * * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event * The Event to process. */ public function onKernelRequestLanguage(GetResponseEvent $event) { if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { - $this->negotiator->setCurrentUser($this->currentUser); - if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) { - $this->languageManager->setNegotiator($this->negotiator); - $this->languageManager->setConfigOverrideLanguage($this->languageManager->getCurrentLanguage()); - } - // After the language manager has initialized, set the default langcode - // for the string translations. - $langcode = $this->languageManager->getCurrentLanguage()->getId(); - $this->translation->setDefaultLangcode($langcode); + $this->setLanguageOverrides(); } } + /** + * Initializes config overrides whenever the service container is rebuilt. + */ + public function onContainerInitializeSubrequestFinished() { + $this->setLanguageOverrides(); + } + + /** + * Sets the language for config overrides on the language manager. + */ + private function setLanguageOverrides() { + $this->negotiator->setCurrentUser($this->currentUser); + if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) { + $this->languageManager->setNegotiator($this->negotiator); + $this->languageManager->setConfigOverrideLanguage($this->languageManager->getCurrentLanguage()); + } + // After the language manager has initialized, set the default langcode for + // the string translations. + $langcode = $this->languageManager->getCurrentLanguage()->getId(); + $this->translation->setDefaultLangcode($langcode); + } + /** * Registers the methods in this class that should be listeners. * @@ -91,6 +106,7 @@ public function onKernelRequestLanguage(GetResponseEvent $event) { */ public static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = ['onKernelRequestLanguage', 255]; + $events[DrupalKernelInterface::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED][] = ['onContainerInitializeSubrequestFinished', 255]; return $events; }