4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Translation\Tests;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Translation\Translator;
16 use Symfony\Component\Translation\Loader\ArrayLoader;
17 use Symfony\Component\Translation\MessageCatalogue;
19 class TranslatorTest extends TestCase
22 * @dataProvider getInvalidLocalesTests
23 * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
25 public function testConstructorInvalidLocale($locale)
27 new Translator($locale);
31 * @dataProvider getValidLocalesTests
33 public function testConstructorValidLocale($locale)
35 $translator = new Translator($locale);
37 $this->assertEquals($locale, $translator->getLocale());
40 public function testConstructorWithoutLocale()
42 $translator = new Translator(null);
44 $this->assertNull($translator->getLocale());
47 public function testSetGetLocale()
49 $translator = new Translator('en');
51 $this->assertEquals('en', $translator->getLocale());
53 $translator->setLocale('fr');
54 $this->assertEquals('fr', $translator->getLocale());
58 * @dataProvider getInvalidLocalesTests
59 * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
61 public function testSetInvalidLocale($locale)
63 $translator = new Translator('fr');
64 $translator->setLocale($locale);
68 * @dataProvider getValidLocalesTests
70 public function testSetValidLocale($locale)
72 $translator = new Translator($locale);
73 $translator->setLocale($locale);
75 $this->assertEquals($locale, $translator->getLocale());
78 public function testGetCatalogue()
80 $translator = new Translator('en');
82 $this->assertEquals(new MessageCatalogue('en'), $translator->getCatalogue());
84 $translator->setLocale('fr');
85 $this->assertEquals(new MessageCatalogue('fr'), $translator->getCatalogue('fr'));
88 public function testGetCatalogueReturnsConsolidatedCatalogue()
91 * This will be useful once we refactor so that different domains will be loaded lazily (on-demand).
92 * In that case, getCatalogue() will probably have to load all missing domains in order to return
93 * one complete catalogue.
97 $translator = new Translator($locale);
98 $translator->addLoader('loader-a', new ArrayLoader());
99 $translator->addLoader('loader-b', new ArrayLoader());
100 $translator->addResource('loader-a', array('foo' => 'foofoo'), $locale, 'domain-a');
101 $translator->addResource('loader-b', array('bar' => 'foobar'), $locale, 'domain-b');
104 * Test that we get a single catalogue comprising messages
105 * from different loaders and different domains
107 $catalogue = $translator->getCatalogue($locale);
108 $this->assertTrue($catalogue->defines('foo', 'domain-a'));
109 $this->assertTrue($catalogue->defines('bar', 'domain-b'));
112 public function testSetFallbackLocales()
114 $translator = new Translator('en');
115 $translator->addLoader('array', new ArrayLoader());
116 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
117 $translator->addResource('array', array('bar' => 'foobar'), 'fr');
119 // force catalogue loading
120 $translator->trans('bar');
122 $translator->setFallbackLocales(array('fr'));
123 $this->assertEquals('foobar', $translator->trans('bar'));
126 public function testSetFallbackLocalesMultiple()
128 $translator = new Translator('en');
129 $translator->addLoader('array', new ArrayLoader());
130 $translator->addResource('array', array('foo' => 'foo (en)'), 'en');
131 $translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
133 // force catalogue loading
134 $translator->trans('bar');
136 $translator->setFallbackLocales(array('fr_FR', 'fr'));
137 $this->assertEquals('bar (fr)', $translator->trans('bar'));
141 * @dataProvider getInvalidLocalesTests
142 * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
144 public function testSetFallbackInvalidLocales($locale)
146 $translator = new Translator('fr');
147 $translator->setFallbackLocales(array('fr', $locale));
151 * @dataProvider getValidLocalesTests
153 public function testSetFallbackValidLocales($locale)
155 $translator = new Translator($locale);
156 $translator->setFallbackLocales(array('fr', $locale));
157 // no assertion. this method just asserts that no exception is thrown
158 $this->addToAssertionCount(1);
161 public function testTransWithFallbackLocale()
163 $translator = new Translator('fr_FR');
164 $translator->setFallbackLocales(array('en'));
166 $translator->addLoader('array', new ArrayLoader());
167 $translator->addResource('array', array('bar' => 'foobar'), 'en');
169 $this->assertEquals('foobar', $translator->trans('bar'));
173 * @dataProvider getInvalidLocalesTests
174 * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
176 public function testAddResourceInvalidLocales($locale)
178 $translator = new Translator('fr');
179 $translator->addResource('array', array('foo' => 'foofoo'), $locale);
183 * @dataProvider getValidLocalesTests
185 public function testAddResourceValidLocales($locale)
187 $translator = new Translator('fr');
188 $translator->addResource('array', array('foo' => 'foofoo'), $locale);
189 // no assertion. this method just asserts that no exception is thrown
190 $this->addToAssertionCount(1);
193 public function testAddResourceAfterTrans()
195 $translator = new Translator('fr');
196 $translator->addLoader('array', new ArrayLoader());
198 $translator->setFallbackLocales(array('en'));
200 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
201 $this->assertEquals('foofoo', $translator->trans('foo'));
203 $translator->addResource('array', array('bar' => 'foobar'), 'en');
204 $this->assertEquals('foobar', $translator->trans('bar'));
208 * @dataProvider getTransFileTests
209 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
211 public function testTransWithoutFallbackLocaleFile($format, $loader)
213 $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
214 $translator = new Translator('en');
215 $translator->addLoader($format, new $loaderClass());
216 $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en');
217 $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en');
219 // force catalogue loading
220 $translator->trans('foo');
224 * @dataProvider getTransFileTests
226 public function testTransWithFallbackLocaleFile($format, $loader)
228 $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
229 $translator = new Translator('en_GB');
230 $translator->addLoader($format, new $loaderClass());
231 $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en_GB');
232 $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en', 'resources');
234 $this->assertEquals('bar', $translator->trans('foo', array(), 'resources'));
237 public function testTransWithFallbackLocaleBis()
239 $translator = new Translator('en_US');
240 $translator->addLoader('array', new ArrayLoader());
241 $translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
242 $translator->addResource('array', array('bar' => 'foobar'), 'en');
243 $this->assertEquals('foobar', $translator->trans('bar'));
246 public function testTransWithFallbackLocaleTer()
248 $translator = new Translator('fr_FR');
249 $translator->addLoader('array', new ArrayLoader());
250 $translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US');
251 $translator->addResource('array', array('bar' => 'bar (en)'), 'en');
253 $translator->setFallbackLocales(array('en_US', 'en'));
255 $this->assertEquals('foo (en_US)', $translator->trans('foo'));
256 $this->assertEquals('bar (en)', $translator->trans('bar'));
259 public function testTransNonExistentWithFallback()
261 $translator = new Translator('fr');
262 $translator->setFallbackLocales(array('en'));
263 $translator->addLoader('array', new ArrayLoader());
264 $this->assertEquals('non-existent', $translator->trans('non-existent'));
268 * @expectedException \Symfony\Component\Translation\Exception\RuntimeException
270 public function testWhenAResourceHasNoRegisteredLoader()
272 $translator = new Translator('en');
273 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
275 $translator->trans('foo');
278 public function testNestedFallbackCatalogueWhenUsingMultipleLocales()
280 $translator = new Translator('fr');
281 $translator->setFallbackLocales(array('ru', 'en'));
283 $translator->getCatalogue('fr');
285 $this->assertNotNull($translator->getCatalogue('ru')->getFallbackCatalogue());
288 public function testFallbackCatalogueResources()
290 $translator = new Translator('en_GB');
291 $translator->addLoader('yml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
292 $translator->addResource('yml', __DIR__.'/fixtures/empty.yml', 'en_GB');
293 $translator->addResource('yml', __DIR__.'/fixtures/resources.yml', 'en');
295 // force catalogue loading
296 $this->assertEquals('bar', $translator->trans('foo', array()));
298 $resources = $translator->getCatalogue('en')->getResources();
299 $this->assertCount(1, $resources);
300 $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources);
302 $resources = $translator->getCatalogue('en_GB')->getResources();
303 $this->assertCount(2, $resources);
304 $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'empty.yml', $resources);
305 $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources);
309 * @dataProvider getTransTests
311 public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)
313 $translator = new Translator('en');
314 $translator->addLoader('array', new ArrayLoader());
315 $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
317 $this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale));
321 * @dataProvider getInvalidLocalesTests
322 * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
324 public function testTransInvalidLocale($locale)
326 $translator = new Translator('en');
327 $translator->addLoader('array', new ArrayLoader());
328 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
330 $translator->trans('foo', array(), '', $locale);
334 * @dataProvider getValidLocalesTests
336 public function testTransValidLocale($locale)
338 $translator = new Translator($locale);
339 $translator->addLoader('array', new ArrayLoader());
340 $translator->addResource('array', array('test' => 'OK'), $locale);
342 $this->assertEquals('OK', $translator->trans('test'));
343 $this->assertEquals('OK', $translator->trans('test', array(), null, $locale));
347 * @dataProvider getFlattenedTransTests
349 public function testFlattenedTrans($expected, $messages, $id)
351 $translator = new Translator('en');
352 $translator->addLoader('array', new ArrayLoader());
353 $translator->addResource('array', $messages, 'fr', '');
355 $this->assertEquals($expected, $translator->trans($id, array(), '', 'fr'));
359 * @dataProvider getTransChoiceTests
361 public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
363 $translator = new Translator('en');
364 $translator->addLoader('array', new ArrayLoader());
365 $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
367 $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
371 * @dataProvider getInvalidLocalesTests
372 * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
374 public function testTransChoiceInvalidLocale($locale)
376 $translator = new Translator('en');
377 $translator->addLoader('array', new ArrayLoader());
378 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
380 $translator->transChoice('foo', 1, array(), '', $locale);
384 * @dataProvider getValidLocalesTests
386 public function testTransChoiceValidLocale($locale)
388 $translator = new Translator('en');
389 $translator->addLoader('array', new ArrayLoader());
390 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
392 $translator->transChoice('foo', 1, array(), '', $locale);
393 // no assertion. this method just asserts that no exception is thrown
394 $this->addToAssertionCount(1);
397 public function getTransFileTests()
400 array('csv', 'CsvFileLoader'),
401 array('ini', 'IniFileLoader'),
402 array('mo', 'MoFileLoader'),
403 array('po', 'PoFileLoader'),
404 array('php', 'PhpFileLoader'),
405 array('ts', 'QtFileLoader'),
406 array('xlf', 'XliffFileLoader'),
407 array('yml', 'YamlFileLoader'),
408 array('json', 'JsonFileLoader'),
412 public function getTransTests()
415 array('Symfony est super !', 'Symfony is great!', 'Symfony est super !', array(), 'fr', ''),
416 array('Symfony est awesome !', 'Symfony is %what%!', 'Symfony est %what% !', array('%what%' => 'awesome'), 'fr', ''),
417 array('Symfony est super !', new StringClass('Symfony is great!'), 'Symfony est super !', array(), 'fr', ''),
421 public function getFlattenedTransTests()
426 'great' => 'Symfony est super!',
431 'baz' => 'Foo Bar Baz',
438 array('Symfony est super!', $messages, 'symfony.is.great'),
439 array('Foo Bar Baz', $messages, 'foo.bar.baz'),
440 array('Foo Baz', $messages, 'foo.baz'),
444 public function getTransChoiceTests()
447 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', ''),
448 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', ''),
449 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 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', ''),
452 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', ''),
453 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 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', ''),
456 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', ''),
457 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 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', ''),
460 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', ''),
461 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 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 // Override %count% with a custom value
466 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', ''),
470 public function getInvalidLocalesTests()
487 public function getValidLocalesTests()
504 public function testTransChoiceFallback()
506 $translator = new Translator('ru');
507 $translator->setFallbackLocales(array('en'));
508 $translator->addLoader('array', new ArrayLoader());
509 $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
511 $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
514 public function testTransChoiceFallbackBis()
516 $translator = new Translator('ru');
517 $translator->setFallbackLocales(array('en_US', 'en'));
518 $translator->addLoader('array', new ArrayLoader());
519 $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US');
521 $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
524 public function testTransChoiceFallbackWithNoTranslation()
526 $translator = new Translator('ru');
527 $translator->setFallbackLocales(array('en'));
528 $translator->addLoader('array', new ArrayLoader());
530 // consistent behavior with Translator::trans(), which returns the string
531 // unchanged if it can't be found
532 $this->assertEquals('some_message2', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
540 public function __construct($str)
545 public function __toString()