yii2 i18n学习

举例说明常见的翻译:Yii::t('app','Login');
追踪源码:BaseYii.php 文件 ,Yii::t($category, $message, $params = [], $language = null) 这个方法实际上是 \yii\i18n\I18N::translate()的一个捷径方法
 1  /**
 2      * Translates a message to the specified language.
 3      *
 4      * This is a shortcut method of [[\yii\i18n\I18N::translate()]].
 5      *
 6      * The translation will be conducted according to the message category and the target language will be used.
 7      *
 8      * You can add parameters to a translation message that will be substituted(取代) with the corresponding(相应的) value after
 9      * translation. The format for this is to use curly brackets around the parameter name as you can see in the following example:
10      *
11      * ```php
12      * $username = 'Alexander';
13      * echo \Yii::t('app', 'Hello, {username}!', ['username' => $username]);
14      * ```
15      *
16      * Further formatting of message parameters is supported using the [PHP intl extensions](http://www.php.net/manual/en/intro.intl.php)
17      * message formatter. See [[\yii\i18n\I18N::translate()]] for more details.
18      *
19      * @param string $category the message category.
20      * @param string $message the message to be translated.
21      * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
22      * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current
23      * [[\yii\base\Application::language|application language]] will be used.
24      * @return string the translated message.
25      */
26     public static function t($category, $message, $params = [], $language = null)
27     {
28         if (static::$app !== null) {
29             return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language);
30         } else {
31             $p = [];
32             foreach ((array) $params as $name => $value) {
33                 $p['{' . $name . '}'] = $value;
34             }
35 
36             return ($p === []) ? $message : strtr($message, $p);
37         }
38     }

查看 \yii\i18n\I18N::translate()方法:

 1 /**
 2      * Translates a message to the specified language.
 3      *
 4      * After translation the message will be formatted using [[MessageFormatter]] if it contains
 5      * ICU message format and `$params` are not empty.
 6      *
 7      * @param string $category the message category.
 8      * @param string $message the message to be translated.
 9      * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
10      * @param string $language the language code (e.g. `en-US`, `en`).
11      * @return string the translated and formatted message.
12      */
13     public function translate($category, $message, $params, $language)
14     {
15         // 返回MessageSource the message source for the given category.
16         $messageSource = $this->getMessageSource($category);
17         //返回翻译的内容
18         $translation = $messageSource->translate($category, $message, $language);
19         //格式话翻译的内容
20         if ($translation === false) {
21             return $this->format($message, $params, $messageSource->sourceLanguage);
22         } else {
23             return $this->format($translation, $params, $language);
24         }
25     }

其中 $messageSource = $this->getMessageSource($category);//根据配置文件内容和 给的参数$category 返回继承MessageSource 相应子类的实例对象, 本例根据配置文件返回PhpMessageSource对象

 1 <?php
 2 return [
 3     'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
 4     'components' => [
 5         'cache' => [
 6             'class' => 'yii\caching\FileCache',
 7         ],
 8         'i18n'=>[
 9             'translations' => [
10                 'app*'=> [
11                     'class' => 'yii\i18n\PhpMessageSource',
12                     'basePath'=>'@common/messages',
13                     'fileMap'=>[
14                         'app'=>'app.php',
15                     ],
16                 ],
17             ],
18         ],
19     ],
20 ];

 $messageSource = $this->getMessageSource($category); 返回继承MessageSource 相应子类的实例对象

 1  /**
 2      * Returns the message source for the given category.
 3      * @param string $category the category name.
 4      * @return MessageSource the message source for the given category.
 5      * @throws InvalidConfigException if there is no message source available for the specified category.
 6      */
 7     //根据配置文件内容和 给的参数$category 返回继承MessageSource 相应子类的实例对象, 本例根据配置文件返回PhpMessageSource对象
 8     public function getMessageSource($category)
 9     {
10         if (isset($this->translations[$category])) {
11             $source = $this->translations[$category];
12             if ($source instanceof MessageSource) {
13                 return $source;
14             } else {
15                 return $this->translations[$category] = Yii::createObject($source);
16             }
17         } else {
18             // try wildcard matching
19             foreach ($this->translations as $pattern => $source) {
20                 if (strpos($pattern, '*') > 0 && strpos($category, rtrim($pattern, '*')) === 0) {
21                     if ($source instanceof MessageSource) {
22                         return $source;
23                     } else {
24                         return $this->translations[$category] = $this->translations[$pattern] = Yii::createObject($source);
25                     }
26                 }
27             }
28             // match '*' in the last
29             if (isset($this->translations['*'])) {
30                 $source = $this->translations['*'];
31                 if ($source instanceof MessageSource) {
32                     return $source;
33                 } else {
34                     return $this->translations[$category] = $this->translations['*'] = Yii::createObject($source);
35                 }
36             }
37         }
38 
39         throw new InvalidConfigException("Unable to locate message source for category '$category'.");
40     }

再根据实例对象的translate方法返回翻译的内容,  $translation = $messageSource->translate($category, $message, $language);

 MessageSource  类的 translate方法如下:

 1   /**
 2      * Translates a message to the specified language.
 3      *
 4      * Note that unless [[forceTranslation]] is true, if the target language
 5      * is the same as the [[sourceLanguage|source language]], the message
 6      * will NOT be translated.
 7      *
 8      * If a translation is not found, a [[EVENT_MISSING_TRANSLATION|missingTranslation]] event will be triggered.
 9      *
10      * @param string $category the message category
11      * @param string $message the message to be translated
12      * @param string $language the target language
13      * @return string|boolean the translated message or false if translation wasn't found or isn't required
14      */
15     // 翻译一段信息为指定的语言文件下的内容
16     public function translate($category, $message, $language)
17     {
18         if ($this->forceTranslation || $language !== $this->sourceLanguage) {
19            
20             return $this->translateMessage($category, $message, $language);
21         } else {
22             return false;
23         }
24     }

$this->translateMessage($category, $message, $language);
 1  /**
 2      * Translates the specified message.
 3      * If the message is not found, a [[EVENT_MISSING_TRANSLATION|missingTranslation]] event will be triggered.
 4      * If there is an event handler, it may provide a [[MissingTranslationEvent::$translatedMessage|fallback translation]].
 5      * If no fallback translation is provided this method will return `false`.
 6      * @param string $category the category that the message belongs to.
 7      * @param string $message the message to be translated.
 8      * @param string $language the target language.
 9      * @return string|boolean the translated message or false if translation wasn't found.
10      */
11     protected function translateMessage($category, $message, $language)
12     {
13         $key = $language . '/' . $category;
14         if (!isset($this->_messages[$key])) {
15             // $language = 'zh-CN'  $category = 'app'
16             // $this->loadMessages($category, $language) 为合并后的指定类别语言的翻译数组 key => value
17             $this->_messages[$key] = $this->loadMessages($category, $language);
18         }
19         if (isset($this->_messages[$key][$message]) && $this->_messages[$key][$message] !== '') {
20             return $this->_messages[$key][$message];
21         } elseif ($this->hasEventHandlers(self::EVENT_MISSING_TRANSLATION)) {
22             $event = new MissingTranslationEvent([
23                 'category' => $category,
24                 'message' => $message,
25                 'language' => $language,
26             ]);
27             $this->trigger(self::EVENT_MISSING_TRANSLATION, $event);
28             if ($event->translatedMessage !== null) {
29                 return $this->_messages[$key][$message] = $event->translatedMessage;
30             }
31         }
32 
33         return $this->_messages[$key][$message] = false;
34     }

根据配置文件生成的 MessageSource子类相应对象的loadMessages方法,生成翻译的文件数组内容,在根据内容查找相应的以$message为键的对应值:
return $this->_messages[$key][$message];
本例根据PhpMessageSource对象的translateMessage方法为例说明:
 1   /**
 2      * Loads the message translation for the specified $language and $category.
 3      * If translation for specific locale code such as `en-US` isn't found it
 4      * tries more generic `en`. When both are present, the `en-US` messages will be merged
 5      * over `en`. See [[loadFallbackMessages]] for details.
 6      * If the $language is less specific than [[sourceLanguage]], the method will try to
 7      * load the messages for [[sourceLanguage]]. For example: [[sourceLanguage]] is `en-GB`,
 8      * $language is `en`. The method will load the messages for `en` and merge them over `en-GB`.
 9      *
10      * @param string $category the message category
11      * @param string $language the target language
12      * @return array the loaded messages. The keys are original messages, and the values are the translated messages.
13      * @see loadFallbackMessages
14      * @see sourceLanguage
15      */
16     protected function loadMessages($category, $language)
17     {
18         //返回指定类别和语言的文件路径
19         $messageFile = $this->getMessageFilePath($category, $language);
20         // 根据文件路径,加载翻译文件,为数组键值对
21         $messages = $this->loadMessagesFromFile($messageFile);
22 
23         $fallbackLanguage = substr($language, 0, 2);
24         $fallbackSourceLanguage = substr($this->sourceLanguage, 0, 2);
25 
26         if ($language !== $fallbackLanguage) {
27             // $language = 'zh-CN'    $fallbackLanguage = 'zh'  合并语言zh-CN和zh文件为新的$messages
28             $messages = $this->loadFallbackMessages($category, $fallbackLanguage, $messages, $messageFile);
29         } elseif ($language === $fallbackSourceLanguage) {
30             //  $language = 'zh'    $fallbackLanguage = 'zh' $this->sourceLanguage = 'en' 合并zh 文件和en 文件,当zh文件翻译key的value信息没有时用 en 文件的相应的value 替代,合并为新的翻译数组内容 $messages
31             $messages = $this->loadFallbackMessages($category, $this->sourceLanguage, $messages, $messageFile);
32         } else {
33             if ($messages === null) {
34                 Yii::error("The message file for category '$category' does not exist: $messageFile", __METHOD__);
35             }
36         }
37 
38         return (array) $messages;
39     }
 //返回指定类别和语言的文件路径
$messageFile = $this->getMessageFilePath($category, $language);
 1  /**
 2      * Returns message file path for the specified language and category.
 3      *
 4      * @param string $category the message category
 5      * @param string $language the target language
 6      * @return string path to message file
 7      */
 8     //返回指定的语言和类别文件路径
 9     protected function getMessageFilePath($category, $language)
10     {
11         //语言类别文件路径
12         $messageFile = Yii::getAlias($this->basePath) . "/$language/";
13         if (isset($this->fileMap[$category])) {
14             $messageFile .= $this->fileMap[$category];
15         } else {
16             $messageFile .= str_replace('\\', '/', $category) . '.php';
17         }
18 
19         return $messageFile;
20     }
// 根据文件路径,加载翻译文件,为数组键值对
$messages = $this->loadMessagesFromFile($messageFile);
 1  /**
 2      * Loads the message translation for the specified language and category or returns null if file doesn't exist.
 3      *
 4      * @param string $messageFile path to message file
 5      * @return array|null array of messages or null if file not found
 6      */
 7     //加载翻译文件,翻译文件为数组文件
 8     protected function loadMessagesFromFile($messageFile)
 9     {
10         if (is_file($messageFile)) {
11             $messages = include($messageFile);
12             if (!is_array($messages)) {
13                 $messages = [];
14             }
15 
16             return $messages;
17         } else {
18             return null;
19         }
20     }

//根据不同的条件,从其他文件中补充语言文件的缺少的key 的值value
$messages = $this->loadFallbackMessages($category, $this->sourceLanguage, $messages, $messageFile);
 1 /**
 2      * The method is normally called by [[loadMessages]] to load the fallback messages for the language.
 3      * Method tries to load the $category messages for the $fallbackLanguage and adds them to the $messages array.
 4      *
 5      * @param string $category the message category
 6      * @param string $fallbackLanguage the target fallback language
 7      * @param array $messages the array of previously loaded translation messages.
 8      * The keys are original messages, and the values are the translated messages.
 9      * @param string $originalMessageFile the path to the file with messages. Used to log an error message
10      * in case when no translations were found.
11      * @return array the loaded messages. The keys are original messages, and the values are the translated messages.
12      * @since 2.0.7
13      */
14     protected function loadFallbackMessages($category, $fallbackLanguage, $messages, $originalMessageFile)
15     {
16         // 返回的信息文件路径
17         $fallbackMessageFile = $this->getMessageFilePath($category, $fallbackLanguage);
18         //根据文件路径信息,加载文件的内容
19         $fallbackMessages = $this->loadMessagesFromFile($fallbackMessageFile);
20 
21         if (
22             $messages === null && $fallbackMessages === null
23             && $fallbackLanguage !== $this->sourceLanguage
24             && $fallbackLanguage !== substr($this->sourceLanguage, 0, 2)
25         ) {
26             Yii::error("The message file for category '$category' does not exist: $originalMessageFile "
27                 . "Fallback file does not exist as well: $fallbackMessageFile", __METHOD__);
28         } elseif (empty($messages)) {
29             return $fallbackMessages;
30         } elseif (!empty($fallbackMessages)) {
31             // 当$message数组key 值为空时,且$fallbackMessages对应的key的翻译内容存在是,把$fallbackMessages的内容翻译数组赋值给 $messages[$key]
32             foreach ($fallbackMessages as $key => $value) {
33                 if (!empty($value) && empty($messages[$key])) {
34                     $messages[$key] = $fallbackMessages[$key];
35                 }
36             }
37         }
38 
39         return (array) $messages;
40     }

 

最后返回$messages:
return (array) $messages;

根据提供的参数($message)把$message作为key 查找 $messages 数组中对应的key的值
posted @ 2017-01-08 18:56  哦先生  阅读(2243)  评论(0编辑  收藏  举报