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()); |
|
} |
|
}
|
|
|