1: <?php
  2: 
  3: /**
  4:  * This is a modified version of the default Yii class. The only change that has
  5:  * been made is the inclusion of "common.php" as a shared source of translation
  6:  * messages. Ctrl + F for "X2CHANGE" to find the exact location of this customization.
  7:  */
  8: class X2MessageSource extends CMessageSource {
  9: 
 10:     const CACHE_KEY_PREFIX = 'Yii.CPhpMessageSource.';
 11: 
 12:     /**
 13:      * @var integer the time in seconds that the messages can remain valid in cache.
 14:      * Defaults to 0, meaning the caching is disabled.
 15:      */
 16:     public $cachingDuration = 0;
 17: 
 18:     /**
 19:      * @var string the ID of the cache application component that is used to cache the messages.
 20:      * Defaults to 'cache' which refers to the primary cache application component.
 21:      * Set this property to false if you want to disable caching the messages.
 22:      */
 23:     public $cacheID = 'cache';
 24: 
 25:     /**
 26:      * @var string the base path for all translated messages. Defaults to null, meaning
 27:      * the "messages" subdirectory of the application directory (e.g. "protected/messages").
 28:      */
 29:     public $basePath;
 30: 
 31:     /**
 32:      * @var array the message paths for extensions that do not have a base class to use as category prefix.
 33:      * The format of the array should be:
 34:      * <pre>
 35:      * array(
 36:      *     'ExtensionName' => 'ext.ExtensionName.messages',
 37:      * )
 38:      * </pre>
 39:      * Where the key is the name of the extension and the value is the alias to the path
 40:      * of the "messages" subdirectory of the extension.
 41:      * When using Yii::t() to translate an extension message, the category name should be
 42:      * set as 'ExtensionName.categoryName'.
 43:      * Defaults to an empty array, meaning no extensions registered.
 44:      * @since 1.1.13
 45:      */
 46:     public $extensionPaths = array();
 47: 
 48:     /**
 49:      * @var boolean Whether or not to log a missing translation if the index is found
 50:      * in the messages file, but the translation message is blank. For example,
 51:      * 'X2Engine'=>'' would trigger an onMissingTranslation event if this parameter
 52:      * is set to true, but will not trigger if it is set to false.
 53:      */
 54:     public $logBlankMessages = true;
 55:     private $_files = array();
 56:     private $_messages = array();
 57: 
 58:     /**
 59:      * Initializes the application component.
 60:      * This method overrides the parent implementation by preprocessing
 61:      * the user request data.
 62:      */
 63:     public function init(){
 64:         parent::init();
 65:         if($this->basePath === null)
 66:             $this->basePath = Yii::getPathOfAlias('application.messages');
 67:         }
 68: 
 69:     /**
 70:      * Translates the specified message.
 71:      * If the message is not found, an {@link onMissingTranslation}
 72:      * event will be raised.
 73:      * @param string $category the category that the message belongs to
 74:      * @param string $message the message to be translated
 75:      * @param string $language the target language
 76:      * @return string the translated message
 77:      */
 78:     protected function translateMessage($category, $message, $language){
 79:         $key = $language.'.'.$category;
 80:         // X2CHANGE The customization occurs here, see comments below.
 81:         if(!isset($this->_messages[$key]))
 82:             $this->_messages[$key] = $this->loadMessages($category, $language); // Load the messages for the chosen language.
 83:         if(isset($this->_messages[$key][$message]) && $this->_messages[$key][$message] !== ''){
 84:             return $this->_messages[$key][$message];  // If we find the message in the translation files, return the translated version.
 85:         }elseif(!isset($this->_messages[$key][$message]) || $this->_messages[$key][$message] == ''){
 86:             if(!isset($this->_messages['common'])){ // Otherwise, lookup the common file to see if the translation is saved there.
 87:                 $this->_messages['common'] = $this->loadMessages('common', $language);
 88:             }
 89:             if(isset($this->_messages['common'][$message])){
 90:                 if($this->_messages['common'][$message] !== ''){
 91:                     return $this->_messages['common'][$message]; // If we find the message in common, return the translated version.
 92:                 }elseif($this->logBlankMessages && $this->hasEventHandler('onMissingTranslation')){
 93:                     $event = new CMissingTranslationEvent($this, $category, $message, $language);
 94:                     $this->onMissingTranslation($event); // If we find the index but not the message
 95:                     return $event->message; // and we're logging blank messages, log the translation issue.
 96:                 }else{
 97:                     return $message; // Otherwise return the starting text.
 98:                 }
 99:             }
100:             if(!Yii::app()->params->noSession && (!isset($this->_messages[$key][$message]) || ($this->_messages[$key][$message] == '' && $this->logBlankMessages)) && $this->hasEventHandler('onMissingTranslation')){
101:                 $event = new CMissingTranslationEvent($this, $category, $message, $language);
102:                 $this->onMissingTranslation($event);
103:                 return $event->message; // Same as above logging, but if we never found anything in common.
104:             }else{
105:                 return $message;
106:             }
107:         }else
108:             return $message;
109:     }
110: 
111:     /**
112:      * Determines the message file name based on the given category and language.
113:      * If the category name contains a dot, it will be split into the module class name and the category name.
114:      * In this case, the message file will be assumed to be located within the 'messages' subdirectory of
115:      * the directory containing the module class file.
116:      * Otherwise, the message file is assumed to be under the {@link basePath}.
117:      * @param string $category category name
118:      * @param string $language language ID
119:      * @return string the message file path
120:      */
121:     protected function getMessageFile($category, $language){
122:         if(!isset($this->_files[$category][$language])){
123:             if(($pos = strpos($category, '.')) !== false){
124:                 $extensionClass = substr($category, 0, $pos);
125:                 $extensionCategory = substr($category, $pos + 1);
126:                 // First check if there's an extension registered for this class.
127:                 if(isset($this->extensionPaths[$extensionClass]))
128:                     $this->_files[$category][$language] = Yii::getPathOfAlias($this->extensionPaths[$extensionClass]).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$extensionCategory.'.php';
129:                 else{
130:                     // No extension registered, need to find it.
131:                     $class = new ReflectionClass($extensionClass);
132:                     $this->_files[$category][$language] = dirname($class->getFileName()).DIRECTORY_SEPARATOR.'messages'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$extensionCategory.'.php';
133:                 }
134:             } else {
135:                 if(file_exists('custom'.DIRECTORY_SEPARATOR.'protected'.DIRECTORY_SEPARATOR.'messages'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$category.'.php')){
136:                     $this->_files[$category][$language] = 'custom'.DIRECTORY_SEPARATOR.'protected'.DIRECTORY_SEPARATOR.'messages'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$category.'.php';
137:                 }else{
138:                     $this->_files[$category][$language] = $this->basePath.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.$category.'.php';
139:                 }
140:             }
141:         }
142:         return $this->_files[$category][$language];
143:     }
144: 
145:     /**
146:      * Loads the message translation for the specified language and category.
147:      * @param string $category the message category
148:      * @param string $language the target language
149:      * @return array the loaded messages
150:      */
151:     protected function loadMessages($category, $language){
152:         $messageFile = $this->getMessageFile($category, $language);
153:         
154:         if($this->cachingDuration > 0 && $this->cacheID !== false && ($cache = Yii::app()->getComponent($this->cacheID)) !== null){
155:             $key = self::CACHE_KEY_PREFIX.$messageFile;
156:             if(($data = $cache->get($key)) !== false)
157:                 return unserialize($data);
158:         }
159: 
160:         if(is_file($messageFile)){
161:             $messages = include($messageFile);
162:             if(!is_array($messages))
163:                 $messages = array();
164:             if(isset($cache)){
165:                 $dependency = new CFileCacheDependency($messageFile);
166:                 $cache->set($key, serialize($messages), $this->cachingDuration, $dependency);
167:             }
168:             return $messages;
169:         }
170:         else
171:             return array();
172:     }
173: 
174: }
175: 
176: ?>
177: