1: <?php
2: /**
3: * CPhpMessageSource class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CPhpMessageSource represents a message source that stores translated messages in PHP scripts.
13: *
14: * CPhpMessageSource uses PHP files and arrays to keep message translations.
15: * <ul>
16: * <li>All translations are saved under the {@link basePath} directory.</li>
17: * <li>Translations in one language are kept as PHP files under an individual subdirectory
18: * whose name is the same as the language ID. Each PHP file contains messages
19: * belonging to the same category, and the file name is the same as the category name.</li>
20: * <li>Within a PHP file, an array of (source, translation) pairs is returned.
21: * For example:
22: * <pre>
23: * return array(
24: * 'original message 1' => 'translated message 1',
25: * 'original message 2' => 'translated message 2',
26: * );
27: * </pre>
28: * </li>
29: * </ul>
30: * When {@link cachingDuration} is set as a positive number, message translations will be cached.
31: *
32: * Messages for an extension class (e.g. a widget, a module) can be specially managed and used.
33: * In particular, if a message belongs to an extension whose class name is Xyz, then the message category
34: * can be specified in the format of 'Xyz.categoryName'. And the corresponding message file
35: * is assumed to be 'BasePath/messages/LanguageID/categoryName.php', where 'BasePath' refers to
36: * the directory that contains the extension class file. When using Yii::t() to translate an extension message,
37: * the category name should be set as 'Xyz.categoryName'.
38: *
39: * @author Qiang Xue <qiang.xue@gmail.com>
40: * @package system.i18n
41: * @since 1.0
42: */
43: class CPhpMessageSource extends CMessageSource
44: {
45: const CACHE_KEY_PREFIX='Yii.CPhpMessageSource.';
46:
47: /**
48: * @var integer the time in seconds that the messages can remain valid in cache.
49: * Defaults to 0, meaning the caching is disabled.
50: */
51: public $cachingDuration=0;
52: /**
53: * @var string the ID of the cache application component that is used to cache the messages.
54: * Defaults to 'cache' which refers to the primary cache application component.
55: * Set this property to false if you want to disable caching the messages.
56: */
57: public $cacheID='cache';
58: /**
59: * @var string the base path for all translated messages. Defaults to null, meaning
60: * the "messages" subdirectory of the application directory (e.g. "protected/messages").
61: */
62: public $basePath;
63: /**
64: * @var array the message paths for extensions that do not have a base class to use as category prefix.
65: * The format of the array should be:
66: * <pre>
67: * array(
68: * 'ExtensionName' => 'ext.ExtensionName.messages',
69: * )
70: * </pre>
71: * Where the key is the name of the extension and the value is the alias to the path
72: * of the "messages" subdirectory of the extension.
73: * When using Yii::t() to translate an extension message, the category name should be
74: * set as 'ExtensionName.categoryName'.
75: * Defaults to an empty array, meaning no extensions registered.
76: * @since 1.1.13
77: */
78: public $extensionPaths=array();
79:
80: private $_files=array();
81:
82: /**
83: * Initializes the application component.
84: * This method overrides the parent implementation by preprocessing
85: * the user request data.
86: */
87: public function init()
88: {
89: parent::init();
90: if($this->basePath===null)
91: $this->basePath=Yii::getPathOfAlias('application.messages');
92: }
93:
94: /**
95: * Determines the message file name based on the given category and language.
96: * If the category name contains a dot, it will be split into the module class name and the category name.
97: * In this case, the message file will be assumed to be located within the 'messages' subdirectory of
98: * the directory containing the module class file.
99: * Otherwise, the message file is assumed to be under the {@link basePath}.
100: * @param string $category category name
101: * @param string $language language ID
102: * @return string the message file path
103: */
104: protected function getMessageFile($category,$language)
105: {
106: if(!isset($this->_files[$category][$language]))
107: {
108: if(($pos=strpos($category,'.'))!==false)
109: {
110: $extensionClass=substr($category,0,$pos);
111: $extensionCategory=substr($category,$pos+1);
112: // First check if there's an extension registered for this class.
113: if(isset($this->extensionPaths[$extensionClass]))
114: $this->_files[$category][$language]=Yii::getPathOfAlias($this->extensionPaths[$extensionClass]).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$extensionCategory.'.php';
115: else
116: {
117: // No extension registered, need to find it.
118: $class=new ReflectionClass($extensionClass);
119: $this->_files[$category][$language]=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'messages'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$extensionCategory.'.php';
120: }
121: }
122: else
123: $this->_files[$category][$language]=$this->basePath.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$category.'.php';
124: }
125: return $this->_files[$category][$language];
126: }
127:
128: /**
129: * Loads the message translation for the specified language and category.
130: * @param string $category the message category
131: * @param string $language the target language
132: * @return array the loaded messages
133: */
134: protected function loadMessages($category,$language)
135: {
136: $messageFile=$this->getMessageFile($category,$language);
137:
138: if($this->cachingDuration>0 && $this->cacheID!==false && ($cache=Yii::app()->getComponent($this->cacheID))!==null)
139: {
140: $key=self::CACHE_KEY_PREFIX . $messageFile;
141: if(($data=$cache->get($key))!==false)
142: return unserialize($data);
143: }
144:
145: if(is_file($messageFile))
146: {
147: $messages=include($messageFile);
148: if(!is_array($messages))
149: $messages=array();
150: if(isset($cache))
151: {
152: $dependency=new CFileCacheDependency($messageFile);
153: $cache->set($key,serialize($messages),$this->cachingDuration,$dependency);
154: }
155: return $messages;
156: }
157: else
158: return array();
159: }
160: }