128b7b1d30c23660c81510122d2af7db43472bf1
[yaffs-website] / web / core / modules / locale / tests / src / Kernel / LocaleConfigSubscriberTest.php
1 <?php
2
3 namespace Drupal\Tests\locale\Kernel;
4
5 use Drupal\language\Entity\ConfigurableLanguage;
6 use Drupal\locale\Locale;
7 use Drupal\locale\StringInterface;
8 use Drupal\locale\TranslationString;
9 use Drupal\KernelTests\KernelTestBase;
10
11 /**
12  * Tests that shipped configuration translations are updated correctly.
13  *
14  * @group locale
15  */
16 class LocaleConfigSubscriberTest extends KernelTestBase {
17
18   /**
19    * {@inheritdoc}
20    */
21   public static $modules = ['language', 'locale', 'system', 'locale_test'];
22
23   /**
24    * The configurable language manager used in this test.
25    *
26    * @var \Drupal\language\ConfigurableLanguageManagerInterface
27    */
28   protected $languageManager;
29
30   /**
31    * The configuration factory used in this test.
32    *
33    * @var \Drupal\Core\Config\ConfigFactoryInterface
34    */
35   protected $configFactory;
36
37   /**
38    * The string storage used in this test.
39    *
40    * @var \Drupal\locale\StringStorageInterface
41    */
42   protected $stringStorage;
43
44   /**
45    * The locale configuration manager used in this test.
46    *
47    * @var \Drupal\locale\LocaleConfigManager
48    */
49   protected $localeConfigManager;
50
51   /**
52    * {@inheritdoc}
53    */
54   protected function setUp() {
55     parent::setUp();
56
57     $this->setUpDefaultLanguage();
58
59     $this->installSchema('locale', ['locales_source', 'locales_target', 'locales_location']);
60
61     $this->setupLanguages();
62
63     $this->installConfig(['locale_test']);
64     // Simulate this hook invoked which would happen if in a non-kernel test
65     // or normal environment.
66     // @see locale_modules_installed()
67     // @see locale_system_update()
68     locale_system_set_config_langcodes();
69     $langcodes = array_keys(\Drupal::languageManager()->getLanguages());
70     $names = Locale::config()->getComponentNames();
71     Locale::config()->updateConfigTranslations($names, $langcodes);
72
73     $this->configFactory = $this->container->get('config.factory');
74     $this->stringStorage = $this->container->get('locale.storage');
75     $this->localeConfigManager = $this->container->get('locale.config_manager');
76     $this->languageManager = $this->container->get('language_manager');
77
78     $this->setUpLocale();
79   }
80
81   /**
82    * Sets up default language for this test.
83    */
84   protected function setUpDefaultLanguage() {
85     // Keep the default English.
86   }
87
88   /**
89    * Sets up languages needed for this test.
90    */
91   protected function setUpLanguages() {
92     ConfigurableLanguage::createFromLangcode('de')->save();
93   }
94
95   /**
96    * Sets up the locale storage strings to be in line with configuration.
97    */
98   protected function setUpLocale() {
99     // Set up the locale database the same way we have in the config samples.
100     $this->setUpNoTranslation('locale_test.no_translation', 'test', 'Test', 'de');
101     $this->setUpTranslation('locale_test.translation', 'test', 'English test', 'German test', 'de');
102   }
103
104   /**
105    * Tests creating translations of shipped configuration.
106    */
107   public function testCreateTranslation() {
108     $config_name = 'locale_test.no_translation';
109
110     $this->saveLanguageOverride($config_name, 'test', 'Test (German)', 'de');
111     $this->assertTranslation($config_name, 'Test (German)', 'de');
112   }
113
114   /**
115    * Tests importing community translations of shipped configuration.
116    */
117   public function testLocaleCreateTranslation() {
118     $config_name = 'locale_test.no_translation';
119
120     $this->saveLocaleTranslationData($config_name, 'test', 'Test', 'Test (German)', 'de');
121     $this->assertTranslation($config_name, 'Test (German)', 'de', FALSE);
122   }
123
124   /**
125    * Tests updating translations of shipped configuration.
126    */
127   public function testUpdateTranslation() {
128     $config_name = 'locale_test.translation';
129
130     $this->saveLanguageOverride($config_name, 'test', 'Updated German test', 'de');
131     $this->assertTranslation($config_name, 'Updated German test', 'de');
132   }
133
134   /**
135    * Tests updating community translations of shipped configuration.
136    */
137   public function testLocaleUpdateTranslation() {
138     $config_name = 'locale_test.translation';
139
140     $this->saveLocaleTranslationData($config_name, 'test', 'English test', 'Updated German test', 'de');
141     $this->assertTranslation($config_name, 'Updated German test', 'de', FALSE);
142   }
143
144   /**
145    * Tests deleting translations of shipped configuration.
146    */
147   public function testDeleteTranslation() {
148     $config_name = 'locale_test.translation';
149
150     $this->deleteLanguageOverride($config_name, 'test', 'English test', 'de');
151     // Instead of deleting the translation, we need to keep a translation with
152     // the source value and mark it as customized to prevent the deletion being
153     // reverted by importing community translations.
154     $this->assertTranslation($config_name, 'English test', 'de');
155   }
156
157   /**
158    * Tests deleting community translations of shipped configuration.
159    */
160   public function testLocaleDeleteTranslation() {
161     $config_name = 'locale_test.translation';
162
163     $this->deleteLocaleTranslationData($config_name, 'test', 'English test', 'de');
164     $this->assertNoTranslation($config_name, 'de');
165   }
166
167   /**
168    * Sets up a configuration string without a translation.
169    *
170    * The actual configuration is already available by installing locale_test
171    * module, as it is done in LocaleConfigSubscriberTest::setUp(). This sets up
172    * the necessary source string and verifies that everything is as expected to
173    * avoid false positives.
174    *
175    * @param string $config_name
176    *   The configuration name.
177    * @param string $key
178    *   The configuration key.
179    * @param string $source
180    *   The source string.
181    * @param string $langcode
182    *   The language code.
183    */
184   protected function setUpNoTranslation($config_name, $key, $source, $langcode) {
185     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
186     $this->assertNoConfigOverride($config_name, $key, $source, $langcode);
187     $this->assertNoTranslation($config_name, $langcode);
188   }
189
190   /**
191    * Sets up a configuration string with a translation.
192    *
193    * The actual configuration is already available by installing locale_test
194    * module, as it is done in LocaleConfigSubscriberTest::setUp(). This sets up
195    * the necessary source and translation strings and verifies that everything
196    * is as expected to avoid false positives.
197    *
198    * @param string $config_name
199    *   The configuration name.
200    * @param string $key
201    *   The configuration key.
202    * @param string $source
203    *   The source string.
204    * @param string $translation
205    *   The translation string.
206    * @param string $langcode
207    *   The language code.
208    * @param bool $is_active
209    *   Whether the update will affect the active configuration.
210    */
211   protected function setUpTranslation($config_name, $key, $source, $translation, $langcode, $is_active = FALSE) {
212     // Create source and translation strings for the configuration value and add
213     // the configuration name as a location. This would be performed by
214     // locale_translate_batch_import() invoking
215     // LocaleConfigManager::updateConfigTranslations() normally.
216     $this->localeConfigManager->reset();
217     $this->localeConfigManager
218       ->getStringTranslation($config_name, $langcode, $source, '')
219       ->setString($translation)
220       ->setCustomized(FALSE)
221       ->save();
222     $this->configFactory->reset($config_name);
223     $this->localeConfigManager->reset();
224     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
225
226     if ($is_active) {
227       $this->assertActiveConfig($config_name, $key, $translation, $langcode);
228     }
229     else {
230       $this->assertConfigOverride($config_name, $key, $translation, $langcode);
231     }
232     $this->assertTranslation($config_name, $translation, $langcode, FALSE);
233   }
234
235   /**
236    * Saves a language override.
237    *
238    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
239    * make sure the configuration was persisted correctly, the configuration
240    * value is checked. Because LocaleConfigSubscriber temporarily disables the
241    * override state of the configuration factory we check that the correct value
242    * is restored afterwards.
243    *
244    * @param string $config_name
245    *   The configuration name.
246    * @param string $key
247    *   The configuration key.
248    * @param string $value
249    *   The configuration value to save.
250    * @param string $langcode
251    *   The language code.
252    */
253   protected function saveLanguageOverride($config_name, $key, $value, $langcode) {
254     $translation_override = $this->languageManager
255       ->getLanguageConfigOverride($langcode, $config_name);
256     $translation_override
257       ->set($key, $value)
258       ->save();
259     $this->configFactory->reset($config_name);
260
261     $this->assertConfigOverride($config_name, $key, $value, $langcode);
262   }
263
264   /**
265    * Saves translation data from locale module.
266    *
267    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
268    * make sure the configuration was persisted correctly, the configuration
269    * value is checked. Because LocaleConfigSubscriber temporarily disables the
270    * override state of the configuration factory we check that the correct value
271    * is restored afterwards.
272    *
273    * @param string $config_name
274    *   The configuration name.
275    * @param string $key
276    *   The configuration key.
277    * @param string $source
278    *   The source string.
279    * @param string $translation
280    *   The translation string to save.
281    * @param string $langcode
282    *   The language code.
283    * @param bool $is_active
284    *   Whether the update will affect the active configuration.
285    */
286   protected function saveLocaleTranslationData($config_name, $key, $source, $translation, $langcode, $is_active = FALSE) {
287     $this->localeConfigManager->reset();
288     $this->localeConfigManager
289       ->getStringTranslation($config_name, $langcode, $source, '')
290       ->setString($translation)
291       ->save();
292     $this->localeConfigManager->reset();
293     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
294     $this->configFactory->reset($config_name);
295
296     if ($is_active) {
297       $this->assertActiveConfig($config_name, $key, $translation, $langcode);
298     }
299     else {
300       $this->assertConfigOverride($config_name, $key, $translation, $langcode);
301     }
302   }
303
304   /**
305    * Deletes a language override.
306    *
307    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
308    * make sure the configuration was persisted correctly, the configuration
309    * value is checked. Because LocaleConfigSubscriber temporarily disables the
310    * override state of the configuration factory we check that the correct value
311    * is restored afterwards.
312    *
313    * @param string $config_name
314    *   The configuration name.
315    * @param string $key
316    *   The configuration key.
317    * @param string $source_value
318    *   The source configuration value to verify the correct value is returned
319    *   from the configuration factory after the deletion.
320    * @param string $langcode
321    *   The language code.
322    */
323   protected function deleteLanguageOverride($config_name, $key, $source_value, $langcode) {
324     $translation_override = $this->languageManager
325       ->getLanguageConfigOverride($langcode, $config_name);
326     $translation_override
327       ->clear($key)
328       ->save();
329     $this->configFactory->reset($config_name);
330
331     $this->assertNoConfigOverride($config_name, $key, $source_value, $langcode);
332   }
333
334   /**
335    * Deletes translation data from locale module.
336    *
337    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
338    * make sure the configuration was persisted correctly, the configuration
339    * value is checked. Because LocaleConfigSubscriber temporarily disables the
340    * override state of the configuration factory we check that the correct value
341    * is restored afterwards.
342    *
343    * @param string $config_name
344    *   The configuration name.
345    * @param string $key
346    *   The configuration key.
347    * @param string $source_value
348    *   The source configuration value to verify the correct value is returned
349    *   from the configuration factory after the deletion.
350    * @param string $langcode
351    *   The language code.
352    */
353   protected function deleteLocaleTranslationData($config_name, $key, $source_value, $langcode) {
354     $this->localeConfigManager
355       ->getStringTranslation($config_name, $langcode, $source_value, '')
356       ->delete();
357     $this->localeConfigManager->reset();
358     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
359     $this->configFactory->reset($config_name);
360
361     $this->assertNoConfigOverride($config_name, $key, $source_value, $langcode);
362   }
363
364   /**
365    * Ensures configuration override is not present anymore.
366    *
367    * @param string $config_name
368    *   The configuration name.
369    * @param string $langcode
370    *   The language code.
371    *
372    * @return bool
373    *   TRUE if the assertion succeeded, FALSE otherwise.
374    */
375   protected function assertNoConfigOverride($config_name, $langcode) {
376     $config_langcode = $this->configFactory->getEditable($config_name)->get('langcode');
377     $override = $this->languageManager->getLanguageConfigOverride($langcode, $config_name);
378     return $this->assertNotEqual($config_langcode, $langcode) && $this->assertEqual($override->isNew(), TRUE);
379   }
380
381   /**
382    * Ensures configuration was saved correctly.
383    *
384    * @param string $config_name
385    *   The configuration name.
386    * @param string $key
387    *   The configuration key.
388    * @param string $value
389    *   The configuration value.
390    * @param string $langcode
391    *   The language code.
392    *
393    * @return bool
394    *   TRUE if the assertion succeeded, FALSE otherwise.
395    */
396   protected function assertConfigOverride($config_name, $key, $value, $langcode) {
397     $config_langcode = $this->configFactory->getEditable($config_name)->get('langcode');
398     $override = $this->languageManager->getLanguageConfigOverride($langcode, $config_name);
399     return $this->assertNotEqual($config_langcode, $langcode) && $this->assertEqual($override->get($key), $value);
400   }
401
402   /**
403    * Ensures configuration was saved correctly.
404    *
405    * @param string $config_name
406    *   The configuration name.
407    * @param string $key
408    *   The configuration key.
409    * @param string $value
410    *   The configuration value.
411    * @param string $langcode
412    *   The language code.
413    *
414    * @return bool
415    *   TRUE if the assertion succeeded, FALSE otherwise.
416    */
417   protected function assertActiveConfig($config_name, $key, $value, $langcode) {
418     $config = $this->configFactory->getEditable($config_name);
419     return
420       $this->assertEqual($config->get('langcode'), $langcode) &&
421       $this->assertIdentical($config->get($key), $value);
422   }
423
424   /**
425    * Ensures no translation exists.
426    *
427    * @param string $config_name
428    *   The configuration name.
429    * @param string $langcode
430    *   The language code.
431    *
432    * @return bool
433    *   TRUE if the assertion succeeded, FALSE otherwise.
434    */
435   protected function assertNoTranslation($config_name, $langcode) {
436     $strings = $this->stringStorage->getTranslations([
437       'type' => 'configuration',
438       'name' => $config_name,
439       'language' => $langcode,
440       'translated' => TRUE,
441     ]);
442     return $this->assertIdentical([], $strings);
443   }
444
445   /**
446    * Ensures a translation exists and is marked as customized.
447    *
448    * @param string $config_name
449    *   The configuration name.
450    * @param string $translation
451    *   The translation.
452    * @param string $langcode
453    *   The language code.
454    * @param bool $customized
455    *   Whether or not the string should be asserted to be customized or not
456    *   customized.
457    *
458    * @return bool
459    *   TRUE if the assertion succeeded, FALSE otherwise.
460    */
461   protected function assertTranslation($config_name, $translation, $langcode, $customized = TRUE) {
462     // Make sure a string exists.
463     $strings = $this->stringStorage->getTranslations([
464       'type' => 'configuration',
465       'name' => $config_name,
466       'language' => $langcode,
467       'translated' => TRUE,
468     ]);
469     $pass = $this->assertIdentical(1, count($strings));
470     $string = reset($strings);
471     if ($this->assertTrue($string instanceof StringInterface)) {
472       /** @var \Drupal\locale\StringInterface $string */
473       $pass = $pass && $this->assertIdentical($translation, $string->getString());
474       $pass = $pass && $this->assertTrue($string->isTranslation());
475       if ($this->assertTrue($string instanceof TranslationString)) {
476         /** @var \Drupal\locale\TranslationString $string */
477         // Make sure the string is marked as customized so that it does not get
478         // overridden when the string translations are updated.
479         return $pass && $this->assertEqual($customized, $string->customized);
480       }
481     }
482     return FALSE;
483   }
484
485 }