| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 | <?php/** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */namespace yii\i18n;use Yii;use yii\base\Component;use yii\base\InvalidConfigException;/** * I18N provides features related with internationalization (I18N) and localization (L10N). * * I18N is configured as an application component in [[\yii\base\Application]] by default. * You can access that instance via `Yii::$app->i18n`. * * @property MessageFormatter $messageFormatter The message formatter to be used to format message via ICU * message format. Note that the type of this property differs in getter and setter. See * [[getMessageFormatter()]] and [[setMessageFormatter()]] for details. * * @author Qiang Xue <qiang.xue@gmail.com> * @since 2.0 */class I18N extends Component{    /**     * @var array list of [[MessageSource]] configurations or objects. The array keys are message     * category patterns, and the array values are the corresponding [[MessageSource]] objects or the configurations     * for creating the [[MessageSource]] objects.     *     * The message category patterns can contain the wildcard `*` at the end to match multiple categories with the same prefix.     * For example, `app/*` matches both `app/cat1` and `app/cat2`.     *     * The `*` category pattern will match all categories that do not match any other category patterns.     *     * This property may be modified on the fly by extensions who want to have their own message sources     * registered under their own namespaces.     *     * The category `yii` and `app` are always defined. The former refers to the messages used in the Yii core     * framework code, while the latter refers to the default message category for custom application code.     * By default, both of these categories use [[PhpMessageSource]] and the corresponding message files are     * stored under `@yii/messages` and `@app/messages`, respectively.     *     * You may override the configuration of both categories.     */    public $translations;    /**     * Initializes the component by configuring the default message categories.     */    public function init()    {        parent::init();        if (!isset($this->translations['yii']) && !isset($this->translations['yii*'])) {            $this->translations['yii'] = [                'class' => 'yii\i18n\PhpMessageSource',                'sourceLanguage' => 'en-US',                'basePath' => '@yii/messages',            ];        }        if (!isset($this->translations['app']) && !isset($this->translations['app*'])) {            $this->translations['app'] = [                'class' => 'yii\i18n\PhpMessageSource',                'sourceLanguage' => Yii::$app->sourceLanguage,                'basePath' => '@app/messages',            ];        }    }    /**     * Translates a message to the specified language.     *     * After translation the message will be formatted using [[MessageFormatter]] if it contains     * ICU message format and `$params` are not empty.     *     * @param string $category the message category.     * @param string $message the message to be translated.     * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.     * @param string $language the language code (e.g. `en-US`, `en`).     * @return string the translated and formatted message.     */    public function translate($category, $message, $params, $language)    {        $messageSource = $this->getMessageSource($category);        $translation = $messageSource->translate($category, $message, $language);        if ($translation === false) {            return $this->format($message, $params, $messageSource->sourceLanguage);        }        return $this->format($translation, $params, $language);    }    /**     * Formats a message using [[MessageFormatter]].     *     * @param string $message the message to be formatted.     * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.     * @param string $language the language code (e.g. `en-US`, `en`).     * @return string the formatted message.     */    public function format($message, $params, $language)    {        $params = (array) $params;        if ($params === []) {            return $message;        }        if (preg_match('~{\s*[\w.]+\s*,~u', $message)) {            $formatter = $this->getMessageFormatter();            $result = $formatter->format($message, $params, $language);            if ($result === false) {                $errorMessage = $formatter->getErrorMessage();                Yii::warning("Formatting message for language '$language' failed with error: $errorMessage. The message being formatted was: $message.", __METHOD__);                return $message;            }            return $result;        }        $p = [];        foreach ($params as $name => $value) {            $p['{' . $name . '}'] = $value;        }        return strtr($message, $p);    }    /**     * @var string|array|MessageFormatter     */    private $_messageFormatter;    /**     * Returns the message formatter instance.     * @return MessageFormatter the message formatter to be used to format message via ICU message format.     */    public function getMessageFormatter()    {        if ($this->_messageFormatter === null) {            $this->_messageFormatter = new MessageFormatter();        } elseif (is_array($this->_messageFormatter) || is_string($this->_messageFormatter)) {            $this->_messageFormatter = Yii::createObject($this->_messageFormatter);        }        return $this->_messageFormatter;    }    /**     * @param string|array|MessageFormatter $value the message formatter to be used to format message via ICU message format.     * Can be given as array or string configuration that will be given to [[Yii::createObject]] to create an instance     * or a [[MessageFormatter]] instance.     */    public function setMessageFormatter($value)    {        $this->_messageFormatter = $value;    }    /**     * Returns the message source for the given category.     * @param string $category the category name.     * @return MessageSource the message source for the given category.     * @throws InvalidConfigException if there is no message source available for the specified category.     */    public function getMessageSource($category)    {        if (isset($this->translations[$category])) {            $source = $this->translations[$category];            if ($source instanceof MessageSource) {                return $source;            }            return $this->translations[$category] = Yii::createObject($source);        }        // try wildcard matching        foreach ($this->translations as $pattern => $source) {            if (strpos($pattern, '*') > 0 && strpos($category, rtrim($pattern, '*')) === 0) {                if ($source instanceof MessageSource) {                    return $source;                }                return $this->translations[$category] = $this->translations[$pattern] = Yii::createObject($source);            }        }        // match '*' in the last        if (isset($this->translations['*'])) {            $source = $this->translations['*'];            if ($source instanceof MessageSource) {                return $source;            }            return $this->translations[$category] = $this->translations['*'] = Yii::createObject($source);        }        throw new InvalidConfigException("Unable to locate message source for category '$category'.");    }}
 |