‪TYPO3CMS  11.5
LocalizationUtilityTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Prophecy\Argument;
21 use Prophecy\PhpUnit\ProphecyTrait;
22 use Prophecy\Prophecy\ObjectProphecy;
30 use TYPO3\CMS\Core\Package\PackageManager;
34 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
35 
39 class ‪LocalizationUtilityTest extends UnitTestCase
40 {
41  use ProphecyTrait;
42 
48  protected ObjectProphecy ‪$configurationManagerInterfaceProphecy;
49 
53  protected array ‪$LOCAL_LANG = [];
54 
58  protected string ‪$languageFilePath = '';
59 
63  protected function ‪setUp(): void
64  {
65  parent::setUp();
66  $this->languageFilePath = $this->‪getLanguageFilePath('core');
67  $this->LOCAL_LANG = [
68  $this->languageFilePath => [
69  'default' => [
70  'key1' => [
71  [
72  'source' => 'English label for key1',
73  'target' => 'English label for key1',
74  ],
75  ],
76  'key2' => [
77  [
78  'source' => 'English label for key2',
79  'target' => 'English label for key2',
80  ],
81  ],
82  'key3' => [
83  [
84  'source' => 'English label for key3',
85  'target' => 'English label for key3',
86  ],
87  ],
88  'key4' => [
89  [
90  'source' => 'English label for key4',
91  'target' => 'English label for key4',
92  ],
93  ],
94  'keyWithPlaceholder' => [
95  [
96  'source' => 'English label with number %d',
97  'target' => 'English label with number %d',
98  ],
99  ],
100  'keyWithPlaceholderAndNoArguments' => [
101  [
102  'source' => '%d/%m/%Y',
103  'target' => '%d/%m/%Y',
104  ],
105  ],
106  ],
107  'dk' => [
108  'key1' => [
109  [
110  'source' => 'English label for key1',
111  'target' => 'Dansk label for key1',
112  ],
113  ],
114  // not translated in dk => no target (llxml)
115  'key2' => [
116  [
117  'source' => 'English label for key2',
118  ],
119  ],
120  'key3' => [
121  [
122  'source' => 'English label for key3',
123  ],
124  ],
125  // not translated in dk => empty target (xliff)
126  'key4' => [
127  [
128  'source' => 'English label for key4',
129  'target' => '',
130  ],
131  ],
132  // not translated in dk => empty target (xliff)
133  'key5' => [
134  [
135  'source' => 'English label for key5',
136  'target' => '',
137  ],
138  ],
139  'keyWithPlaceholder' => [
140  [
141  'source' => 'English label with number %d',
142  ],
143  ],
144  'keyWithPlaceholderAndNoArguments' => [
145  [
146  'source' => '%d/%m/%Y',
147  'target' => '%d-%m-%Y',
148  ],
149  ],
150  ],
151  // fallback language for labels which are not translated in dk
152  'dk_alt' => [
153  'key1' => [
154  [
155  'source' => 'English label for key1',
156  ],
157  ],
158  'key2' => [
159  [
160  'source' => 'English label for key2',
161  'target' => 'Dansk alternative label for key2',
162  ],
163  ],
164  'key3' => [
165  [
166  'source' => 'English label for key3',
167  ],
168  ],
169  // not translated in dk_alt => empty target (xliff)
170  'key4' => [
171  [
172  'source' => 'English label for key4',
173  'target' => '',
174  ],
175  ],
176  'key5' => [
177  [
178  'source' => 'English label for key5',
179  'target' => 'Dansk alternative label for key5',
180  ],
181  ],
182  'keyWithPlaceholder' => [
183  [
184  'source' => 'English label with number %d',
185  ],
186  ],
187  ],
188 
189  ],
190  ];
191 
192  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
193 
194  $this->configurationManagerInterfaceProphecy = $this->prophesize(ConfigurationManagerInterface::class);
195  $property = $reflectionClass->getProperty('configurationManager');
196  $property->setAccessible(true);
197  $property->setValue(null, $this->configurationManagerInterfaceProphecy->reveal());
198 
199  $localizationFactoryProphecy = $this->prophesize(LocalizationFactory::class);
200  GeneralUtility::setSingletonInstance(LocalizationFactory::class, $localizationFactoryProphecy->reveal());
201  $localizationFactoryProphecy->getParsedData(Argument::cetera(), 'foo')->willReturn([]);
202  }
203 
207  protected function ‪tearDown(): void
208  {
209  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
210 
211  $property = $reflectionClass->getProperty('configurationManager');
212  $property->setAccessible(true);
213  $property->setValue(null, null);
214 
215  $property = $reflectionClass->getProperty('LOCAL_LANG');
216  $property->setAccessible(true);
217  $property->setValue(null, []);
218 
219  GeneralUtility::purgeInstances();
220 
221  parent::tearDown();
222  }
223 
228  protected function ‪getLanguageFilePath(string $extensionName): string
229  {
230  return 'EXT:' . $extensionName . '/Resources/Private/Language/locallang.xlf';
231  }
232 
236  public function ‪implodeTypoScriptLabelArrayWorks(): void
237  {
238  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
239  $method = $reflectionClass->getMethod('flattenTypoScriptLabelArray');
240  $method->setAccessible(true);
241 
242  $expected = [
243  'key1' => 'value1',
244  'key2' => 'value2',
245  'key3' => 'value3',
246  'key3.subkey1' => 'subvalue1',
247  'key3.subkey2.subsubkey' => 'val',
248  ];
249  $input = [
250  'key1' => 'value1',
251  'key2' => 'value2',
252  'key3' => [
253  '_typoScriptNodeValue' => 'value3',
254  'subkey1' => 'subvalue1',
255  'subkey2' => [
256  'subsubkey' => 'val',
257  ],
258  ],
259  ];
260  $result = $method->invoke(null, $input);
261  self::assertEquals($expected, $result);
262  }
263 
267  public function ‪translateForEmptyStringKeyReturnsNull(): void
268  {
269  self::assertNull(‪LocalizationUtility::translate('', 'extbase'));
270  }
271 
276  {
277  self::assertNull(‪LocalizationUtility::translate('', 'extbase', ['argument']));
278  }
279 
283  public function ‪translateDataProvider(): array
284  {
285  return [
286  'get translated key' =>
287  ['key1', 'dk', 'Dansk label for key1'],
288 
289  'fallback to English when translation is missing for key' =>
290  ['key2', 'dk', 'English label for key2'],
291 
292  'fallback to English for non existing language' =>
293  ['key2', 'xx', 'English label for key2'],
294 
295  'replace placeholder with argument' =>
296  ['keyWithPlaceholder', 'default', 'English label with number 100', [], [100]],
297 
298  'placeholder and empty arguments in default' =>
299  ['keyWithPlaceholderAndNoArguments', 'default', '%d/%m/%Y', [], []],
300 
301  'placeholder and empty arguments in translation' =>
302  ['keyWithPlaceholderAndNoArguments', 'dk', '%d-%m-%Y', [], []],
303 
304  'get translated key from primary language' =>
305  ['key1', 'dk', 'Dansk label for key1', ['dk_alt']],
306 
307  'fallback to alternative language if translation is missing(llxml)' =>
308  ['key2', 'dk', 'Dansk alternative label for key2', ['dk_alt']],
309 
310  'fallback to alternative language if translation is missing(xlif)' =>
311  ['key5', 'dk', 'Dansk alternative label for key5', ['dk_alt']],
312 
313  'fallback to English for label not translated in dk and dk_alt(llxml)' =>
314  ['key3', 'dk', 'English label for key3', ['dk_alt']],
315 
316  'fallback to English for label not translated in dk and dk_alt(xlif)' =>
317  ['key4', 'dk', 'English label for key4', ['dk_alt']],
318  ];
319  }
320 
330  public function ‪translateTestWithBackendUserLanguage($key, $languageKey, $expected, array $altLanguageKeys = [], array $arguments = null): void
331  {
332  $this->configurationManagerInterfaceProphecy
333  ->getConfiguration('Framework', 'core', null)
334  ->willReturn([]);
335 
336  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
337 
338  $property = $reflectionClass->getProperty('LOCAL_LANG');
339  $property->setAccessible(true);
340  $property->setValue(null, $this->LOCAL_LANG);
341 
342  $backendUserAuthenticationProphecy = $this->prophesize(BackendUserAuthentication::class);
343  $backendUserAuthentication = $backendUserAuthenticationProphecy->reveal();
344  $backendUserAuthentication->user = [
345  'lang' => $languageKey,
346  ];
347  ‪$GLOBALS['BE_USER'] = $backendUserAuthentication;
349 
350  self::assertEquals($expected, ‪LocalizationUtility::translate($key, 'core', $arguments, null, $altLanguageKeys));
351  }
352 
362  public function ‪translateTestWithExplicitLanguageParameters($key, $languageKey, $expected, array $altLanguageKeys = [], array $arguments = null): void
363  {
364  $packageManagerProphecy = $this->prophesize(PackageManager::class);
365  $this->configurationManagerInterfaceProphecy
366  ->getConfiguration('Framework', 'core', null)
367  ->willReturn([]);
368 
369  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
370 
371  $property = $reflectionClass->getProperty('LOCAL_LANG');
372  $property->setAccessible(true);
373  $property->setValue(null, $this->LOCAL_LANG);
374  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
375  $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
376  $cacheManagerProphecy->getCache('l10n')->willReturn($cacheFrontendProphecy->reveal());
377  $cacheFrontendProphecy->get(Argument::cetera())->willReturn(false);
378  $cacheFrontendProphecy->set(Argument::cetera())->willReturn(null);
379  ‪$GLOBALS['LANG'] = new ‪LanguageService(new ‪Locales(), new ‪LocalizationFactory(new ‪LanguageStore($packageManagerProphecy->reveal()), $cacheManagerProphecy->reveal()), $cacheFrontendProphecy->reveal());
380  self::assertEquals($expected, ‪LocalizationUtility::translate($key, 'core', $arguments, $languageKey, $altLanguageKeys));
381  }
382 
386  public function ‪loadTypoScriptLabelsProvider(): array
387  {
388  return [
389  'override labels with typoscript' => [
390  'LOCAL_LANG' => [
391  $this->‪getLanguageFilePath('core') => [
392  'dk' => [
393  'key1' => [
394  [
395  'source' => 'English label for key1',
396  'target' => 'Dansk label for key1 core',
397  ],
398  ],
399  'key2' => [
400  [
401  'source' => 'English label for key2',
402  ],
403  ],
404  'key3.subkey1' => [
405  [
406  'source' => 'English label for key3',
407  ],
408  ],
409  ],
410  ],
411  $this->‪getLanguageFilePath('backend') => [
412  'dk' => [
413  'key1' => [
414  [
415  'source' => 'English label for key1',
416  'target' => 'Dansk label for key1 backend',
417  ],
418  ],
419  'key2' => [
420  [
421  'source' => 'English label for key2',
422  ],
423  ],
424  'key3.subkey1' => [
425  [
426  'source' => 'English label for key3',
427  ],
428  ],
429  ],
430  ],
431  ],
432  'typoscript LOCAL_LANG' => [
433  '_LOCAL_LANG' => [
434  'dk' => [
435  'key1' => 'key1 value from TS core',
436  'key3' => [
437  'subkey1' => 'key3.subkey1 value from TS core',
438  // this key doesn't exist in xml files
439  'subkey2' => [
440  'subsubkey' => 'key3.subkey2.subsubkey value from TS core',
441  ],
442  ],
443  ],
444  ],
445  ],
446  'language key' => 'dk',
447  'expected' => [
448  'key1' => [
449  [
450  'source' => 'English label for key1',
451  'target' => 'key1 value from TS core',
452  ],
453  ],
454  'key2' => [
455  [
456  'source' => 'English label for key2',
457  ],
458  ],
459  'key3.subkey1' => [
460  [
461  'source' => 'English label for key3',
462  'target' => 'key3.subkey1 value from TS core',
463  ],
464  ],
465  'key3.subkey2.subsubkey' => [
466  [
467  'target' => 'key3.subkey2.subsubkey value from TS core',
468  ],
469  ],
470  ],
471  ],
472  ];
473  }
474 
485  public function ‪loadTypoScriptLabels(array ‪$LOCAL_LANG, array $typoScriptLocalLang, $languageKey, array $expected): void
486  {
487  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
488 
489  $property = $reflectionClass->getProperty('LOCAL_LANG');
490  $property->setAccessible(true);
491  $property->setValue(null, ‪$LOCAL_LANG);
492 
494  $this->configurationManagerInterfaceProphecy
495  ->getConfiguration($configurationType, 'core', null)
496  ->shouldBeCalled()
497  ->willReturn($typoScriptLocalLang);
498 
499  $method = $reflectionClass->getMethod('loadTypoScriptLabels');
500  $method->setAccessible(true);
501  $method->invoke(null, 'core', $this->languageFilePath);
502 
503  $property = $reflectionClass->getProperty('LOCAL_LANG');
504  $property->setAccessible(true);
505  $result = $property->getValue();
506 
507  self::assertEquals($expected, $result[$this->languageFilePath][$languageKey]);
508  }
509 
513  public function ‪clearLabelWithTypoScript(): void
514  {
515  $packageManagerProphecy = $this->prophesize(PackageManager::class);
516  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
517 
518  $property = $reflectionClass->getProperty('LOCAL_LANG');
519  $property->setAccessible(true);
520  $property->setValue(null, $this->LOCAL_LANG);
521 
522  $typoScriptLocalLang = [
523  '_LOCAL_LANG' => [
524  'dk' => [
525  'key1' => '',
526  ],
527  ],
528  ];
529 
531  $this->configurationManagerInterfaceProphecy
532  ->getConfiguration($configurationType, 'core', null)
533  ->shouldBeCalled()
534  ->willReturn($typoScriptLocalLang);
535 
536  $method = $reflectionClass->getMethod('loadTypoScriptLabels');
537  $method->setAccessible(true);
538  $method->invoke(null, 'core', $this->languageFilePath);
539 
540  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
541  $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
542  $cacheManagerProphecy->getCache('l10n')->willReturn($cacheFrontendProphecy->reveal());
543  $cacheFrontendProphecy->get(Argument::cetera())->willReturn(false);
544  $cacheFrontendProphecy->set(Argument::cetera())->willReturn(null);
545  ‪$GLOBALS['LANG'] = new ‪LanguageService(new ‪Locales(), new ‪LocalizationFactory(new ‪LanguageStore($packageManagerProphecy->reveal()), $cacheManagerProphecy->reveal()), $cacheFrontendProphecy->reveal());
546 
547  $result = ‪LocalizationUtility::translate('key1', 'core', null, 'dk');
548  self::assertNotNull($result);
549  self::assertEquals('', $result);
550  }
551 
556  {
557  $this->expectException(\InvalidArgumentException::class);
558  $this->expectExceptionCode(1498144052);
559  ‪LocalizationUtility::translate('foo/bar', '');
560  }
561 
566  {
567  $packageManagerProphecy = $this->prophesize(PackageManager::class);
568  $reflectionClass = new \ReflectionClass(LocalizationUtility::class);
569 
570  $typoScriptLocalLang = [
571  '_LOCAL_LANG' => [
572  'dk' => [
573  'key1' => 'I am a new key and there is no xlf file',
574  ],
575  ],
576  ];
577 
579  $this->configurationManagerInterfaceProphecy
580  ->getConfiguration($configurationType, 'core', null)
581  ->shouldBeCalled()
582  ->willReturn($typoScriptLocalLang);
583 
584  $method = $reflectionClass->getMethod('loadTypoScriptLabels');
585  $method->setAccessible(true);
586  $method->invoke(null, 'core', ''); // setting the language file path to an empty string here
587 
588  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
589  $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
590  $cacheManagerProphecy->getCache('l10n')->willReturn($cacheFrontendProphecy->reveal());
591  $cacheFrontendProphecy->get(Argument::cetera())->willReturn(false);
592  $cacheFrontendProphecy->set(Argument::cetera())->willReturn(null);
593  ‪$GLOBALS['LANG'] = new ‪LanguageService(new ‪Locales(), new ‪LocalizationFactory(new ‪LanguageStore($packageManagerProphecy->reveal()), $cacheManagerProphecy->reveal()), $cacheFrontendProphecy->reveal());
594 
595  $result = ‪LocalizationUtility::translate('key1', 'core', null, 'dk');
596  self::assertNotNull($result);
597  self::assertEquals('I am a new key and there is no xlf file', $result);
598  }
599 }
‪TYPO3\CMS\Extbase\Utility\LocalizationUtility
Definition: LocalizationUtility.php:33
‪TYPO3\CMS\Core\Localization\LocalizationFactory
Definition: LocalizationFactory.php:31
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\tearDown
‪tearDown()
Definition: LocalizationUtilityTest.php:206
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:30
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateForEmptyStringKeyReturnsNull
‪translateForEmptyStringKeyReturnsNull()
Definition: LocalizationUtilityTest.php:266
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateWillReturnLabelsFromTsEvenIfNoXlfFileExists
‪translateWillReturnLabelsFromTsEvenIfNoXlfFileExists()
Definition: LocalizationUtilityTest.php:564
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface\CONFIGURATION_TYPE_FRAMEWORK
‪const CONFIGURATION_TYPE_FRAMEWORK
Definition: ConfigurationManagerInterface.php:29
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\implodeTypoScriptLabelArrayWorks
‪implodeTypoScriptLabelArrayWorks()
Definition: LocalizationUtilityTest.php:235
‪TYPO3\CMS\Core\Localization\LanguageStore
Definition: LanguageStore.php:29
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\loadTypoScriptLabelsProvider
‪array loadTypoScriptLabelsProvider()
Definition: LocalizationUtilityTest.php:385
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateTestWithExplicitLanguageParameters
‪translateTestWithExplicitLanguageParameters($key, $languageKey, $expected, array $altLanguageKeys=[], array $arguments=null)
Definition: LocalizationUtilityTest.php:361
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\$configurationManagerInterfaceProphecy
‪ObjectProphecy $configurationManagerInterfaceProphecy
Definition: LocalizationUtilityTest.php:47
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateForEmptyStringKeyWithArgumentsReturnsNull
‪translateForEmptyStringKeyWithArgumentsReturnsNull()
Definition: LocalizationUtilityTest.php:274
‪TYPO3\CMS\Extbase\Tests\Unit\Utility
Definition: DebuggerUtilityTest.php:18
‪TYPO3\CMS\Extbase\Utility\LocalizationUtility\translate
‪static string null translate(string $key, ?string $extensionName=null, array $arguments=null, string $languageKey=null, array $alternativeLanguageKeys=null)
Definition: LocalizationUtility.php:67
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateTestWithBackendUserLanguage
‪translateTestWithBackendUserLanguage($key, $languageKey, $expected, array $altLanguageKeys=[], array $arguments=null)
Definition: LocalizationUtilityTest.php:329
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest
Definition: LocalizationUtilityTest.php:40
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateThrowsExceptionWithEmptyExtensionNameIfKeyIsNotPrefixedWithLLL
‪translateThrowsExceptionWithEmptyExtensionNameIfKeyIsNotPrefixedWithLLL()
Definition: LocalizationUtilityTest.php:554
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\setUp
‪setUp()
Definition: LocalizationUtilityTest.php:62
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\$languageFilePath
‪string $languageFilePath
Definition: LocalizationUtilityTest.php:57
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\getLanguageFilePath
‪string getLanguageFilePath(string $extensionName)
Definition: LocalizationUtilityTest.php:227
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\clearLabelWithTypoScript
‪clearLabelWithTypoScript()
Definition: LocalizationUtilityTest.php:512
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\translateDataProvider
‪array translateDataProvider()
Definition: LocalizationUtilityTest.php:282
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\loadTypoScriptLabels
‪loadTypoScriptLabels(array $LOCAL_LANG, array $typoScriptLocalLang, $languageKey, array $expected)
Definition: LocalizationUtilityTest.php:484
‪TYPO3\CMS\Extbase\Tests\Unit\Utility\LocalizationUtilityTest\$LOCAL_LANG
‪array $LOCAL_LANG
Definition: LocalizationUtilityTest.php:52