举例说明常见的翻译:Yii::t('app','Login');
追踪源码:BaseYii.php 文件 ,Yii::t($category, $message, $params = [], $language = null) 这个方法实际上是 \yii\i18n\I18N::translate()的一个捷径方法
/**
* Translates a message to the specified language.
*
* This is a shortcut method of [[\yii\i18n\I18N::translate()]].
*
* The translation will be conducted according to the message category and the target language will be used.
*
* You can add parameters to a translation message that will be substituted(取代) with the corresponding(相应的) value after
* translation. The format for this is to use curly brackets around the parameter name as you can see in the following example:
*
* ```php
* $username = 'Alexander';
* echo \Yii::t('app', 'Hello, {username}!', ['username' => $username]);
* ```
*
* Further formatting of message parameters is supported using the [PHP intl extensions](http://www.php.net/manual/en/intro.intl.php)
* message formatter. See [[\yii\i18n\I18N::translate()]] for more details.
*
* @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`). If this is null, the current
* [[\yii\base\Application::language|application language]] will be used.
* @return string the translated message.
*/
public static function t($category, $message, $params = [], $language = null)
{
if (static::$app !== null) {
return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language);
} else {
$p = [];
foreach ((array) $params as $name => $value) {
$p['{' . $name . '}'] = $value;
} return ($p === []) ? $message : strtr($message, $p);
}
}
查看 \yii\i18n\I18N::translate()方法:
/**
* 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 the message source for the given category.
$messageSource = $this->getMessageSource($category);
//返回翻译的内容
$translation = $messageSource->translate($category, $message, $language);
//格式话翻译的内容
if ($translation === false) {
return $this->format($message, $params, $messageSource->sourceLanguage);
} else {
return $this->format($translation, $params, $language);
}
}
其中 $messageSource = $this->getMessageSource($category);//根据配置文件内容和 给的参数$category 返回继承MessageSource 相应子类的实例对象, 本例根据配置文件返回PhpMessageSource对象
<?php
return [
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'i18n'=>[
'translations' => [
'app*'=> [
'class' => 'yii\i18n\PhpMessageSource',
'basePath'=>'@common/messages',
'fileMap'=>[
'app'=>'app.php',
],
],
],
],
],
];
$messageSource = $this->getMessageSource($category); 返回继承MessageSource 相应子类的实例对象
/**
* 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.
*/
//根据配置文件内容和 给的参数$category 返回继承MessageSource 相应子类的实例对象, 本例根据配置文件返回PhpMessageSource对象
public function getMessageSource($category)
{
if (isset($this->translations[$category])) {
$source = $this->translations[$category];
if ($source instanceof MessageSource) {
return $source;
} else {
return $this->translations[$category] = Yii::createObject($source);
}
} else {
// try wildcard matching
foreach ($this->translations as $pattern => $source) {
if (strpos($pattern, '*') > 0 && strpos($category, rtrim($pattern, '*')) === 0) {
if ($source instanceof MessageSource) {
return $source;
} else {
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;
} else {
return $this->translations[$category] = $this->translations['*'] = Yii::createObject($source);
}
}
} throw new InvalidConfigException("Unable to locate message source for category '$category'.");
}
再根据实例对象的translate方法返回翻译的内容, $translation = $messageSource->translate($category, $message, $language);
MessageSource 类的 translate方法如下:
/**
* Translates a message to the specified language.
*
* Note that unless [[forceTranslation]] is true, if the target language
* is the same as the [[sourceLanguage|source language]], the message
* will NOT be translated.
*
* If a translation is not found, a [[EVENT_MISSING_TRANSLATION|missingTranslation]] event will be triggered.
*
* @param string $category the message category
* @param string $message the message to be translated
* @param string $language the target language
* @return string|boolean the translated message or false if translation wasn't found or isn't required
*/
// 翻译一段信息为指定的语言文件下的内容
public function translate($category, $message, $language)
{
if ($this->forceTranslation || $language !== $this->sourceLanguage) { return $this->translateMessage($category, $message, $language);
} else {
return false;
}
}
$this->translateMessage($category, $message, $language);
/**
* Translates the specified message.
* If the message is not found, a [[EVENT_MISSING_TRANSLATION|missingTranslation]] event will be triggered.
* If there is an event handler, it may provide a [[MissingTranslationEvent::$translatedMessage|fallback translation]].
* If no fallback translation is provided this method will return `false`.
* @param string $category the category that the message belongs to.
* @param string $message the message to be translated.
* @param string $language the target language.
* @return string|boolean the translated message or false if translation wasn't found.
*/
protected function translateMessage($category, $message, $language)
{
$key = $language . '/' . $category;
if (!isset($this->_messages[$key])) {
// $language = 'zh-CN' $category = 'app'
// $this->loadMessages($category, $language) 为合并后的指定类别语言的翻译数组 key => value
$this->_messages[$key] = $this->loadMessages($category, $language);
}
if (isset($this->_messages[$key][$message]) && $this->_messages[$key][$message] !== '') {
return $this->_messages[$key][$message];
} elseif ($this->hasEventHandlers(self::EVENT_MISSING_TRANSLATION)) {
$event = new MissingTranslationEvent([
'category' => $category,
'message' => $message,
'language' => $language,
]);
$this->trigger(self::EVENT_MISSING_TRANSLATION, $event);
if ($event->translatedMessage !== null) {
return $this->_messages[$key][$message] = $event->translatedMessage;
}
} return $this->_messages[$key][$message] = false;
}
根据配置文件生成的 MessageSource子类相应对象的loadMessages方法,生成翻译的文件数组内容,在根据内容查找相应的以$message为键的对应值:
return $this->_messages[$key][$message];
本例根据PhpMessageSource对象的translateMessage方法为例说明:
/**
* Loads the message translation for the specified $language and $category.
* If translation for specific locale code such as `en-US` isn't found it
* tries more generic `en`. When both are present, the `en-US` messages will be merged
* over `en`. See [[loadFallbackMessages]] for details.
* If the $language is less specific than [[sourceLanguage]], the method will try to
* load the messages for [[sourceLanguage]]. For example: [[sourceLanguage]] is `en-GB`,
* $language is `en`. The method will load the messages for `en` and merge them over `en-GB`.
*
* @param string $category the message category
* @param string $language the target language
* @return array the loaded messages. The keys are original messages, and the values are the translated messages.
* @see loadFallbackMessages
* @see sourceLanguage
*/
protected function loadMessages($category, $language)
{
//返回指定类别和语言的文件路径
$messageFile = $this->getMessageFilePath($category, $language);
// 根据文件路径,加载翻译文件,为数组键值对
$messages = $this->loadMessagesFromFile($messageFile); $fallbackLanguage = substr($language, 0, 2);
$fallbackSourceLanguage = substr($this->sourceLanguage, 0, 2); if ($language !== $fallbackLanguage) {
// $language = 'zh-CN' $fallbackLanguage = 'zh' 合并语言zh-CN和zh文件为新的$messages
$messages = $this->loadFallbackMessages($category, $fallbackLanguage, $messages, $messageFile);
} elseif ($language === $fallbackSourceLanguage) {
// $language = 'zh' $fallbackLanguage = 'zh' $this->sourceLanguage = 'en' 合并zh 文件和en 文件,当zh文件翻译key的value信息没有时用 en 文件的相应的value 替代,合并为新的翻译数组内容 $messages
$messages = $this->loadFallbackMessages($category, $this->sourceLanguage, $messages, $messageFile);
} else {
if ($messages === null) {
Yii::error("The message file for category '$category' does not exist: $messageFile", __METHOD__);
}
} return (array) $messages;
}
//返回指定类别和语言的文件路径
$messageFile = $this->getMessageFilePath($category, $language);
/**
* Returns message file path for the specified language and category.
*
* @param string $category the message category
* @param string $language the target language
* @return string path to message file
*/
//返回指定的语言和类别文件路径
protected function getMessageFilePath($category, $language)
{
//语言类别文件路径
$messageFile = Yii::getAlias($this->basePath) . "/$language/";
if (isset($this->fileMap[$category])) {
$messageFile .= $this->fileMap[$category];
} else {
$messageFile .= str_replace('\\', '/', $category) . '.php';
} return $messageFile;
}
// 根据文件路径,加载翻译文件,为数组键值对
$messages = $this->loadMessagesFromFile($messageFile);
/**
* Loads the message translation for the specified language and category or returns null if file doesn't exist.
*
* @param string $messageFile path to message file
* @return array|null array of messages or null if file not found
*/
//加载翻译文件,翻译文件为数组文件
protected function loadMessagesFromFile($messageFile)
{
if (is_file($messageFile)) {
$messages = include($messageFile);
if (!is_array($messages)) {
$messages = [];
} return $messages;
} else {
return null;
}
}
//根据不同的条件,从其他文件中补充语言文件的缺少的key 的值value
$messages = $this->loadFallbackMessages($category, $this->sourceLanguage, $messages, $messageFile);
/**
* The method is normally called by [[loadMessages]] to load the fallback messages for the language.
* Method tries to load the $category messages for the $fallbackLanguage and adds them to the $messages array.
*
* @param string $category the message category
* @param string $fallbackLanguage the target fallback language
* @param array $messages the array of previously loaded translation messages.
* The keys are original messages, and the values are the translated messages.
* @param string $originalMessageFile the path to the file with messages. Used to log an error message
* in case when no translations were found.
* @return array the loaded messages. The keys are original messages, and the values are the translated messages.
* @since 2.0.7
*/
protected function loadFallbackMessages($category, $fallbackLanguage, $messages, $originalMessageFile)
{
// 返回的信息文件路径
$fallbackMessageFile = $this->getMessageFilePath($category, $fallbackLanguage);
//根据文件路径信息,加载文件的内容
$fallbackMessages = $this->loadMessagesFromFile($fallbackMessageFile); if (
$messages === null && $fallbackMessages === null
&& $fallbackLanguage !== $this->sourceLanguage
&& $fallbackLanguage !== substr($this->sourceLanguage, 0, 2)
) {
Yii::error("The message file for category '$category' does not exist: $originalMessageFile "
. "Fallback file does not exist as well: $fallbackMessageFile", __METHOD__);
} elseif (empty($messages)) {
return $fallbackMessages;
} elseif (!empty($fallbackMessages)) {
// 当$message数组key 值为空时,且$fallbackMessages对应的key的翻译内容存在是,把$fallbackMessages的内容翻译数组赋值给 $messages[$key]
foreach ($fallbackMessages as $key => $value) {
if (!empty($value) && empty($messages[$key])) {
$messages[$key] = $fallbackMessages[$key];
}
}
} return (array) $messages;
}
最后返回$messages:
return (array) $messages; 根据提供的参数($message)把$message作为key 查找 $messages 数组中对应的key的值