4 * MessageSource class file.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the BSD License.
9 * Copyright(c) 2004 by Qiang Xue. All rights reserved.
11 * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
12 * The latest version of PRADO can be obtained from:
13 * {@link http://prado.sourceforge.net/}
15 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
16 * @version $Revision: 1.4 $ $Date: 2005/12/17 06:11:28 $
17 * @package System.I18N.core
21 * Get the IMessageSource interface.
23 require_once(dirname(__FILE__).'/IMessageSource.php');
26 * Get the MessageCache class file.
28 require_once(dirname(__FILE__).'/MessageCache.php');
31 * Abstract MessageSource class.
33 * The base class for all MessageSources. Message sources must be instantiated
34 * using the factory method. The default valid sources are
36 * # XLIFF -- using XML XLIFF format to store the translation messages.
37 * # gettext -- Translated messages are stored in the gettext format.
38 * # Database -- Use an existing TDbConnection to store the messages.
39 * # SQLite -- (Deprecated) Store the translation messages in a SQLite database.
41 * A custom message source can be instantiated by specifying the filename
42 * parameter to point to the custom class file. E.g.
44 * $resource = '...'; //custom message source resource
45 * $classfile = '../MessageSource_MySource.php'; //custom message source
46 * $source = MessageSource::factory('MySource', $resource, $classfile);
49 * If you are writting your own message sources, pay attention to the
50 * loadCatalogue method. It details how the resources are loaded and cached.
51 * See also the existing message source types as examples.
53 * The following example instantiates a Database message source, set the culture,
54 * set the cache handler, and use the source in a message formatter.
55 * The messages are stored using an existing connection. The source parameter
56 * for the factory method must contain a valid ConnectionID.
58 * // db1 must be already configured
59 * $source = MessageSource::factory('Database', 'db1');
61 * //set the culture and cache, store the cache in the /tmp directory.
62 * $source->setCulture('en_AU')l
63 * $source->setCache(new MessageCache('/tmp'));
65 * $formatter = new MessageFormat($source);
68 * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
69 * @version v1.0, last update on Fri Dec 24 19:55:49 EST 2004
70 * @package System.I18N.core
72 abstract class MessageSource implements IMessageSource
75 * The culture name for this message source.
81 * Array of translation messages.
84 protected $messages = array();
87 * The source of message translations.
93 * The translation cache.
98 protected $untranslated = array();
101 * Private constructor. MessageSource must be initialized using
102 * the factory method.
104 private function __construct()
106 //throw new Exception('Please use the factory method to instantiate.');
110 * Factory method to instantiate a new MessageSource depending on the
111 * source type. The allowed source types are 'XLIFF', 'gettext' and
112 * 'Database'. The source parameter depends on the source type.
113 * For 'gettext' and 'XLIFF', 'source' should point to the directory
114 * where the messages are stored.
115 * For 'Database', 'source' must be a valid connection id.
116 * If a deprecated 'SQLite' type is used, 'source' must contain
119 * Custom message source are possible by supplying the a filename parameter
120 * in the factory method.
122 * @param string the message source type.
123 * @param string the location of the resource or the ConnectionID.
124 * @param string the filename of the custom message source.
125 * @return MessageSource a new message source of the specified type.
126 * @throws InvalidMessageSourceTypeException
128 static function &factory($type, $source='.', $filename='')
130 $types = array('XLIFF','gettext','Database','SQLite');
132 if(empty($filename) && !in_array($type, $types))
133 throw new Exception('Invalid type "'.$type.'", valid types are '.
134 implode(', ', $types));
136 $class = 'MessageSource_'.$type;
139 $filename = dirname(__FILE__).'/'.$class.'.php';
141 if(is_file($filename) == false)
142 throw new Exception("File $filename not found");
144 include_once $filename;
146 $obj = new $class($source);
152 * Load a particular message catalogue. Use read() to
153 * to get the array of messages. The catalogue loading sequence
156 * # [1] call getCatalogeList($catalogue) to get a list of
157 * variants for for the specified $catalogue.
158 * # [2] for each of the variants, call getSource($variant)
159 * to get the resource, could be a file or catalogue ID.
160 * # [3] verify that this resource is valid by calling isValidSource($source)
161 * # [4] try to get the messages from the cache
162 * # [5] if a cache miss, call load($source) to load the message array
163 * # [6] store the messages to cache.
164 * # [7] continue with the foreach loop, e.g. goto [2].
166 * @param string a catalogue to load
167 * @return boolean true if loaded, false otherwise.
170 function load($catalogue='messages')
172 $variants = $this->getCatalogueList($catalogue);
174 $this->messages = array();
176 foreach($variants as $variant)
178 $source = $this->getSource($variant);
180 if($this->isValidSource($source) == false) continue;
186 $data = $this->cache->get($variant,
187 $this->culture, $this->getLastModified($source));
191 $this->messages[$variant] = $data;
198 $data = &$this->loadData($source);
201 $this->messages[$variant] = $data;
203 $this->cache->save($data, $variant, $this->culture);
213 * Get the array of messages.
215 * @return array translation messages.
217 public function read()
219 return $this->messages;
223 * Get the cache handler for this source.
224 * @return MessageCache cache handler
226 public function getCache()
232 * Set the cache handler for caching the messages.
233 * @param MessageCache the cache handler.
235 public function setCache(MessageCache $cache)
237 $this->cache = $cache;
241 * Add a untranslated message to the source. Need to call save()
242 * to save the messages to source.
243 * @param string message to add
245 public function append($message)
247 if(!in_array($message, $this->untranslated))
248 $this->untranslated[] = $message;
252 * Set the culture for this message source.
253 * @param string culture name
255 public function setCulture($culture)
257 $this->culture = $culture;
261 * Get the culture identifier for the source.
262 * @return string culture identifier.
264 public function getCulture()
266 return $this->culture;
270 * Get the last modified unix-time for this particular catalogue+variant.
271 * @param string catalogue+variant
272 * @return int last modified in unix-time format.
274 protected function getLastModified($source)
280 * Load the message for a particular catalogue+variant.
281 * This methods needs to implemented by subclasses.
282 * @param string catalogue+variant.
283 * @return array of translation messages.
285 protected function &loadData($variant)
291 * Get the source, this could be a filename or database ID.
292 * @param string catalogue+variant
293 * @return string the resource key
295 protected function getSource($variant)
301 * Determine if the source is valid.
302 * @param string catalogue+variant
303 * @return boolean true if valid, false otherwise.
305 protected function isValidSource($source)
311 * Get all the variants of a particular catalogue.
312 * This method must be implemented by subclasses.
313 * @param string catalogue name
314 * @return array list of all variants for this catalogue.
316 protected function getCatalogueList($catalogue)
324 * TMessageSourceIOException thrown when unable to modify message source
327 * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
328 * @version $Revision: 1.4 $ $Date: 2005/12/17 06:11:28 ${DATE} ${TIME} $
329 * @package System.I18N.core
331 class TMessageSourceIOException extends TException