4 changed files with 468 additions and 171 deletions
			
			
		@ -1,168 +0,0 @@ | 
				
			|||||||
<?php | 
					 | 
				
			||||||
/** | 
					 | 
				
			||||||
 * @link http://www.yiiframework.com/ | 
					 | 
				
			||||||
 * @copyright Copyright (c) 2008 Yii Software LLC | 
					 | 
				
			||||||
 * @license http://www.yiiframework.com/license/ | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace yii\i18n; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use yii\base\NotSupportedException; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** | 
					 | 
				
			||||||
 * BaseMessageFormatter is a fallback implementation for the PHP intl MessageFormatter that is used in case intl extension is not installed. | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * This implementation only supports message plural formatting for english and simple parameters. | 
					 | 
				
			||||||
 * All other formats are ignored. | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * @author Carsten Brandt <mail@cebe.cc> | 
					 | 
				
			||||||
 * @since 2.0 | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
class BaseMessageFormatter | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	private $_locale; | 
					 | 
				
			||||||
	private $_pattern; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Constructs a new Message Formatter | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.create.php | 
					 | 
				
			||||||
	 * @param string $locale The locale to use when formatting arguments | 
					 | 
				
			||||||
	 * @param string $pattern The pattern string to stick arguments into. | 
					 | 
				
			||||||
	 * The pattern uses an 'apostrophe-friendly' syntax; it is run through | 
					 | 
				
			||||||
	 * umsg_autoQuoteApostrophe before being interpreted. | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function __construct($locale, $pattern) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		$this->_locale = $locale; | 
					 | 
				
			||||||
		$this->_pattern = $pattern; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Constructs a new Message Formatter | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.create.php | 
					 | 
				
			||||||
	 * @param string $locale The locale to use when formatting arguments | 
					 | 
				
			||||||
	 * @param string $pattern The pattern string to stick arguments into. | 
					 | 
				
			||||||
	 * The pattern uses an 'apostrophe-friendly' syntax; it is run through | 
					 | 
				
			||||||
	 * umsg_autoQuoteApostrophe before being interpreted. | 
					 | 
				
			||||||
	 * @return MessageFormatter The formatter object | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public static function create($locale, $pattern) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return new static($locale, $pattern); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Format the message | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.format.php | 
					 | 
				
			||||||
	 * @param array $args Arguments to insert into the format string | 
					 | 
				
			||||||
	 * @return string The formatted string, or <b>FALSE</b> if an error occurred | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function format(array $args) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return static::formatMessage($this->_locale, $this->_pattern, $args); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Quick format message | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.formatmessage.php | 
					 | 
				
			||||||
	 * @param string $locale The locale to use for formatting locale-dependent parts | 
					 | 
				
			||||||
	 * @param string $pattern The pattern string to insert things into. | 
					 | 
				
			||||||
	 * The pattern uses an 'apostrophe-friendly' syntax; it is run through | 
					 | 
				
			||||||
	 * umsg_autoQuoteApostrophe before being interpreted. | 
					 | 
				
			||||||
	 * @param array $args The array of values to insert into the format string | 
					 | 
				
			||||||
	 * @return string The formatted pattern string or <b>FALSE</b> if an error occurred | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public static function formatMessage($locale, $pattern, array $args) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		// TODO implement plural format | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		$a = []; | 
					 | 
				
			||||||
		foreach($args as $name => $value) { | 
					 | 
				
			||||||
			$a['{' . $name . '}'] = $value; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		return strtr($pattern, $a); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Parse input string according to pattern | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.parse.php | 
					 | 
				
			||||||
	 * @param string $value The string to parse | 
					 | 
				
			||||||
	 * @return array An array containing the items extracted, or <b>FALSE</b> on error | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function parse ($value) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Quick parse input string | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.parsemessage.php | 
					 | 
				
			||||||
	 * @param string $locale The locale to use for parsing locale-dependent parts | 
					 | 
				
			||||||
	 * @param string $pattern The pattern with which to parse the <i>value</i>. | 
					 | 
				
			||||||
	 * @param string $source The string to parse, conforming to the <i>pattern</i>. | 
					 | 
				
			||||||
	 * @return array An array containing items extracted, or <b>FALSE</b> on error | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public static function parseMessage ($locale, $pattern, $source) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Set the pattern used by the formatter | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.setpattern.php | 
					 | 
				
			||||||
	 * @param string $pattern The pattern string to use in this message formatter. | 
					 | 
				
			||||||
	 * The pattern uses an 'apostrophe-friendly' syntax; it is run through | 
					 | 
				
			||||||
	 * umsg_autoQuoteApostrophe before being interpreted. | 
					 | 
				
			||||||
	 * @return bool <b>TRUE</b> on success or <b>FALSE</b> on failure. | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function setPattern ($pattern) | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		$this->_pattern = $pattern; | 
					 | 
				
			||||||
		return true; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Get the pattern used by the formatter | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.getpattern.php | 
					 | 
				
			||||||
	 * @return string The pattern string for this message formatter | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function getPattern() | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return $this->_pattern; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Get the locale for which the formatter was created. | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.getlocale.php | 
					 | 
				
			||||||
	 * @return string The locale name | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function getLocale() | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return $this->_locale; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Get the error code from last operation | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.geterrorcode.php | 
					 | 
				
			||||||
	 * @return int The error code, one of UErrorCode values. Initial value is U_ZERO_ERROR. | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function getErrorCode() | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** | 
					 | 
				
			||||||
	 * Get the error text from the last operation | 
					 | 
				
			||||||
	 * @link http://php.net/manual/en/messageformatter.geterrormessage.php | 
					 | 
				
			||||||
	 * @return string Description of the last error. | 
					 | 
				
			||||||
	 */ | 
					 | 
				
			||||||
	public function getErrorMessage() | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return ''; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (!class_exists('MessageFormatter', false)) { | 
					 | 
				
			||||||
	class_alias('yii\\i18n\\BaseMessageFormatter', 'MessageFormatter'); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -0,0 +1,306 @@ | 
				
			|||||||
 | 
					<?php | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @link http://www.yiiframework.com/ | 
				
			||||||
 | 
					 * @copyright Copyright (c) 2008 Yii Software LLC | 
				
			||||||
 | 
					 * @license http://www.yiiframework.com/license/ | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace yii\i18n; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use yii\base\NotSupportedException; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * FallbackMessageFormatter is a fallback implementation for the PHP intl MessageFormatter that is | 
				
			||||||
 | 
					 * used in case PHP intl extension is not installed. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * Do not use this class directly. Use [[MessageFormatter]] instead, which will automatically detect | 
				
			||||||
 | 
					 * installed version of PHP intl and use the fallback if it is not installed. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * It is highly recommended that you install [PHP intl extension](http://php.net/manual/en/book.intl.php) if you want to use | 
				
			||||||
 | 
					 * MessageFormatter features. | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * This implementation only supports to following message formats: | 
				
			||||||
 | 
					 * - plural formatting for english | 
				
			||||||
 | 
					 * - select format | 
				
			||||||
 | 
					 * - simple parameters | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * The pattern also does NOT support the ['apostrophe-friendly' syntax](http://www.php.net/manual/en/messageformatter.formatmessage.php). | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * @author Carsten Brandt <mail@cebe.cc> | 
				
			||||||
 | 
					 * @since 2.0 | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					class FallbackMessageFormatter | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						private $_locale; | 
				
			||||||
 | 
						private $_pattern; | 
				
			||||||
 | 
						private $_errorMessage = ''; | 
				
			||||||
 | 
						private $_errorCode = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Constructs a new Message Formatter | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.create.php | 
				
			||||||
 | 
						 * @param string $locale The locale to use when formatting arguments | 
				
			||||||
 | 
						 * @param string $pattern The pattern string to stick arguments into. | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function __construct($locale, $pattern) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$this->_locale = $locale; | 
				
			||||||
 | 
							$this->_pattern = $pattern; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Constructs a new Message Formatter | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.create.php | 
				
			||||||
 | 
						 * @param string $locale The locale to use when formatting arguments | 
				
			||||||
 | 
						 * @param string $pattern The pattern string to stick arguments into. | 
				
			||||||
 | 
						 * @return MessageFormatter The formatter object | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public static function create($locale, $pattern) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return new static($locale, $pattern); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Format the message | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.format.php | 
				
			||||||
 | 
						 * @param array $args Arguments to insert into the format string | 
				
			||||||
 | 
						 * @return string The formatted string, or `FALSE` if an error occurred | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function format(array $args) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return static::formatMessage($this->_locale, $this->_pattern, $args); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Quick format message | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.formatmessage.php | 
				
			||||||
 | 
						 * @param string $locale The locale to use for formatting locale-dependent parts | 
				
			||||||
 | 
						 * @param string $pattern The pattern string to insert things into. | 
				
			||||||
 | 
						 * @param array $args The array of values to insert into the format string | 
				
			||||||
 | 
						 * @return string The formatted pattern string or `FALSE` if an error occurred | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public static function formatMessage($locale, $pattern, array $args) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							if (($tokens = static::tokenizePattern($pattern)) === false) { | 
				
			||||||
 | 
								return false; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							foreach($tokens as $i => $token) { | 
				
			||||||
 | 
								if (is_array($token)) { | 
				
			||||||
 | 
									if (($tokens[$i] = static::parseToken($token, $args, $locale)) === false) { | 
				
			||||||
 | 
										return false; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return implode('', $tokens); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Tokenizes a pattern by separating normal text from replaceable patterns | 
				
			||||||
 | 
						 * @param string $pattern patter to tokenize | 
				
			||||||
 | 
						 * @return array|bool array of tokens or false on failure | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						private static function tokenizePattern($pattern) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$depth = 1; | 
				
			||||||
 | 
							if (($start = $pos = mb_strpos($pattern, '{')) === false) { | 
				
			||||||
 | 
								return [$pattern]; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							$tokens = [mb_substr($pattern, 0, $pos)]; | 
				
			||||||
 | 
							while(true) { | 
				
			||||||
 | 
								$open = mb_strpos($pattern, '{', $pos + 1); | 
				
			||||||
 | 
								$close = mb_strpos($pattern, '}', $pos + 1); | 
				
			||||||
 | 
								if ($open === false && $close === false) { | 
				
			||||||
 | 
									break; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								if ($open === false) { | 
				
			||||||
 | 
									$open = mb_strlen($pattern); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								if ($close > $open) { | 
				
			||||||
 | 
									$depth++; | 
				
			||||||
 | 
									$pos = $open; | 
				
			||||||
 | 
								} else { | 
				
			||||||
 | 
									$depth--; | 
				
			||||||
 | 
									$pos = $close; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								if ($depth == 0) { | 
				
			||||||
 | 
									$tokens[] = explode(',', mb_substr($pattern, $start + 1, $pos - $start - 1), 3); | 
				
			||||||
 | 
									$start = $pos + 1; | 
				
			||||||
 | 
									$tokens[] = mb_substr($pattern, $start, $open - $start); | 
				
			||||||
 | 
									$start = $open; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							if ($depth != 0) { | 
				
			||||||
 | 
								return false; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return $tokens; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Parses a token | 
				
			||||||
 | 
						 * @param array $token the token to parse | 
				
			||||||
 | 
						 * @param array $args arguments to replace | 
				
			||||||
 | 
						 * @param string $locale the locale | 
				
			||||||
 | 
						 * @return bool|string parsed token or false on failure | 
				
			||||||
 | 
						 * @throws \yii\base\NotSupportedException when unsupported formatting is used. | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						private static function parseToken($token, $args, $locale) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$param = trim($token[0]); | 
				
			||||||
 | 
							if (isset($args[$param])) { | 
				
			||||||
 | 
								$arg = $args[$param]; | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								return '{' . implode(',', $token) . '}'; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							$type = isset($token[1]) ? trim($token[1]) : 'none'; | 
				
			||||||
 | 
							switch($type) | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								case 'number': | 
				
			||||||
 | 
								case 'date': | 
				
			||||||
 | 
								case 'time': | 
				
			||||||
 | 
								case 'spellout': | 
				
			||||||
 | 
								case 'ordinal': | 
				
			||||||
 | 
								case 'duration': | 
				
			||||||
 | 
								case 'choice': | 
				
			||||||
 | 
								case 'selectordinal': | 
				
			||||||
 | 
									throw new NotSupportedException("Message format '$type' is not supported. You have to install PHP intl extension to use this feature."); | 
				
			||||||
 | 
								case 'none': return $arg; | 
				
			||||||
 | 
								case 'select': | 
				
			||||||
 | 
									/* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html | 
				
			||||||
 | 
									selectStyle = (selector '{' message '}')+ | 
				
			||||||
 | 
									*/ | 
				
			||||||
 | 
									$select = static::tokenizePattern($token[2]); | 
				
			||||||
 | 
									$c = count($select); | 
				
			||||||
 | 
									$message = false; | 
				
			||||||
 | 
									for($i = 0; $i + 1 < $c; $i++) { | 
				
			||||||
 | 
										if (is_array($select[$i]) || !is_array($select[$i + 1])) { | 
				
			||||||
 | 
											return false; | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
										$selector = trim($select[$i++]); | 
				
			||||||
 | 
										if ($message === false && $selector == 'other' || $selector == $arg) { | 
				
			||||||
 | 
											$message = implode(',', $select[$i]); | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									if ($message !== false) { | 
				
			||||||
 | 
										return static::formatMessage($locale, $message, $args); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								break; | 
				
			||||||
 | 
								case 'plural': | 
				
			||||||
 | 
									/* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html | 
				
			||||||
 | 
									pluralStyle = [offsetValue] (selector '{' message '}')+ | 
				
			||||||
 | 
									offsetValue = "offset:" number | 
				
			||||||
 | 
									selector = explicitValue | keyword | 
				
			||||||
 | 
									explicitValue = '=' number  // adjacent, no white space in between | 
				
			||||||
 | 
									keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+ | 
				
			||||||
 | 
									message: see MessageFormat | 
				
			||||||
 | 
									*/ | 
				
			||||||
 | 
									$plural = static::tokenizePattern($token[2]); | 
				
			||||||
 | 
									$c = count($plural); | 
				
			||||||
 | 
									$message = false; | 
				
			||||||
 | 
									$offset = 0; | 
				
			||||||
 | 
									for($i = 0; $i + 1 < $c; $i++) { | 
				
			||||||
 | 
										if (is_array($plural[$i]) || !is_array($plural[$i + 1])) { | 
				
			||||||
 | 
											return false; | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
										$selector = trim($plural[$i++]); | 
				
			||||||
 | 
										if ($i == 1 && substr($selector, 0, 7) == 'offset:') { | 
				
			||||||
 | 
											$offset = (int) trim(mb_substr($selector, 7, ($pos = mb_strpos(str_replace(["\n", "\r", "\t"], ' ', $selector), ' ', 7)) - 7)); | 
				
			||||||
 | 
											$selector = trim(mb_substr($selector, $pos + 1)); | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
										if ($message === false && $selector == 'other' || | 
				
			||||||
 | 
											$selector[0] == '=' && (int) mb_substr($selector, 1) == $arg || | 
				
			||||||
 | 
											$selector == 'zero' && $arg - $offset == 0 || | 
				
			||||||
 | 
											$selector == 'one' && $arg - $offset == 1 || | 
				
			||||||
 | 
											$selector == 'two' && $arg - $offset == 2 | 
				
			||||||
 | 
										) { | 
				
			||||||
 | 
											$message = implode(',', str_replace('#', $arg - $offset, $plural[$i])); | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									if ($message !== false) { | 
				
			||||||
 | 
										return static::formatMessage($locale, $message, $args); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									break; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return false; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Parse input string according to pattern | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.parse.php | 
				
			||||||
 | 
						 * @param string $value The string to parse | 
				
			||||||
 | 
						 * @return array An array containing the items extracted, or `FALSE` on error | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function parse($value) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Quick parse input string | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.parsemessage.php | 
				
			||||||
 | 
						 * @param string $locale The locale to use for parsing locale-dependent parts | 
				
			||||||
 | 
						 * @param string $pattern The pattern with which to parse the `value`. | 
				
			||||||
 | 
						 * @param string $source The string to parse, conforming to the `pattern`. | 
				
			||||||
 | 
						 * @return array An array containing items extracted, or `FALSE` on error | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public static function parseMessage($locale, $pattern, $source) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Set the pattern used by the formatter | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.setpattern.php | 
				
			||||||
 | 
						 * @param string $pattern The pattern string to use in this message formatter. | 
				
			||||||
 | 
						 * @return bool `TRUE` on success or `FALSE` on failure. | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function setPattern($pattern) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$this->_pattern = $pattern; | 
				
			||||||
 | 
							return true; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Get the pattern used by the formatter | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.getpattern.php | 
				
			||||||
 | 
						 * @return string The pattern string for this message formatter | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function getPattern() | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->_pattern; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Get the locale for which the formatter was created. | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.getlocale.php | 
				
			||||||
 | 
						 * @return string The locale name | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function getLocale() | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->_locale; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Get the error code from last operation | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.geterrorcode.php | 
				
			||||||
 | 
						 * @return int The error code, one of UErrorCode values. Initial value is U_ZERO_ERROR. | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function getErrorCode() | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->_errorCode; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * Get the error text from the last operation | 
				
			||||||
 | 
						 * @link http://php.net/manual/en/messageformatter.geterrormessage.php | 
				
			||||||
 | 
						 * @return string Description of the last error. | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function getErrorMessage() | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->_errorMessage; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!class_exists('MessageFormatter', false)) { | 
				
			||||||
 | 
						class_alias('yii\\i18n\\FallbackMessageFormatter', 'MessageFormatter'); | 
				
			||||||
 | 
						define('YII_INTL_MESSAGE_FALLBACK', true); | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,155 @@ | 
				
			|||||||
 | 
					<?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\FallbackMessageFormatter; | 
				
			||||||
 | 
					use yiiunit\TestCase; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @author Carsten Brandt <mail@cebe.cc> | 
				
			||||||
 | 
					 * @since 2.0 | 
				
			||||||
 | 
					 * @group i18n | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					class FallbackMessageFormatterTest 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.'}', // 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' | 
				
			||||||
 | 
									] | 
				
			||||||
 | 
								], | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								[ | 
				
			||||||
 | 
									'{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', | 
				
			||||||
 | 
									], | 
				
			||||||
 | 
								], | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 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', | 
				
			||||||
 | 
									] | 
				
			||||||
 | 
								], | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 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', | 
				
			||||||
 | 
									], | 
				
			||||||
 | 
								], | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// some parser specific verifications | 
				
			||||||
 | 
								[ | 
				
			||||||
 | 
									'{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr} is {gender}!', | 
				
			||||||
 | 
									'male and wtf loves 42 is male!', | 
				
			||||||
 | 
									[ | 
				
			||||||
 | 
										'nr' => 42, | 
				
			||||||
 | 
										'gender' => 'male', | 
				
			||||||
 | 
										'he' => 'wtf', | 
				
			||||||
 | 
										'she' => 'wtf', | 
				
			||||||
 | 
									], | 
				
			||||||
 | 
								], | 
				
			||||||
 | 
							]; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * @dataProvider patterns | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function testNamedArgumentsStatic($pattern, $expected, $args) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$result = FallbackMessageFormatter::formatMessage('en_US', $pattern, $args); | 
				
			||||||
 | 
							$this->assertEquals($expected, $result); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * @dataProvider patterns | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function testNamedArgumentsObject($pattern, $expected, $args) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$formatter = new FallbackMessageFormatter('en_US', $pattern); | 
				
			||||||
 | 
							$result = $formatter->format($args); | 
				
			||||||
 | 
							$this->assertEquals($expected, $result, $formatter->getErrorMessage()); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function testInsufficientArguments() | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$result = FallbackMessageFormatter::formatMessage('en_US', '{'.self::SUBJECT.'} is {'.self::N.'}', [ | 
				
			||||||
 | 
								self::N => self::N_VALUE, | 
				
			||||||
 | 
							]); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$this->assertEquals($expected, $result); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function testNoParams() | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$pattern = '{'.self::SUBJECT.'} is '.self::N; | 
				
			||||||
 | 
							$result = FallbackMessageFormatter::formatMessage('en_US', $pattern, []); | 
				
			||||||
 | 
							$this->assertEquals($pattern, $result); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$formatter = new FallbackMessageFormatter('en_US', $pattern); | 
				
			||||||
 | 
							$result = $formatter->format([]); | 
				
			||||||
 | 
							$this->assertEquals($pattern, $result, $formatter->getErrorMessage()); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue