Completed
Pull Request — master (#5804)
by Hamish
11:11
created

tests/i18n/i18nTest.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use SilverStripe\ORM\DataObject;
4
require_once 'Zend/Translate.php';
5
6
/**
7
 * @package framework
8
 * @subpackage tests
9
 */
10
class i18nTest extends SapphireTest {
11
12
	/**
13
	 * @var string $tmpBasePath Used to write language files.
14
	 * We don't want to store them inside framework (or in any web-accessible place)
15
	 * in case something goes wrong with the file parsing.
16
	 */
17
	protected $alternateBaseSavePath;
18
19
	/**
20
	 * @var string $alternateBasePath Fake webroot with a single module
21
	 * /i18ntestmodule which contains some files with _t() calls.
22
	 */
23
	protected $alternateBasePath;
24
25
	protected $extraDataObjects = array(
26
		'i18nTest_DataObject'
27
	);
28
29
30
	public function setUp() {
31
		parent::setUp();
32
33
		$this->alternateBasePath = $this->getCurrentAbsolutePath() . DIRECTORY_SEPARATOR . "_fakewebroot";
34
		$this->alternateBaseSavePath = TEMP_FOLDER . DIRECTORY_SEPARATOR . 'i18nTextCollectorTest_webroot';
35
		FileSystem::makeFolder($this->alternateBaseSavePath);
36
		Config::inst()->update('Director', 'alternate_base_folder', $this->alternateBasePath);
37
38
		// Push a template loader running from the fake webroot onto the stack.
39
		$templateManifest = new SS_TemplateManifest($this->alternateBasePath, null, false, true);
40
		$templateManifest->regenerate(false);
41
		SS_TemplateLoader::instance()->pushManifest($templateManifest);
42
		$this->_oldTheme = Config::inst()->get('SSViewer', 'theme');
43
		Config::inst()->update('SSViewer', 'theme', 'testtheme1');
44
45
		$this->originalLocale = i18n::get_locale();
46
47
		// Override default adapter to avoid cached translations between tests.
48
		// Emulates behaviour in i18n::get_translators()
49
		$this->origAdapter = i18n::get_translator('core');
50
		$adapter = new Zend_Translate(array(
51
			'adapter' => 'i18nRailsYamlAdapter',
52
			'locale' => i18n::default_locale(),
0 ignored issues
show
Deprecated Code introduced by
The method i18n::default_locale() has been deprecated with message: since version 4.0; Use the "i18n.default_locale" config setting instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
53
			'disableNotices' => true,
54
		));
55
		i18n::register_translator($adapter, 'core');
56
		$adapter->removeCache();
57
		i18n::include_by_locale('en');
58
	}
59
60
	public function tearDown() {
61
		SS_TemplateLoader::instance()->popManifest();
62
		i18n::set_locale($this->originalLocale);
63
		Config::inst()->update('Director', 'alternate_base_folder', null);
64
		Config::inst()->update('SSViewer', 'theme', $this->_oldTheme);
65
		i18n::register_translator($this->origAdapter, 'core');
66
67
		parent::tearDown();
68
	}
69
70
	public function testGetExistingTranslations() {
71
		$translations = i18n::get_existing_translations();
72
		$this->assertTrue(isset($translations['en_US']), 'Checking for en translation');
73
		$this->assertEquals($translations['en_US'], 'English (United States)');
74
		$this->assertTrue(isset($translations['de_DE']), 'Checking for de_DE translation');
75
	}
76
77
	public function testGetClosestTranslation() {
78
79
		// Validate necessary assumptions for this test
80
		$translations = i18n::get_existing_translations();
81
		$this->assertTrue(isset($translations['en_US']));
82
		$this->assertTrue(isset($translations['en_GB']));
83
		$this->assertTrue(isset($translations['es_ES']));
84
		$this->assertTrue(isset($translations['es_AR']));
85
		$this->assertFalse(isset($translations['en_ZZ']));
86
		$this->assertFalse(isset($translations['es_ZZ']));
87
		$this->assertFalse(isset($translations['zz_ZZ']));
88
89
		// Test indeterminate locales
90
		$this->assertEmpty(i18n::get_closest_translation('zz_ZZ'));
91
92
		// Test english fallback
93
		$this->assertEquals('en_US', i18n::get_closest_translation('en_US'));
94
		$this->assertEquals('en_GB', i18n::get_closest_translation('en_GB'));
95
		$this->assertEquals('en_US', i18n::get_closest_translation('en_ZZ'));
96
97
		// Test spanish fallbacks
98
		$this->assertEquals('es_AR', i18n::get_closest_translation('es_AR'));
99
		$this->assertEquals('es_ES', i18n::get_closest_translation('es_ES'));
100
		$this->assertEquals('es_ES', i18n::get_closest_translation('es_XX'));
101
	}
102
103
	public function testDataObjectFieldLabels() {
104
		$oldLocale = i18n::get_locale();
105
		i18n::set_locale('de_DE');
106
		$obj = new i18nTest_DataObject();
107
108
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
109
			'i18nTest_DataObject.MyProperty' => 'MyProperty'
110
		), 'en_US');
111
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
112
			'i18nTest_DataObject.MyProperty' => 'Mein Attribut'
113
		), 'de_DE');
114
115
		$this->assertEquals(
116
			$obj->fieldLabel('MyProperty'),
117
			'Mein Attribut'
118
		);
119
120
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
121
			'i18nTest_DataObject.MyUntranslatedProperty' => 'Mein Attribut'
122
		), 'en_US');
123
		$this->assertEquals(
124
			$obj->fieldLabel('MyUntranslatedProperty'),
125
			'My Untranslated Property'
126
		);
127
128
		i18n::set_locale($oldLocale);
129
	}
130
131
	public function testProvideI18nEntities() {
132
		$oldLocale = i18n::get_locale();
133
		i18n::set_locale('en_US');
134
135
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
136
			'i18nTest_Object.MyProperty' => 'Untranslated'
137
		), 'en_US');
138
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
139
			'i18nTest_Object.my_translatable_property' => 'Übersetzt'
140
		), 'de_DE');
141
142
		$this->assertEquals(
143
			i18nTest_Object::$my_translatable_property,
144
			'Untranslated'
145
		);
146
		$this->assertEquals(
147
			i18nTest_Object::my_translatable_property(),
148
			'Untranslated'
149
		);
150
151
		i18n::set_locale('en_US');
152
		$this->assertEquals(
153
			i18nTest_Object::my_translatable_property(),
154
			'Untranslated',
155
			'Getter returns original static value when called in default locale'
156
		);
157
158
		i18n::set_locale('de_DE');
159
		$this->assertEquals(
160
			i18nTest_Object::my_translatable_property(),
161
			'Übersetzt',
162
			'Getter returns translated value when called in another locale'
163
		);
164
	}
165
166
	public function testTemplateTranslation() {
167
		$oldLocale = i18n::get_locale();
168
169
		i18n::set_locale('en_US');
170
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
171
			'i18nTestModule.MAINTEMPLATE' => 'Main Template',
172
			'i18nTestModule.ss.SPRINTFNONAMESPACE' => 'My replacement no namespace: %s',
173
			'i18nTestModule.LAYOUTTEMPLATE' => 'Layout Template',
174
			'i18nTestModule.ss.LAYOUTTEMPLATENONAMESPACE' => 'Layout Template no namespace',
175
			'i18nTestModule.SPRINTFNAMESPACE' => 'My replacement: %s',
176
			'i18nTestModule.WITHNAMESPACE' => 'Include Entity with Namespace',
177
			'i18nTestModuleInclude.ss.NONAMESPACE' => 'Include Entity without Namespace',
178
			'i18nTestModuleInclude.ss.SPRINTFINCLUDENAMESPACE' => 'My include replacement: %s',
179
			'i18nTestModuleInclude.ss.SPRINTFINCLUDENONAMESPACE' => 'My include replacement no namespace: %s'
180
		), 'en_US');
181
182
		$viewer = new SSViewer('i18nTestModule');
183
		$parsedHtml = Convert::nl2os($viewer->process(new ArrayData(array('TestProperty' => 'TestPropertyValue'))));
184
		$this->assertContains(
185
			Convert::nl2os("Layout Template\n"),
186
			$parsedHtml
187
		);
188
		$this->assertContains(
189
			Convert::nl2os("Layout Template no namespace\n"),
190
			$parsedHtml
191
		);
192
193
		i18n::set_locale('de_DE');
194
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
195
			'i18nTestModule.MAINTEMPLATE' => 'TRANS Main Template',
196
			'i18nTestModule.ss.SPRINTFNONAMESPACE' => 'TRANS My replacement no namespace: %s',
197
			'i18nTestModule.LAYOUTTEMPLATE' => 'TRANS Layout Template',
198
			'i18nTestModule.ss.LAYOUTTEMPLATENONAMESPACE' => 'TRANS Layout Template no namespace',
199
			'i18nTestModule.SPRINTFNAMESPACE' => 'TRANS My replacement: %s',
200
			'i18nTestModule.WITHNAMESPACE' => 'TRANS Include Entity with Namespace',
201
			'i18nTestModuleInclude.ss.NONAMESPACE' => 'TRANS Include Entity without Namespace',
202
			'i18nTestModuleInclude.ss.SPRINTFINCLUDENAMESPACE' => 'TRANS My include replacement: %s',
203
			'i18nTestModuleInclude.ss.SPRINTFINCLUDENONAMESPACE' => 'TRANS My include replacement no namespace: %s'
204
		), 'de_DE');
205
206
		$viewer = new SSViewer('i18nTestModule');
207
		$parsedHtml = Convert::nl2os($viewer->process(new ArrayData(array('TestProperty' => 'TestPropertyValue'))));
208
		$this->assertContains(
209
			Convert::nl2os("TRANS Main Template\n"),
210
			$parsedHtml
211
		);
212
		$this->assertContains(
213
			Convert::nl2os("TRANS Layout Template\n"),
214
			$parsedHtml
215
		);
216
		$this->assertContains(
217
			Convert::nl2os("TRANS Layout Template no namespace\n"),
218
			$parsedHtml
219
		);
220
		$this->assertContains(
221
			Convert::nl2os("TRANS My replacement: TestPropertyValue\n"),
222
			$parsedHtml
223
		);
224
		$this->assertContains(
225
			Convert::nl2os("TRANS Include Entity with Namespace\n"),
226
			$parsedHtml
227
		);
228
		$this->assertContains(
229
			Convert::nl2os("TRANS Include Entity without Namespace\n"),
230
			$parsedHtml
231
		);
232
		$this->assertContains(
233
			Convert::nl2os("TRANS My include replacement: TestPropertyValue\n"),
234
			$parsedHtml
235
		);
236
		$this->assertContains(
237
			Convert::nl2os("TRANS My include replacement no namespace: TestPropertyValue\n"),
238
			$parsedHtml
239
		);
240
241
		i18n::set_locale($oldLocale);
242
	}
243
244
	public function testNewTMethodSignature() {
245
		global $lang;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
246
		$oldLocale = i18n::get_locale();
247
248
		i18n::set_locale('en_US');
249
250
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
251
			'i18nTestModule.NEWMETHODSIG' => 'TRANS New _t method signature test',
252
			'i18nTestModule.INJECTIONS' => 'TRANS Hello {name} {greeting}. But it is late, {goodbye}',
253
			'i18nTestModule.INJECTIONSLEGACY' => 'TRANS Hello %s %s. But it is late, %s',
254
		), 'en_US');
255
256
		$entity = "i18nTestModule.INJECTIONS";
257
		$default = "Hello {name} {greeting}. But it is late, {goodbye}";
258
259
		$translated = i18n::_t('i18nTestModule.NEWMETHODSIG',"New _t method signature test");
260
		$this->assertContains(
261
			"TRANS New _t method signature test",
262
			$translated
263
		);
264
265
		$translated = i18n::_t($entity.'_DOES_NOT_EXIST', $default,
266
			array("name"=>"Mark", "greeting"=>"welcome", "goodbye"=>"bye"));
267
		$this->assertContains(
268
			"Hello Mark welcome. But it is late, bye",
269
			$translated, "Testing fallback to the translation default (but using the injection array)"
270
		);
271
272
		$translated = i18n::_t($entity, $default,
273
			array("name"=>"Paul", "greeting"=>"good you are here", "goodbye"=>"see you"));
274
		$this->assertContains(
275
			"TRANS Hello Paul good you are here. But it is late, see you",
276
			$translated, "Testing entity, default string and injection array"
277
		);
278
279
		$translated = i18n::_t($entity, $default, "New context (this should be ignored)",
280
			array("name"=>"Steffen", "greeting"=>"willkommen", "goodbye"=>"wiedersehen"));
281
		$this->assertContains(
282
			"TRANS Hello Steffen willkommen. But it is late, wiedersehen",
283
			$translated, "Full test of translation, using default, context and injection array"
284
		);
285
286
		$translated = i18n::_t($entity, array("name"=>"Cat", "greeting"=>"meow", "goodbye"=>"meow"));
287
		$this->assertContains(
288
			"TRANS Hello Cat meow. But it is late, meow",
289
			$translated, "Testing a translation with just entity and injection array"
290
		);
291
292
		$translated = i18n::_t(
293
			'i18nTestModule.INJECTIONSLEGACY', // has %s placeholders
294
			array("name"=>"Cat", "greeting2"=>"meow", "goodbye"=>"meow")
295
		);
296
		$this->assertContains(
297
			"TRANS Hello Cat meow. But it is late, meow",
298
			$translated, "Testing sprintf placeholders with named injections"
299
		);
300
301
		$translated = i18n::_t(
302
			'i18nTestModule.INJECTIONSLEGACY', // has %s placeholders
303
			array("Cat", "meow"/*, "meow" */) // remove third arg
304
		);
305
		$this->assertContains(
306
			"TRANS Hello Cat meow. But it is late, ",
307
			$translated, "Testing sprintf placeholders with unnamed injections and too few args"
308
		);
309
310
		$translated = i18n::_t(
311
			'i18nTestModule.INJECTIONS', // has {name} placeholders
312
			array("Cat", "meow", "meow")
313
		);
314
		$this->assertContains(
315
			"TRANS Hello Cat meow. But it is late, meow",
316
			$translated, "Testing named injection placeholders with unnamed injections"
317
		);
318
319
		i18n::set_locale($oldLocale);
320
	}
321
322
	/**
323
	 * See @i18nTestModule.ss for the template that is being used for this test
324
	 * */
325
	public function testNewTemplateTranslation() {
326
		global $lang;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
327
		$oldLocale = i18n::get_locale();
328
329
		i18n::set_locale('en_US');
330
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
331
			'i18nTestModule.NEWMETHODSIG' => 'TRANS New _t method signature test',
332
			'i18nTestModule.INJECTIONS' => 'TRANS Hello {name} {greeting}. But it is late, {goodbye}'
333
		),'en_US');
334
335
		$viewer = new SSViewer('i18nTestModule');
336
		$parsedHtml = Convert::nl2os($viewer->process(new ArrayData(array('TestProperty' => 'TestPropertyValue'))));
337
		$this->assertContains(
338
			Convert::nl2os("Hello Mark welcome. But it is late, bye\n"),
339
			$parsedHtml, "Testing fallback to the translation default (but using the injection array)"
340
		);
341
342
		$this->assertContains(
343
			Convert::nl2os("TRANS Hello Paul good you are here. But it is late, see you\n"),
344
			$parsedHtml, "Testing entity, default string and injection array"
345
		);
346
347
		$this->assertContains(
348
			Convert::nl2os("TRANS Hello Cat meow. But it is late, meow\n"),
349
			$parsedHtml, "Testing a translation with just entity and injection array"
350
		);
351
352
		//test injected calls
353
		$this->assertContains(
354
			Convert::nl2os(
355
				"TRANS Hello ".Director::absoluteBaseURL()." ".i18n::get_locale().". But it is late, global calls\n"
356
			),
357
			$parsedHtml,
358
			"Testing a translation with just entity and injection array, but with global variables injected in"
359
		);
360
361
		i18n::set_locale($oldLocale);
362
	}
363
364
	public function testGetLocaleFromLang() {
365
		$this->assertEquals('en_US', i18n::get_locale_from_lang('en'));
366
		$this->assertEquals('de_DE', i18n::get_locale_from_lang('de_DE'));
367
		$this->assertEquals('xy_XY', i18n::get_locale_from_lang('xy'));
368
	}
369
370
	public function testValidateLocale() {
371
		$this->assertTrue(i18n::validate_locale('en_US'), 'Known locale in underscore format is valid');
372
		$this->assertTrue(i18n::validate_locale('en-US'), 'Known locale in dash format is valid');
373
		$this->assertFalse(i18n::validate_locale('en'), 'Short lang format is not valid');
374
		$this->assertFalse(i18n::validate_locale('xx_XX'), 'Unknown locale in correct format is not valid');
375
		$this->assertFalse(i18n::validate_locale(''), 'Empty string is not valid');
376
	}
377
378
	public function testTranslate() {
379
		$oldLocale = i18n::get_locale();
380
381
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
382
			'i18nTestModule.ENTITY' => 'Entity with "Double Quotes"',
383
		), 'en_US');
384
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
385
			'i18nTestModule.ENTITY' => 'Entity with "Double Quotes" (de)',
386
			'i18nTestModule.ADDITION' => 'Addition (de)',
387
		), 'de');
388
		i18n::get_translator('core')->getAdapter()->addTranslation(array(
389
			'i18nTestModule.ENTITY' => 'Entity with "Double Quotes" (de_AT)',
390
		), 'de_AT');
391
392
393
		$this->assertEquals(i18n::_t('i18nTestModule.ENTITY'), 'Entity with "Double Quotes"',
394
			'Returns translation in default language'
395
		);
396
397
		i18n::set_locale('de');
398
		$this->assertEquals(i18n::_t('i18nTestModule.ENTITY'), 'Entity with "Double Quotes" (de)',
399
			'Returns translation according to current locale'
400
		);
401
402
		i18n::set_locale('de_AT');
403
		$this->assertEquals(i18n::_t('i18nTestModule.ENTITY'), 'Entity with "Double Quotes" (de_AT)',
404
			'Returns specific regional translation if available'
405
		);
406
		$this->assertEquals(i18n::_t('i18nTestModule.ADDITION'), 'Addition (de)',
407
			'Returns fallback non-regional translation if regional is not available'
408
		);
409
410
		i18n::set_locale('fr');
411
		$this->assertEquals(i18n::_t('i18nTestModule.ENTITY'), '',
412
			'Returns empty translation without default string if locale is not found'
413
		);
414
		$this->assertEquals(i18n::_t('i18nTestModule.ENTITY', 'default'), 'default',
415
			'Returns default string if locale is not found'
416
		);
417
418
		i18n::set_locale($oldLocale);
419
	}
420
421
	public function testIncludeByLocale() {
422
		// Looping through modules, so we can test the translation autoloading
423
		// Load non-exclusive to retain core class autoloading
424
		$classManifest = new SS_ClassManifest($this->alternateBasePath, true, true, false);
425
		SS_ClassLoader::instance()->pushManifest($classManifest);
426
427
		$adapter = i18n::get_translator('core')->getAdapter();
428
		$this->assertTrue($adapter->isAvailable('en'));
429
		$this->assertFalse($adapter->isAvailable('de'));
430
		$this->assertFalse($adapter->isTranslated('i18nTestModule.ENTITY', 'de'),
431
			'Existing unloaded entity not available before call'
432
		);
433
		$this->assertFalse($adapter->isTranslated('i18nTestModule.ENTITY', 'af'),
434
			'Non-existing unloaded entity not available before call'
435
		);
436
437
		// set _fakewebroot module priority
438
		Config::inst()->update('i18n', 'module_priority', array('subfolder','i18ntestmodule'));
439
440
		i18n::include_by_locale('de');
441
442
		$this->assertTrue($adapter->isAvailable('en'));
443
		$this->assertTrue($adapter->isAvailable('de'));
444
		$this->assertTrue($adapter->isTranslated('i18nTestModule.ENTITY', null, 'de'), 'Includes module files');
445
		$this->assertTrue($adapter->isTranslated('i18nTestTheme1.LAYOUTTEMPLATE', null, 'de'), 'Includes theme files');
446
		$this->assertTrue($adapter->isTranslated('i18nTestModule.OTHERENTITY', null, 'de'), 'Includes submodule files');
447
448
		// check module priority
449
		$this->assertEquals($adapter->translate('i18nTestModule.PRIORITYNOTICE', 'de'),
450
			'High Module Priority (de)'
451
		);
452
453
		SS_ClassLoader::instance()->popManifest();
454
	}
455
456
	public function testIncludeByLocaleWithoutFallbackLanguage() {
457
		$classManifest = new SS_ClassManifest($this->alternateBasePath, true, true, false);
458
		SS_ClassLoader::instance()->pushManifest($classManifest);
459
460
		$adapter = i18n::get_translator('core')->getAdapter();
461
		$this->assertTrue($adapter->isAvailable('en'));
462
		$this->assertFalse($adapter->isAvailable('mi')); // not defined at all
463
		$this->assertFalse($adapter->isAvailable('mi_NZ')); // defined, but not loaded yet
464
		$this->assertFalse($adapter->isTranslated('i18nTestModule.ENTITY', 'mi'),
465
			'Existing unloaded entity not available before call'
466
		);
467
		$this->assertFalse($adapter->isTranslated('i18nTestModule.ENTITY', 'mi_NZ'),
468
			'Non-existing unloaded entity not available before call'
469
		);
470
471
		i18n::include_by_locale('mi_NZ');
472
473
		$this->assertFalse($adapter->isAvailable('mi'));
474
		$this->assertTrue($adapter->isAvailable('mi_NZ'));
475
		$this->assertTrue($adapter->isTranslated('i18nTestModule.ENTITY', null, 'mi_NZ'), 'Includes module files');
476
477
		SS_ClassLoader::instance()->popManifest();
478
	}
479
480
	public function testRegisterTranslator() {
481
		$translator = new Zend_Translate(array(
482
			'adapter' => 'i18nTest_CustomTranslatorAdapter',
483
			'disableNotices' => true,
484
		));
485
486
		i18n::register_translator($translator, 'custom', 10);
487
		$translators = i18n::get_translators();
488
		$this->assertArrayHasKey('custom', $translators[10]);
489
		$this->assertInstanceOf('Zend_Translate', $translators[10]['custom']);
490
		$this->assertInstanceOf('i18nTest_CustomTranslatorAdapter', $translators[10]['custom']->getAdapter());
491
492
		i18n::unregister_translator('custom');
493
		$translators = i18n::get_translators();
494
		$this->assertArrayNotHasKey('custom', $translators[10]);
495
	}
496
497
	public function testMultipleTranslators() {
498
		// Looping through modules, so we can test the translation autoloading
499
		// Load non-exclusive to retain core class autoloading
500
		$classManifest = new SS_ClassManifest($this->alternateBasePath, true, true, false);
501
		SS_ClassLoader::instance()->pushManifest($classManifest);
502
503
		// Changed manifest, so we also need to unset all previously collected messages.
504
		// The easiest way to do this it to register a new adapter.
505
		$adapter = new Zend_Translate(array(
506
			'adapter' => 'i18nRailsYamlAdapter',
507
			'locale' => i18n::default_locale(),
0 ignored issues
show
Deprecated Code introduced by
The method i18n::default_locale() has been deprecated with message: since version 4.0; Use the "i18n.default_locale" config setting instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
508
			'disableNotices' => true,
509
		));
510
		i18n::register_translator($adapter, 'core');
511
512
		i18n::set_locale('en_US');
513
514
		$this->assertEquals(
515
			i18n::_t('i18nTestModule.ENTITY'),
516
			'Entity with "Double Quotes"'
517
		);
518
		$this->assertEquals(
519
			i18n::_t('AdapterEntity1', 'AdapterEntity1'),
520
			'AdapterEntity1',
521
			'Falls back to default string if not found'
522
		);
523
524
		// Add a new translator
525
		$translator = new Zend_Translate(array(
526
			'adapter' => 'i18nTest_CustomTranslatorAdapter',
527
			'disableNotices' => true,
528
		));
529
		i18n::register_translator($translator, 'custom', 11);
530
		$this->assertEquals(
531
			i18n::_t('i18nTestModule.ENTITY'),
532
			'i18nTestModule.ENTITY CustomAdapter (en_US)',
533
			'Existing entities overruled by adapter with higher priority'
534
		);
535
		$this->assertEquals(
536
			i18n::_t('AdapterEntity1', 'AdapterEntity1'),
537
			'AdapterEntity1 CustomAdapter (en_US)',
538
			'New entities only defined in new adapter are detected'
539
		);
540
541
		// Add a second new translator to test priorities
542
		$translator = new Zend_Translate(array(
543
			'adapter' => 'i18nTest_OtherCustomTranslatorAdapter',
544
			'disableNotices' => true,
545
		));
546
		i18n::register_translator($translator, 'othercustom_lower_prio', 5);
547
		$this->assertEquals(
548
			i18n::_t('i18nTestModule.ENTITY'),
549
			'i18nTestModule.ENTITY CustomAdapter (en_US)',
550
			'Adapter with lower priority loses'
551
		);
552
553
		// Add a third new translator to test priorities
554
		$translator = new Zend_Translate(array(
555
			'adapter' => 'i18nTest_OtherCustomTranslatorAdapter',
556
			'disableNotices' => true,
557
		));
558
559
		i18n::register_translator($translator, 'othercustom_higher_prio', 15);
560
561
		$this->assertEquals(
562
			i18n::_t('i18nTestModule.ENTITY'),
563
			'i18nTestModule.ENTITY OtherCustomAdapter (en_US)',
564
			'Adapter with higher priority wins'
565
		);
566
567
		i18n::unregister_translator('custom');
568
		i18n::unregister_translator('othercustom_lower_prio');
569
		i18n::unregister_translator('othercustom_higher_prio');
570
571
		SS_ClassLoader::instance()->popManifest();
572
	}
573
574
	public function testGetLanguageName() {
575
		Config::inst()->update(
576
			'i18n',
577
			'common_languages',
578
			array('de_CGN' => array('name' => 'German (Cologne)', 'native' => 'K&ouml;lsch'))
579
		);
580
		$this->assertEquals('German (Cologne)', i18n::get_language_name('de_CGN'));
581
		$this->assertEquals('K&ouml;lsch', i18n::get_language_name('de_CGN', true));
582
	}
583
}
584
585
class i18nTest_DataObject extends DataObject implements TestOnly {
586
587
	private static $db = array(
588
		'MyProperty' => 'Varchar',
589
		'MyUntranslatedProperty' => 'Text'
590
	);
591
592
	private static $has_one = array(
593
		'HasOneRelation' => 'SilverStripe\\Security\\Member'
594
	);
595
596
	private static $has_many = array(
597
		'HasManyRelation' => 'SilverStripe\\Security\\Member'
598
	);
599
600
	private static $many_many = array(
601
		'ManyManyRelation' => 'SilverStripe\\Security\\Member'
602
	);
603
604
	/**
605
	 *
606
	 * @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields
607
	 *
608
	 */
609
	public function fieldLabels($includerelations = true) {
610
		$labels = parent::fieldLabels($includerelations);
611
		$labels['MyProperty'] = _t('i18nTest_DataObject.MyProperty', 'My Property');
612
613
		return $labels;
614
	}
615
616
}
617
618
class i18nTest_Object extends Object implements TestOnly, i18nEntityProvider {
619
	static $my_translatable_property = "Untranslated";
620
621
	public static function my_translatable_property() {
622
		return _t("i18nTest_Object.my_translatable_property", self::$my_translatable_property);
623
	}
624
625
	public function provideI18nEntities() {
626
		return array(
627
			"i18nTest_Object.my_translatable_property" => array(
628
				self::$my_translatable_property
629
			)
630
		);
631
	}
632
}
633
634
class i18nTest_CustomTranslatorAdapter extends Zend_Translate_Adapter
635
		implements TestOnly,i18nTranslateAdapterInterface {
0 ignored issues
show
The implements keyword must be on the same line as the class name
Loading history...
Expected 1 space before "i18nTranslateAdapterInterface"; 0 found
Loading history...
636
	protected function _loadTranslationData($filename, $locale, array $options = array()) {
637
		return array(
638
			$locale => array(
639
				'AdapterEntity1' =>  'AdapterEntity1 CustomAdapter (' . $locale . ')',
640
				'i18nTestModule.ENTITY' => 'i18nTestModule.ENTITY CustomAdapter (' . $locale . ')',
641
			)
642
		);
643
	}
644
645
	public function toString() {
646
		return 'i18nTest_CustomTranslatorAdapter';
647
	}
648
649
	public function getFilenameForLocale($locale) {
650
		return false; // not file based
651
	}
652
}
653
654
class i18nTest_OtherCustomTranslatorAdapter extends Zend_Translate_Adapter
655
		implements TestOnly,i18nTranslateAdapterInterface {
0 ignored issues
show
The implements keyword must be on the same line as the class name
Loading history...
Expected 1 space before "i18nTranslateAdapterInterface"; 0 found
Loading history...
656
	protected function _loadTranslationData($filename, $locale, array $options = array()) {
657
		return array(
658
			$locale => array(
659
				'i18nTestModule.ENTITY' => 'i18nTestModule.ENTITY OtherCustomAdapter (' . $locale . ')',
660
			)
661
		);
662
	}
663
664
	public function toString() {
665
		return 'i18nTest_OtherCustomTranslatorAdapter';
666
	}
667
668
	public function getFilenameForLocale($locale) {
669
		return false; // not file based
670
	}
671
}
672