/lib/vendor/symfony/lib/i18n/sfMessageSource.class.php
PHP | 330 lines | 118 code | 33 blank | 179 comment | 13 complexity | c1dd44bff9c8eb1144ac7d081938ea89 MD5 | raw file
1<?php
2
3/**
4 * sfMessageSource class file.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the BSD License.
8 *
9 * Copyright(c) 2004 by Qiang Xue. All rights reserved.
10 *
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/}
14 *
15 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
16 * @version $Id: sfMessageSource.class.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
17 * @package symfony
18 * @subpackage i18n
19 */
20
21/**
22 * Abstract sfMessageSource class.
23 *
24 * The base class for all sfMessageSources. Message sources must be instantiated
25 * using the factory method. The default valid sources are
26 *
27 * # XLIFF -- using XML XLIFF format to store the translation messages.
28 * # SQLite -- Store the translation messages in a SQLite database.
29 * # MySQL -- Using a MySQL database to store the messages.
30 * # gettext -- Translated messages are stored in the gettext format.
31 *
32 * A custom message source can be instantiated by specifying the filename
33 * parameter to point to the custom class file. E.g.
34 * <code>
35 * $resource = '...'; //custom message source resource
36 * $classfile = '../sfMessageSource_MySource.php'; //custom message source
37 * $source = sfMessageSource::factory('MySource', $resource, $classfile);
38 * </code>
39 *
40 * If you are writting your own message sources, pay attention to the
41 * loadCatalogue method. It details how the resources are loaded and cached.
42 * See also the existing message source types as examples.
43 *
44 * The following example instantiates a MySQL message source, set the culture,
45 * set the cache handler, and use the source in a message formatter.
46 * The messages are store in a database named "messages". The source parameter
47 * for the actory method is a PEAR DB style DSN.
48 * <code>
49 * $dsn = 'mysql://username:password@localhost/messages';
50 * $source = sfMessageSource::factory('MySQL', $dsn);
51 *
52 * //set the culture and cache, store the cache in the /tmp directory.
53 * $source->setCulture('en_AU')l
54 * $source->setCache(new sfMessageCache(new sfFileCache(array('/tmp'))));
55 *
56 * $formatter = new sfMessageFormat($source);
57 * </code>
58 *
59 * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
60 * @version v1.0, last update on Fri Dec 24 19:55:49 EST 2004
61 * @package symfony
62 * @subpackage i18n
63 */
64abstract class sfMessageSource implements sfIMessageSource
65{
66 /**
67 * The culture name for this message source.
68 * @var string
69 */
70 protected $culture;
71
72 /**
73 * Array of translation messages.
74 * @var array
75 */
76 protected $messages = array();
77
78 /**
79 * The source of message translations.
80 * @var string
81 */
82 protected $source;
83
84 /**
85 * The translation cache.
86 * @var sfMessageCache
87 */
88 protected $cache;
89
90 protected $untranslated = array();
91
92 /**
93 * Private constructor. sfMessageSource must be initialized using
94 * the factory method.
95 */
96 private function __construct()
97 {
98 //throw new sfException('Please use the factory method to instantiate.');
99 }
100
101 /**
102 * Factory method to instantiate a new sfMessageSource depending on the
103 * source type. The built-in source types are 'XLIFF', 'SQLite',
104 * 'MySQL', 'gettext', and 'Aggregate'.
105 * The source parameter is dependent on the source type.
106 * For 'gettext' and 'XLIFF', it should point to the directory
107 * where the messages are stored. For database types, e.g. 'SQLite' and
108 * 'MySQL', it should be a PEAR DB style DSN string.
109 *
110 * Custom message source are possible by supplying the a filename parameter
111 * in the factory method.
112 *
113 * @param string $type the message source type.
114 * @param string $source the location of the resource.
115 * @param string $filename the filename of the custom message source.
116 * @return sfMessageSource a new message source of the specified type.
117 * @throws sfException
118 */
119 static function factory($type, $source = '.', $filename = '')
120 {
121 if ($filename)
122 {
123 if (!is_file($filename))
124 {
125 throw new sfException(sprintf("File %s not found.", $filename));
126 }
127
128 include_once($filename);
129 }
130
131 $class = 'sfMessageSource_'.$type;
132 if (!class_exists($class))
133 {
134 throw new sfException(sprintf('Unable to find type "%s".', $type));
135 }
136
137 return new $class($source);
138 }
139
140 /**
141 * Loads a particular message catalogue. Use read() to
142 * to get the array of messages. The catalogue loading sequence
143 * is as follows:
144 *
145 * # [1] Call getCatalogueList($catalogue) to get a list of variants for for the specified $catalogue.
146 * # [2] For each of the variants, call getSource($variant) to get the resource, could be a file or catalogue ID.
147 * # [3] Verify that this resource is valid by calling isValidSource($source)
148 * # [4] Try to get the messages from the cache
149 * # [5] If a cache miss, call load($source) to load the message array
150 * # [6] Store the messages to cache.
151 * # [7] Continue with the foreach loop, e.g. goto [2].
152 *
153 * @param string $catalogue a catalogue to load
154 * @return boolean always true
155 * @see read()
156 */
157 function load($catalogue = 'messages')
158 {
159 $variants = $this->getCatalogueList($catalogue);
160
161 $this->messages = array();
162
163 foreach ($variants as $variant)
164 {
165 $source = $this->getSource($variant);
166
167 if ($this->isValidSource($source) == false)
168 {
169 continue;
170 }
171
172 $loadData = true;
173
174 if ($this->cache)
175 {
176 $lastModified = $this->getLastModified($source);
177 if ($lastModified >= 0 && $lastModified < $this->cache->getLastModified($variant.':'.$this->culture))
178 {
179 $data = unserialize($this->cache->get($variant.':'.$this->culture));
180
181 if (is_array($data))
182 {
183 $this->messages[$variant] = $data;
184 $loadData = false;
185 }
186
187 unset($data);
188 }
189 }
190
191 if ($loadData)
192 {
193 $data = &$this->loadData($source);
194 if (is_array($data))
195 {
196 $this->messages[$variant] = $data;
197 if ($this->cache)
198 {
199 $this->cache->set($variant.':'.$this->culture, serialize($data));
200 }
201 }
202
203 unset($data);
204 }
205 }
206
207 return true;
208 }
209
210 /**
211 * Gets the array of messages.
212 *
213 * @return array translation messages.
214 */
215 public function read()
216 {
217 return $this->messages;
218 }
219
220 /**
221 * Gets the cache handler for this source.
222 *
223 * @return sfMessageCache cache handler
224 */
225 public function getCache()
226 {
227 return $this->cache;
228 }
229
230 /**
231 * Sets the cache handler for caching the messages.
232 *
233 * @param sfCache $cache the cache handler.
234 */
235 public function setCache(sfCache $cache)
236 {
237 $this->cache = $cache;
238 }
239
240 /**
241 * Adds a untranslated message to the source. Need to call save()
242 * to save the messages to source.
243 *
244 * @param string $message message to add
245 */
246 public function append($message)
247 {
248 if (!in_array($message, $this->untranslated))
249 {
250 $this->untranslated[] = $message;
251 }
252 }
253
254 /**
255 * Sets the culture for this message source.
256 *
257 * @param string $culture culture name
258 */
259 public function setCulture($culture)
260 {
261 $this->culture = $culture;
262 }
263
264 /**
265 * Gets the culture identifier for the source.
266 *
267 * @return string culture identifier.
268 */
269 public function getCulture()
270 {
271 return $this->culture;
272 }
273
274 /**
275 * Gets the last modified unix-time for this particular catalogue+variant.
276 *
277 * @param string $source catalogue+variant
278 * @return int last modified in unix-time format.
279 */
280 protected function getLastModified($source)
281 {
282 return 0;
283 }
284
285 /**
286 * Loads the message for a particular catalogue+variant.
287 * This methods needs to implemented by subclasses.
288 *
289 * @param string $variant catalogue+variant.
290 * @return array of translation messages.
291 */
292 public function &loadData($variant)
293 {
294 return array();
295 }
296
297 /**
298 * Gets the source, this could be a filename or database ID.
299 *
300 * @param string $variant catalogue+variant
301 * @return string the resource key
302 */
303 public function getSource($variant)
304 {
305 return $variant;
306 }
307
308 /**
309 * Determines if the source is valid.
310 *
311 * @param string $source catalogue+variant
312 * @return boolean true if valid, false otherwise.
313 */
314 public function isValidSource($source)
315 {
316 return false;
317 }
318
319 /**
320 * Gets all the variants of a particular catalogue.
321 * This method must be implemented by subclasses.
322 *
323 * @param string $catalogue catalogue name
324 * @return array list of all variants for this catalogue.
325 */
326 public function getCatalogueList($catalogue)
327 {
328 return array();
329 }
330}