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的值