Chris@0: setUpDefaultLanguage(); Chris@0: Chris@0: $this->installSchema('locale', ['locales_source', 'locales_target', 'locales_location']); Chris@0: Chris@0: $this->setupLanguages(); Chris@0: Chris@0: $this->installConfig(['locale_test']); Chris@0: // Simulate this hook invoked which would happen if in a non-kernel test Chris@0: // or normal environment. Chris@0: // @see locale_modules_installed() Chris@0: // @see locale_system_update() Chris@0: locale_system_set_config_langcodes(); Chris@0: $langcodes = array_keys(\Drupal::languageManager()->getLanguages()); Chris@0: $names = Locale::config()->getComponentNames(); Chris@0: Locale::config()->updateConfigTranslations($names, $langcodes); Chris@0: Chris@0: $this->configFactory = $this->container->get('config.factory'); Chris@0: $this->stringStorage = $this->container->get('locale.storage'); Chris@0: $this->localeConfigManager = $this->container->get('locale.config_manager'); Chris@0: $this->languageManager = $this->container->get('language_manager'); Chris@0: Chris@0: $this->setUpLocale(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets up default language for this test. Chris@0: */ Chris@0: protected function setUpDefaultLanguage() { Chris@0: // Keep the default English. Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets up languages needed for this test. Chris@0: */ Chris@0: protected function setUpLanguages() { Chris@0: ConfigurableLanguage::createFromLangcode('de')->save(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets up the locale storage strings to be in line with configuration. Chris@0: */ Chris@0: protected function setUpLocale() { Chris@0: // Set up the locale database the same way we have in the config samples. Chris@0: $this->setUpNoTranslation('locale_test.no_translation', 'test', 'Test', 'de'); Chris@0: $this->setUpTranslation('locale_test.translation', 'test', 'English test', 'German test', 'de'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests creating translations of shipped configuration. Chris@0: */ Chris@0: public function testCreateTranslation() { Chris@0: $config_name = 'locale_test.no_translation'; Chris@0: Chris@0: $this->saveLanguageOverride($config_name, 'test', 'Test (German)', 'de'); Chris@0: $this->assertTranslation($config_name, 'Test (German)', 'de'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests importing community translations of shipped configuration. Chris@0: */ Chris@0: public function testLocaleCreateTranslation() { Chris@0: $config_name = 'locale_test.no_translation'; Chris@0: Chris@0: $this->saveLocaleTranslationData($config_name, 'test', 'Test', 'Test (German)', 'de'); Chris@0: $this->assertTranslation($config_name, 'Test (German)', 'de', FALSE); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests updating translations of shipped configuration. Chris@0: */ Chris@0: public function testUpdateTranslation() { Chris@0: $config_name = 'locale_test.translation'; Chris@0: Chris@0: $this->saveLanguageOverride($config_name, 'test', 'Updated German test', 'de'); Chris@0: $this->assertTranslation($config_name, 'Updated German test', 'de'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests updating community translations of shipped configuration. Chris@0: */ Chris@0: public function testLocaleUpdateTranslation() { Chris@0: $config_name = 'locale_test.translation'; Chris@0: Chris@0: $this->saveLocaleTranslationData($config_name, 'test', 'English test', 'Updated German test', 'de'); Chris@0: $this->assertTranslation($config_name, 'Updated German test', 'de', FALSE); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests deleting translations of shipped configuration. Chris@0: */ Chris@0: public function testDeleteTranslation() { Chris@0: $config_name = 'locale_test.translation'; Chris@0: Chris@0: $this->deleteLanguageOverride($config_name, 'test', 'English test', 'de'); Chris@0: // Instead of deleting the translation, we need to keep a translation with Chris@0: // the source value and mark it as customized to prevent the deletion being Chris@0: // reverted by importing community translations. Chris@0: $this->assertTranslation($config_name, 'English test', 'de'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests deleting community translations of shipped configuration. Chris@0: */ Chris@0: public function testLocaleDeleteTranslation() { Chris@0: $config_name = 'locale_test.translation'; Chris@0: Chris@0: $this->deleteLocaleTranslationData($config_name, 'test', 'English test', 'de'); Chris@0: $this->assertNoTranslation($config_name, 'de'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets up a configuration string without a translation. Chris@0: * Chris@0: * The actual configuration is already available by installing locale_test Chris@0: * module, as it is done in LocaleConfigSubscriberTest::setUp(). This sets up Chris@0: * the necessary source string and verifies that everything is as expected to Chris@0: * avoid false positives. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $source Chris@0: * The source string. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: */ Chris@0: protected function setUpNoTranslation($config_name, $key, $source, $langcode) { Chris@0: $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]); Chris@0: $this->assertNoConfigOverride($config_name, $key, $source, $langcode); Chris@0: $this->assertNoTranslation($config_name, $langcode); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets up a configuration string with a translation. Chris@0: * Chris@0: * The actual configuration is already available by installing locale_test Chris@0: * module, as it is done in LocaleConfigSubscriberTest::setUp(). This sets up Chris@0: * the necessary source and translation strings and verifies that everything Chris@0: * is as expected to avoid false positives. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $source Chris@0: * The source string. Chris@0: * @param string $translation Chris@0: * The translation string. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * @param bool $is_active Chris@0: * Whether the update will affect the active configuration. Chris@0: */ Chris@0: protected function setUpTranslation($config_name, $key, $source, $translation, $langcode, $is_active = FALSE) { Chris@0: // Create source and translation strings for the configuration value and add Chris@0: // the configuration name as a location. This would be performed by Chris@0: // locale_translate_batch_import() invoking Chris@0: // LocaleConfigManager::updateConfigTranslations() normally. Chris@0: $this->localeConfigManager->reset(); Chris@0: $this->localeConfigManager Chris@0: ->getStringTranslation($config_name, $langcode, $source, '') Chris@0: ->setString($translation) Chris@0: ->setCustomized(FALSE) Chris@0: ->save(); Chris@0: $this->configFactory->reset($config_name); Chris@0: $this->localeConfigManager->reset(); Chris@0: $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]); Chris@0: Chris@0: if ($is_active) { Chris@0: $this->assertActiveConfig($config_name, $key, $translation, $langcode); Chris@0: } Chris@0: else { Chris@0: $this->assertConfigOverride($config_name, $key, $translation, $langcode); Chris@0: } Chris@0: $this->assertTranslation($config_name, $translation, $langcode, FALSE); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Saves a language override. Chris@0: * Chris@0: * This will invoke LocaleConfigSubscriber through the event dispatcher. To Chris@0: * make sure the configuration was persisted correctly, the configuration Chris@0: * value is checked. Because LocaleConfigSubscriber temporarily disables the Chris@0: * override state of the configuration factory we check that the correct value Chris@0: * is restored afterwards. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $value Chris@0: * The configuration value to save. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: */ Chris@0: protected function saveLanguageOverride($config_name, $key, $value, $langcode) { Chris@0: $translation_override = $this->languageManager Chris@0: ->getLanguageConfigOverride($langcode, $config_name); Chris@0: $translation_override Chris@0: ->set($key, $value) Chris@0: ->save(); Chris@0: $this->configFactory->reset($config_name); Chris@0: Chris@0: $this->assertConfigOverride($config_name, $key, $value, $langcode); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Saves translation data from locale module. Chris@0: * Chris@0: * This will invoke LocaleConfigSubscriber through the event dispatcher. To Chris@0: * make sure the configuration was persisted correctly, the configuration Chris@0: * value is checked. Because LocaleConfigSubscriber temporarily disables the Chris@0: * override state of the configuration factory we check that the correct value Chris@0: * is restored afterwards. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $source Chris@0: * The source string. Chris@0: * @param string $translation Chris@0: * The translation string to save. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * @param bool $is_active Chris@0: * Whether the update will affect the active configuration. Chris@0: */ Chris@0: protected function saveLocaleTranslationData($config_name, $key, $source, $translation, $langcode, $is_active = FALSE) { Chris@0: $this->localeConfigManager->reset(); Chris@0: $this->localeConfigManager Chris@0: ->getStringTranslation($config_name, $langcode, $source, '') Chris@0: ->setString($translation) Chris@0: ->save(); Chris@0: $this->localeConfigManager->reset(); Chris@0: $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]); Chris@0: $this->configFactory->reset($config_name); Chris@0: Chris@0: if ($is_active) { Chris@0: $this->assertActiveConfig($config_name, $key, $translation, $langcode); Chris@0: } Chris@0: else { Chris@0: $this->assertConfigOverride($config_name, $key, $translation, $langcode); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes a language override. Chris@0: * Chris@0: * This will invoke LocaleConfigSubscriber through the event dispatcher. To Chris@0: * make sure the configuration was persisted correctly, the configuration Chris@0: * value is checked. Because LocaleConfigSubscriber temporarily disables the Chris@0: * override state of the configuration factory we check that the correct value Chris@0: * is restored afterwards. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $source_value Chris@0: * The source configuration value to verify the correct value is returned Chris@0: * from the configuration factory after the deletion. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: */ Chris@0: protected function deleteLanguageOverride($config_name, $key, $source_value, $langcode) { Chris@0: $translation_override = $this->languageManager Chris@0: ->getLanguageConfigOverride($langcode, $config_name); Chris@0: $translation_override Chris@0: ->clear($key) Chris@0: ->save(); Chris@0: $this->configFactory->reset($config_name); Chris@0: Chris@0: $this->assertNoConfigOverride($config_name, $key, $source_value, $langcode); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Deletes translation data from locale module. Chris@0: * Chris@0: * This will invoke LocaleConfigSubscriber through the event dispatcher. To Chris@0: * make sure the configuration was persisted correctly, the configuration Chris@0: * value is checked. Because LocaleConfigSubscriber temporarily disables the Chris@0: * override state of the configuration factory we check that the correct value Chris@0: * is restored afterwards. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $source_value Chris@0: * The source configuration value to verify the correct value is returned Chris@0: * from the configuration factory after the deletion. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: */ Chris@0: protected function deleteLocaleTranslationData($config_name, $key, $source_value, $langcode) { Chris@0: $this->localeConfigManager Chris@0: ->getStringTranslation($config_name, $langcode, $source_value, '') Chris@0: ->delete(); Chris@0: $this->localeConfigManager->reset(); Chris@0: $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]); Chris@0: $this->configFactory->reset($config_name); Chris@0: Chris@0: $this->assertNoConfigOverride($config_name, $key, $source_value, $langcode); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures configuration override is not present anymore. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the assertion succeeded, FALSE otherwise. Chris@0: */ Chris@0: protected function assertNoConfigOverride($config_name, $langcode) { Chris@0: $config_langcode = $this->configFactory->getEditable($config_name)->get('langcode'); Chris@0: $override = $this->languageManager->getLanguageConfigOverride($langcode, $config_name); Chris@0: return $this->assertNotEqual($config_langcode, $langcode) && $this->assertEqual($override->isNew(), TRUE); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures configuration was saved correctly. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $value Chris@0: * The configuration value. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the assertion succeeded, FALSE otherwise. Chris@0: */ Chris@0: protected function assertConfigOverride($config_name, $key, $value, $langcode) { Chris@0: $config_langcode = $this->configFactory->getEditable($config_name)->get('langcode'); Chris@0: $override = $this->languageManager->getLanguageConfigOverride($langcode, $config_name); Chris@0: return $this->assertNotEqual($config_langcode, $langcode) && $this->assertEqual($override->get($key), $value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures configuration was saved correctly. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $key Chris@0: * The configuration key. Chris@0: * @param string $value Chris@0: * The configuration value. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the assertion succeeded, FALSE otherwise. Chris@0: */ Chris@0: protected function assertActiveConfig($config_name, $key, $value, $langcode) { Chris@0: $config = $this->configFactory->getEditable($config_name); Chris@18: return $this->assertEqual($config->get('langcode'), $langcode) && Chris@0: $this->assertIdentical($config->get($key), $value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures no translation exists. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the assertion succeeded, FALSE otherwise. Chris@0: */ Chris@0: protected function assertNoTranslation($config_name, $langcode) { Chris@0: $strings = $this->stringStorage->getTranslations([ Chris@0: 'type' => 'configuration', Chris@0: 'name' => $config_name, Chris@0: 'language' => $langcode, Chris@0: 'translated' => TRUE, Chris@0: ]); Chris@0: return $this->assertIdentical([], $strings); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures a translation exists and is marked as customized. Chris@0: * Chris@0: * @param string $config_name Chris@0: * The configuration name. Chris@0: * @param string $translation Chris@0: * The translation. Chris@0: * @param string $langcode Chris@0: * The language code. Chris@0: * @param bool $customized Chris@0: * Whether or not the string should be asserted to be customized or not Chris@0: * customized. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the assertion succeeded, FALSE otherwise. Chris@0: */ Chris@0: protected function assertTranslation($config_name, $translation, $langcode, $customized = TRUE) { Chris@0: // Make sure a string exists. Chris@0: $strings = $this->stringStorage->getTranslations([ Chris@0: 'type' => 'configuration', Chris@0: 'name' => $config_name, Chris@0: 'language' => $langcode, Chris@0: 'translated' => TRUE, Chris@0: ]); Chris@0: $pass = $this->assertIdentical(1, count($strings)); Chris@0: $string = reset($strings); Chris@0: if ($this->assertTrue($string instanceof StringInterface)) { Chris@0: /** @var \Drupal\locale\StringInterface $string */ Chris@0: $pass = $pass && $this->assertIdentical($translation, $string->getString()); Chris@0: $pass = $pass && $this->assertTrue($string->isTranslation()); Chris@0: if ($this->assertTrue($string instanceof TranslationString)) { Chris@0: /** @var \Drupal\locale\TranslationString $string */ Chris@0: // Make sure the string is marked as customized so that it does not get Chris@0: // overridden when the string translations are updated. Chris@0: return $pass && $this->assertEqual($customized, $string->customized); Chris@0: } Chris@0: } Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: }