You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							337 lines
						
					
					
						
							9.0 KiB
						
					
					
				
			
		
		
	
	
							337 lines
						
					
					
						
							9.0 KiB
						
					
					
				| <?php | |
| /** | |
|  * @link http://www.yiiframework.com/ | |
|  * @copyright Copyright (c) 2008 Yii Software LLC | |
|  * @license http://www.yiiframework.com/license/ | |
|  */ | |
|  | |
| namespace yiiunit\framework\i18n; | |
|  | |
| use yii\i18n\MessageFormatter; | |
| use yiiunit\TestCase; | |
|  | |
| /** | |
|  * @author Alexander Makarov <sam@rmcreative.ru> | |
|  * @since 2.0 | |
|  * @group i18n | |
|  */ | |
| class MessageFormatterTest extends TestCase | |
| { | |
| 	const N = 'n'; | |
| 	const N_VALUE = 42; | |
| 	const SUBJECT = 'сабж'; | |
| 	const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; | |
|  | |
| 	public function patterns() | |
| 	{ | |
| 		return [ | |
| 			[ | |
| 				'{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern | |
| 				self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected | |
| 				[ // params | |
| 					self::N => self::N_VALUE, | |
| 					self::SUBJECT => self::SUBJECT_VALUE, | |
| 				] | |
| 			], | |
|  | |
| 			[ | |
| 				'{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern | |
| 				self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected | |
| 				[ // params | |
| 					self::N => self::N_VALUE, | |
| 					self::SUBJECT => self::SUBJECT_VALUE, | |
| 				] | |
| 			], | |
|  | |
| 			// This one was provided by Aura.Intl. Thanks! | |
| 			[<<<_MSG_ | |
| {gender_of_host, select, | |
|   female {{num_guests, plural, offset:1 | |
| 	  =0 {{host} does not give a party.} | |
| 	  =1 {{host} invites {guest} to her party.} | |
| 	  =2 {{host} invites {guest} and one other person to her party.} | |
| 	 other {{host} invites {guest} and # other people to her party.}}} | |
|   male {{num_guests, plural, offset:1 | |
| 	  =0 {{host} does not give a party.} | |
| 	  =1 {{host} invites {guest} to his party.} | |
| 	  =2 {{host} invites {guest} and one other person to his party.} | |
| 	 other {{host} invites {guest} and # other people to his party.}}} | |
|   other {{num_guests, plural, offset:1 | |
| 	  =0 {{host} does not give a party.} | |
| 	  =1 {{host} invites {guest} to their party.} | |
| 	  =2 {{host} invites {guest} and one other person to their party.} | |
| 	  other {{host} invites {guest} and # other people to their party.}}}} | |
| _MSG_ | |
| 				, | |
| 				'ralph invites beep and 3 other people to his party.', | |
| 				[ | |
| 					'gender_of_host' => 'male', | |
| 					'num_guests' => 4, | |
| 					'host' => 'ralph', | |
| 					'guest' => 'beep' | |
| 				], | |
| 				defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), | |
| 				'select format is available in ICU > 4.4 and plural format with =X selector is avilable since 4.8' | |
| 			], | |
|  | |
| 			[ | |
| 				'{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', | |
| 				'Alexander is male and he loves Yii!', | |
| 				[ | |
| 					'name' => 'Alexander', | |
| 					'gender' => 'male', | |
| 				], | |
| 				defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), | |
| 				'select format is available in ICU > 4.4' | |
| 			], | |
|  | |
| 			// verify pattern in select does not get replaced | |
| 			[ | |
| 				'{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', | |
| 				'Alexander is male and he loves Yii!', | |
| 				[ | |
| 					'name' => 'Alexander', | |
| 					'gender' => 'male', | |
| 					 // following should not be replaced | |
| 					'he' => 'wtf', | |
| 					'she' => 'wtf', | |
| 					'it' => 'wtf', | |
| 				], | |
| 				defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), | |
| 				'select format is available in ICU > 4.4' | |
| 			], | |
|  | |
| 			// verify pattern in select message gets replaced | |
| 			[ | |
| 				'{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', | |
| 				'Alexander is male and wtf loves Yii!', | |
| 				[ | |
| 					'name' => 'Alexander', | |
| 					'gender' => 'male', | |
| 					'he' => 'wtf', | |
| 					'she' => 'wtf', | |
| 				], | |
| 				defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), | |
| 				'parameters in select format do not seem to work in ICU < 4.8' | |
| 			], | |
|  | |
| 			// some parser specific verifications | |
| 			[ | |
| 				'{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr, number} is {gender}!', | |
| 				'male and wtf loves 42 is male!', | |
| 				[ | |
| 					'nr' => 42, | |
| 					'gender' => 'male', | |
| 					'he' => 'wtf', | |
| 					'she' => 'wtf', | |
| 				], | |
| 				defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), | |
| 				'select format is available in ICU > 4.4' | |
| 			], | |
|  | |
| 			// test ICU version compatibility | |
| 			[ | |
| 				'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', | |
| 				'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', | |
| 				[], | |
| 			], | |
| 			[ | |
| 				'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', | |
| 				'Showing <b>1-10</b> of <b>12</b> items.', | |
| 				[// A | |
| 					'begin' => 1, | |
| 					'end' => 10, | |
| 					'count' => 10, | |
| 					'totalCount' => 12, | |
| 					'page' => 1, | |
| 					'pageCount' => 2, | |
| 				] | |
| 			], | |
| 			[ | |
| 				'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', | |
| 				'Showing <b>1-1</b> of <b>1</b> item.', | |
| 				[// B | |
| 					'begin' => 1, | |
| 					'end' => 1, | |
| 					'count' => 1, | |
| 					'totalCount' => 1, | |
| 					'page' => 1, | |
| 					'pageCount' => 1, | |
| 				] | |
| 			], | |
| 			[ | |
| 				'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', | |
| 				'Showing <b>0-0</b> of <b>0</b> items.', | |
| 				[// C | |
| 					'begin' => 0, | |
| 					'end' => 0, | |
| 					'count' => 0, | |
| 					'totalCount' => 0, | |
| 					'page' => 1, | |
| 					'pageCount' => 1, | |
| 				] | |
| 			], | |
| 			[ | |
| 				'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.', | |
| 				'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.', | |
| 				[] | |
| 			], | |
| 			[ | |
| 				'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.', | |
| 				'Total <b>1</b> item.', | |
| 				[ | |
| 					'count' => 1, | |
| 				] | |
| 			], | |
| 			[ | |
| 				'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.', | |
| 				'Total <b>1</b> item.', | |
| 				[ | |
| 					'begin' => 5, | |
| 					'count' => 1, | |
| 					'end' => 10, | |
| 				] | |
| 			], | |
| 			[ | |
| 				'{0, plural, one {offer} other {offers}}', | |
| 				'{0, plural, one {offer} other {offers}}', | |
| 				[], | |
| 			], | |
| 			[ | |
| 				'{0, plural, one {offer} other {offers}}', | |
| 				'offers', | |
| 				[0], | |
| 			], | |
| 			[ | |
| 				'{0, plural, one {offer} other {offers}}', | |
| 				'offer', | |
| 				[1], | |
| 			], | |
| 			[ | |
| 				'{0, plural, one {offer} other {offers}}', | |
| 				'offers', | |
| 				[13], | |
| 			], | |
| 		]; | |
| 	} | |
|  | |
| 	public function parsePatterns() | |
| 	{ | |
| 		return [ | |
| 			[ | |
| 				self::SUBJECT_VALUE.' is {0, number}', // pattern | |
| 				self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected | |
| 				[ // params | |
| 					0 => self::N_VALUE, | |
| 				] | |
| 			], | |
|  | |
| 			[ | |
| 				self::SUBJECT_VALUE.' is {'.self::N.', number}', // pattern | |
| 				self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected | |
| 				[ // params | |
| 					self::N => self::N_VALUE, | |
| 				] | |
| 			], | |
|  | |
| 			[ | |
| 				self::SUBJECT_VALUE.' is {'.self::N.', number, integer}', // pattern | |
| 				self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected | |
| 				[ // params | |
| 					self::N => self::N_VALUE, | |
| 				] | |
| 			], | |
|  | |
| 			[ | |
| 				"{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree", | |
| 				"4,560 monkeys on 123 trees make 37.073 monkeys per tree", | |
| 				[ | |
| 					0 => 4560, | |
| 					1 => 123, | |
| 					2 => 37.073 | |
| 				], | |
| 				'en-US' | |
| 			], | |
|  | |
| 			[ | |
| 				"{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum", | |
| 				"4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", | |
| 				[ | |
| 					0 => 4560, | |
| 					1 => 123, | |
| 					2 => 37.073 | |
| 				], | |
| 				'de', | |
| 			], | |
|  | |
| 			[ | |
| 				"{monkeyCount,number,integer} monkeys on {trees,number,integer} trees make {monkeysPerTree,number} monkeys per tree", | |
| 				"4,560 monkeys on 123 trees make 37.073 monkeys per tree", | |
| 				[ | |
| 					'monkeyCount' => 4560, | |
| 					'trees' => 123, | |
| 					'monkeysPerTree' => 37.073 | |
| 				], | |
| 				'en-US' | |
| 			], | |
|  | |
| 			[ | |
| 				"{monkeyCount,number,integer} Affen auf {trees,number,integer} Bäumen sind {monkeysPerTree,number} Affen pro Baum", | |
| 				"4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", | |
| 				[ | |
| 					'monkeyCount' => 4560, | |
| 					'trees' => 123, | |
| 					'monkeysPerTree' => 37.073 | |
| 				], | |
| 				'de', | |
| 			], | |
| 		]; | |
| 	} | |
|  | |
| 	/** | |
| 	 * @dataProvider patterns | |
| 	 */ | |
| 	public function testNamedArguments($pattern, $expected, $args, $skip = false, $skipMessage = '') | |
| 	{ | |
| 		if ($skip) { | |
| 			$this->markTestSkipped($skipMessage); | |
| 		} | |
| 		$formatter = new MessageFormatter(); | |
| 		$result = $formatter->format($pattern, $args, 'en-US'); | |
| 		$this->assertEquals($expected, $result, $formatter->getErrorMessage()); | |
| 	} | |
|  | |
| 	/** | |
| 	 * @dataProvider parsePatterns | |
| 	 */ | |
| 	public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en-US') | |
| 	{ | |
| 		if (!extension_loaded("intl")) { | |
| 			$this->markTestSkipped("intl not installed. Skipping."); | |
| 		} | |
|  | |
| 		$formatter = new MessageFormatter(); | |
| 		$result = $formatter->parse($pattern, $expected, $locale); | |
| 		$this->assertEquals($args, $result, $formatter->getErrorMessage() . ' Pattern: ' . $pattern); | |
| 	} | |
|  | |
| 	public function testInsufficientArguments() | |
| 	{ | |
| 		$expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; | |
|  | |
| 		$formatter = new MessageFormatter(); | |
| 		$result = $formatter->format('{'.self::SUBJECT.'} is {'.self::N.', number}', [ | |
| 			self::N => self::N_VALUE, | |
| 		], 'en-US'); | |
|  | |
| 		$this->assertEquals($expected, $result, $formatter->getErrorMessage()); | |
| 	} | |
|  | |
| 	public function testNoParams() | |
| 	{ | |
| 		$pattern = '{'.self::SUBJECT.'} is '.self::N; | |
| 		$formatter = new MessageFormatter(); | |
| 		$result = $formatter->format($pattern, [], 'en-US'); | |
| 		$this->assertEquals($pattern, $result, $formatter->getErrorMessage()); | |
| 	} | |
| }
 | |
| 
 |