Patched to Drupal 8.4.8 level. See https://www.drupal.org/sa-core-2018-004 and patch...
[yaffs-website] / vendor / symfony / translation / Tests / TranslatorTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Translation\Tests;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Translation\Translator;
16 use Symfony\Component\Translation\MessageSelector;
17 use Symfony\Component\Translation\Loader\ArrayLoader;
18 use Symfony\Component\Translation\MessageCatalogue;
19
20 class TranslatorTest extends TestCase
21 {
22     /**
23      * @dataProvider      getInvalidLocalesTests
24      * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
25      */
26     public function testConstructorInvalidLocale($locale)
27     {
28         $translator = new Translator($locale, new MessageSelector());
29     }
30
31     /**
32      * @dataProvider getValidLocalesTests
33      */
34     public function testConstructorValidLocale($locale)
35     {
36         $translator = new Translator($locale, new MessageSelector());
37
38         $this->assertEquals($locale, $translator->getLocale());
39     }
40
41     public function testConstructorWithoutLocale()
42     {
43         $translator = new Translator(null, new MessageSelector());
44
45         $this->assertNull($translator->getLocale());
46     }
47
48     public function testSetGetLocale()
49     {
50         $translator = new Translator('en');
51
52         $this->assertEquals('en', $translator->getLocale());
53
54         $translator->setLocale('fr');
55         $this->assertEquals('fr', $translator->getLocale());
56     }
57
58     /**
59      * @dataProvider      getInvalidLocalesTests
60      * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
61      */
62     public function testSetInvalidLocale($locale)
63     {
64         $translator = new Translator('fr', new MessageSelector());
65         $translator->setLocale($locale);
66     }
67
68     /**
69      * @dataProvider getValidLocalesTests
70      */
71     public function testSetValidLocale($locale)
72     {
73         $translator = new Translator($locale, new MessageSelector());
74         $translator->setLocale($locale);
75
76         $this->assertEquals($locale, $translator->getLocale());
77     }
78
79     public function testGetCatalogue()
80     {
81         $translator = new Translator('en');
82
83         $this->assertEquals(new MessageCatalogue('en'), $translator->getCatalogue());
84
85         $translator->setLocale('fr');
86         $this->assertEquals(new MessageCatalogue('fr'), $translator->getCatalogue('fr'));
87     }
88
89     public function testGetCatalogueReturnsConsolidatedCatalogue()
90     {
91         /*
92          * This will be useful once we refactor so that different domains will be loaded lazily (on-demand).
93          * In that case, getCatalogue() will probably have to load all missing domains in order to return
94          * one complete catalogue.
95          */
96
97         $locale = 'whatever';
98         $translator = new Translator($locale);
99         $translator->addLoader('loader-a', new ArrayLoader());
100         $translator->addLoader('loader-b', new ArrayLoader());
101         $translator->addResource('loader-a', array('foo' => 'foofoo'), $locale, 'domain-a');
102         $translator->addResource('loader-b', array('bar' => 'foobar'), $locale, 'domain-b');
103
104         /*
105          * Test that we get a single catalogue comprising messages
106          * from different loaders and different domains
107          */
108         $catalogue = $translator->getCatalogue($locale);
109         $this->assertTrue($catalogue->defines('foo', 'domain-a'));
110         $this->assertTrue($catalogue->defines('bar', 'domain-b'));
111     }
112
113     public function testSetFallbackLocales()
114     {
115         $translator = new Translator('en');
116         $translator->addLoader('array', new ArrayLoader());
117         $translator->addResource('array', array('foo' => 'foofoo'), 'en');
118         $translator->addResource('array', array('bar' => 'foobar'), 'fr');
119
120         // force catalogue loading
121         $translator->trans('bar');
122
123         $translator->setFallbackLocales(array('fr'));
124         $this->assertEquals('foobar', $translator->trans('bar'));
125     }
126
127     public function testSetFallbackLocalesMultiple()
128     {
129         $translator = new Translator('en');
130         $translator->addLoader('array', new ArrayLoader());
131         $translator->addResource('array', array('foo' => 'foo (en)'), 'en');
132         $translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
133
134         // force catalogue loading
135         $translator->trans('bar');
136
137         $translator->setFallbackLocales(array('fr_FR', 'fr'));
138         $this->assertEquals('bar (fr)', $translator->trans('bar'));
139     }
140
141     /**
142      * @dataProvider      getInvalidLocalesTests
143      * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
144      */
145     public function testSetFallbackInvalidLocales($locale)
146     {
147         $translator = new Translator('fr', new MessageSelector());
148         $translator->setFallbackLocales(array('fr', $locale));
149     }
150
151     /**
152      * @dataProvider getValidLocalesTests
153      */
154     public function testSetFallbackValidLocales($locale)
155     {
156         $translator = new Translator($locale, new MessageSelector());
157         $translator->setFallbackLocales(array('fr', $locale));
158         // no assertion. this method just asserts that no exception is thrown
159         $this->addToAssertionCount(1);
160     }
161
162     public function testTransWithFallbackLocale()
163     {
164         $translator = new Translator('fr_FR');
165         $translator->setFallbackLocales(array('en'));
166
167         $translator->addLoader('array', new ArrayLoader());
168         $translator->addResource('array', array('bar' => 'foobar'), 'en');
169
170         $this->assertEquals('foobar', $translator->trans('bar'));
171     }
172
173     /**
174      * @dataProvider      getInvalidLocalesTests
175      * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
176      */
177     public function testAddResourceInvalidLocales($locale)
178     {
179         $translator = new Translator('fr', new MessageSelector());
180         $translator->addResource('array', array('foo' => 'foofoo'), $locale);
181     }
182
183     /**
184      * @dataProvider getValidLocalesTests
185      */
186     public function testAddResourceValidLocales($locale)
187     {
188         $translator = new Translator('fr', new MessageSelector());
189         $translator->addResource('array', array('foo' => 'foofoo'), $locale);
190         // no assertion. this method just asserts that no exception is thrown
191         $this->addToAssertionCount(1);
192     }
193
194     public function testAddResourceAfterTrans()
195     {
196         $translator = new Translator('fr');
197         $translator->addLoader('array', new ArrayLoader());
198
199         $translator->setFallbackLocales(array('en'));
200
201         $translator->addResource('array', array('foo' => 'foofoo'), 'en');
202         $this->assertEquals('foofoo', $translator->trans('foo'));
203
204         $translator->addResource('array', array('bar' => 'foobar'), 'en');
205         $this->assertEquals('foobar', $translator->trans('bar'));
206     }
207
208     /**
209      * @dataProvider      getTransFileTests
210      * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
211      */
212     public function testTransWithoutFallbackLocaleFile($format, $loader)
213     {
214         $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
215         $translator = new Translator('en');
216         $translator->addLoader($format, new $loaderClass());
217         $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en');
218         $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en');
219
220         // force catalogue loading
221         $translator->trans('foo');
222     }
223
224     /**
225      * @dataProvider getTransFileTests
226      */
227     public function testTransWithFallbackLocaleFile($format, $loader)
228     {
229         $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
230         $translator = new Translator('en_GB');
231         $translator->addLoader($format, new $loaderClass());
232         $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en_GB');
233         $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en', 'resources');
234
235         $this->assertEquals('bar', $translator->trans('foo', array(), 'resources'));
236     }
237
238     public function testTransWithFallbackLocaleBis()
239     {
240         $translator = new Translator('en_US');
241         $translator->addLoader('array', new ArrayLoader());
242         $translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
243         $translator->addResource('array', array('bar' => 'foobar'), 'en');
244         $this->assertEquals('foobar', $translator->trans('bar'));
245     }
246
247     public function testTransWithFallbackLocaleTer()
248     {
249         $translator = new Translator('fr_FR');
250         $translator->addLoader('array', new ArrayLoader());
251         $translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US');
252         $translator->addResource('array', array('bar' => 'bar (en)'), 'en');
253
254         $translator->setFallbackLocales(array('en_US', 'en'));
255
256         $this->assertEquals('foo (en_US)', $translator->trans('foo'));
257         $this->assertEquals('bar (en)', $translator->trans('bar'));
258     }
259
260     public function testTransNonExistentWithFallback()
261     {
262         $translator = new Translator('fr');
263         $translator->setFallbackLocales(array('en'));
264         $translator->addLoader('array', new ArrayLoader());
265         $this->assertEquals('non-existent', $translator->trans('non-existent'));
266     }
267
268     /**
269      * @expectedException \Symfony\Component\Translation\Exception\RuntimeException
270      */
271     public function testWhenAResourceHasNoRegisteredLoader()
272     {
273         $translator = new Translator('en');
274         $translator->addResource('array', array('foo' => 'foofoo'), 'en');
275
276         $translator->trans('foo');
277     }
278
279     public function testNestedFallbackCatalogueWhenUsingMultipleLocales()
280     {
281         $translator = new Translator('fr');
282         $translator->setFallbackLocales(array('ru', 'en'));
283
284         $translator->getCatalogue('fr');
285
286         $this->assertNotNull($translator->getCatalogue('ru')->getFallbackCatalogue());
287     }
288
289     public function testFallbackCatalogueResources()
290     {
291         $translator = new Translator('en_GB', new MessageSelector());
292         $translator->addLoader('yml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
293         $translator->addResource('yml', __DIR__.'/fixtures/empty.yml', 'en_GB');
294         $translator->addResource('yml', __DIR__.'/fixtures/resources.yml', 'en');
295
296         // force catalogue loading
297         $this->assertEquals('bar', $translator->trans('foo', array()));
298
299         $resources = $translator->getCatalogue('en')->getResources();
300         $this->assertCount(1, $resources);
301         $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources);
302
303         $resources = $translator->getCatalogue('en_GB')->getResources();
304         $this->assertCount(2, $resources);
305         $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'empty.yml', $resources);
306         $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources);
307     }
308
309     /**
310      * @dataProvider getTransTests
311      */
312     public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)
313     {
314         $translator = new Translator('en');
315         $translator->addLoader('array', new ArrayLoader());
316         $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
317
318         $this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale));
319     }
320
321     /**
322      * @dataProvider      getInvalidLocalesTests
323      * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
324      */
325     public function testTransInvalidLocale($locale)
326     {
327         $translator = new Translator('en', new MessageSelector());
328         $translator->addLoader('array', new ArrayLoader());
329         $translator->addResource('array', array('foo' => 'foofoo'), 'en');
330
331         $translator->trans('foo', array(), '', $locale);
332     }
333
334     /**
335      * @dataProvider      getValidLocalesTests
336      */
337     public function testTransValidLocale($locale)
338     {
339         $translator = new Translator($locale, new MessageSelector());
340         $translator->addLoader('array', new ArrayLoader());
341         $translator->addResource('array', array('test' => 'OK'), $locale);
342
343         $this->assertEquals('OK', $translator->trans('test'));
344         $this->assertEquals('OK', $translator->trans('test', array(), null, $locale));
345     }
346
347     /**
348      * @dataProvider getFlattenedTransTests
349      */
350     public function testFlattenedTrans($expected, $messages, $id)
351     {
352         $translator = new Translator('en');
353         $translator->addLoader('array', new ArrayLoader());
354         $translator->addResource('array', $messages, 'fr', '');
355
356         $this->assertEquals($expected, $translator->trans($id, array(), '', 'fr'));
357     }
358
359     /**
360      * @dataProvider getTransChoiceTests
361      */
362     public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
363     {
364         $translator = new Translator('en');
365         $translator->addLoader('array', new ArrayLoader());
366         $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
367
368         $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
369     }
370
371     /**
372      * @dataProvider      getInvalidLocalesTests
373      * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
374      */
375     public function testTransChoiceInvalidLocale($locale)
376     {
377         $translator = new Translator('en', new MessageSelector());
378         $translator->addLoader('array', new ArrayLoader());
379         $translator->addResource('array', array('foo' => 'foofoo'), 'en');
380
381         $translator->transChoice('foo', 1, array(), '', $locale);
382     }
383
384     /**
385      * @dataProvider      getValidLocalesTests
386      */
387     public function testTransChoiceValidLocale($locale)
388     {
389         $translator = new Translator('en', new MessageSelector());
390         $translator->addLoader('array', new ArrayLoader());
391         $translator->addResource('array', array('foo' => 'foofoo'), 'en');
392
393         $translator->transChoice('foo', 1, array(), '', $locale);
394         // no assertion. this method just asserts that no exception is thrown
395         $this->addToAssertionCount(1);
396     }
397
398     public function getTransFileTests()
399     {
400         return array(
401             array('csv', 'CsvFileLoader'),
402             array('ini', 'IniFileLoader'),
403             array('mo', 'MoFileLoader'),
404             array('po', 'PoFileLoader'),
405             array('php', 'PhpFileLoader'),
406             array('ts', 'QtFileLoader'),
407             array('xlf', 'XliffFileLoader'),
408             array('yml', 'YamlFileLoader'),
409             array('json', 'JsonFileLoader'),
410         );
411     }
412
413     public function getTransTests()
414     {
415         return array(
416             array('Symfony est super !', 'Symfony is great!', 'Symfony est super !', array(), 'fr', ''),
417             array('Symfony est awesome !', 'Symfony is %what%!', 'Symfony est %what% !', array('%what%' => 'awesome'), 'fr', ''),
418             array('Symfony est super !', new StringClass('Symfony is great!'), 'Symfony est super !', array(), 'fr', ''),
419         );
420     }
421
422     public function getFlattenedTransTests()
423     {
424         $messages = array(
425             'symfony' => array(
426                 'is' => array(
427                     'great' => 'Symfony est super!',
428                 ),
429             ),
430             'foo' => array(
431                 'bar' => array(
432                     'baz' => 'Foo Bar Baz',
433                 ),
434                 'baz' => 'Foo Baz',
435             ),
436         );
437
438         return array(
439             array('Symfony est super!', $messages, 'symfony.is.great'),
440             array('Foo Bar Baz', $messages, 'foo.bar.baz'),
441             array('Foo Baz', $messages, 'foo.baz'),
442         );
443     }
444
445     public function getTransChoiceTests()
446     {
447         return array(
448             array('Il y a 0 pomme', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array(), 'fr', ''),
449             array('Il y a 1 pomme', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, array(), 'fr', ''),
450             array('Il y a 10 pommes', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, array(), 'fr', ''),
451
452             array('Il y a 0 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 0, array(), 'fr', ''),
453             array('Il y a 1 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 1, array(), 'fr', ''),
454             array('Il y a 10 pommes', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 10, array(), 'fr', ''),
455
456             array('Il y a 0 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array(), 'fr', ''),
457             array('Il y a 1 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array(), 'fr', ''),
458             array('Il y a 10 pommes', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array(), 'fr', ''),
459
460             array('Il n\'y a aucune pomme', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array(), 'fr', ''),
461             array('Il y a 1 pomme', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array(), 'fr', ''),
462             array('Il y a 10 pommes', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array(), 'fr', ''),
463
464             array('Il y a 0 pomme', new StringClass('{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array(), 'fr', ''),
465
466             // Override %count% with a custom value
467             array('Il y a quelques pommes', 'one: There is one apple|more: There are %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 2, array('%count%' => 'quelques'), 'fr', ''),
468         );
469     }
470
471     public function getInvalidLocalesTests()
472     {
473         return array(
474             array('fr FR'),
475             array('français'),
476             array('fr+en'),
477             array('utf#8'),
478             array('fr&en'),
479             array('fr~FR'),
480             array(' fr'),
481             array('fr '),
482             array('fr*'),
483             array('fr/FR'),
484             array('fr\\FR'),
485         );
486     }
487
488     public function getValidLocalesTests()
489     {
490         return array(
491             array(''),
492             array(null),
493             array('fr'),
494             array('francais'),
495             array('FR'),
496             array('frFR'),
497             array('fr-FR'),
498             array('fr_FR'),
499             array('fr.FR'),
500             array('fr-FR.UTF8'),
501             array('sr@latin'),
502         );
503     }
504
505     public function testTransChoiceFallback()
506     {
507         $translator = new Translator('ru');
508         $translator->setFallbackLocales(array('en'));
509         $translator->addLoader('array', new ArrayLoader());
510         $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
511
512         $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
513     }
514
515     public function testTransChoiceFallbackBis()
516     {
517         $translator = new Translator('ru');
518         $translator->setFallbackLocales(array('en_US', 'en'));
519         $translator->addLoader('array', new ArrayLoader());
520         $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US');
521
522         $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
523     }
524
525     public function testTransChoiceFallbackWithNoTranslation()
526     {
527         $translator = new Translator('ru');
528         $translator->setFallbackLocales(array('en'));
529         $translator->addLoader('array', new ArrayLoader());
530
531         // consistent behavior with Translator::trans(), which returns the string
532         // unchanged if it can't be found
533         $this->assertEquals('some_message2', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
534     }
535 }
536
537 class StringClass
538 {
539     protected $str;
540
541     public function __construct($str)
542     {
543         $this->str = $str;
544     }
545
546     public function __toString()
547     {
548         return $this->str;
549     }
550 }