|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Translate |
|
17 * @subpackage Zend_Translate_Adapter |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Adapter.php 22726 2010-07-30 10:52:07Z thomas $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * @see Zend_Locale |
|
25 */ |
|
26 require_once 'Zend/Locale.php'; |
|
27 |
|
28 /** |
|
29 * @see Zend_Translate_Plural |
|
30 */ |
|
31 require_once 'Zend/Translate/Plural.php'; |
|
32 |
|
33 /** |
|
34 * Basic adapter class for each translation source adapter |
|
35 * |
|
36 * @category Zend |
|
37 * @package Zend_Translate |
|
38 * @subpackage Zend_Translate_Adapter |
|
39 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
40 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
41 */ |
|
42 abstract class Zend_Translate_Adapter { |
|
43 /** |
|
44 * Shows if locale detection is in automatic level |
|
45 * @var boolean |
|
46 */ |
|
47 private $_automatic = true; |
|
48 |
|
49 /** |
|
50 * Internal value to see already routed languages |
|
51 * @var array() |
|
52 */ |
|
53 private $_routed = array(); |
|
54 |
|
55 /** |
|
56 * Internal cache for all adapters |
|
57 * @var Zend_Cache_Core |
|
58 */ |
|
59 protected static $_cache = null; |
|
60 |
|
61 /** |
|
62 * Internal value to remember if cache supports tags |
|
63 * |
|
64 * @var boolean |
|
65 */ |
|
66 private static $_cacheTags = false; |
|
67 |
|
68 /** |
|
69 * Scans for the locale within the name of the directory |
|
70 * @constant integer |
|
71 */ |
|
72 const LOCALE_DIRECTORY = 'directory'; |
|
73 |
|
74 /** |
|
75 * Scans for the locale within the name of the file |
|
76 * @constant integer |
|
77 */ |
|
78 const LOCALE_FILENAME = 'filename'; |
|
79 |
|
80 /** |
|
81 * Array with all options, each adapter can have own additional options |
|
82 * 'clear' => when true, clears already loaded translations when adding new files |
|
83 * 'content' => content to translate or file or directory with content |
|
84 * 'disableNotices' => when true, omits notices from being displayed |
|
85 * 'ignore' => a prefix for files and directories which are not being added |
|
86 * 'locale' => the actual set locale to use |
|
87 * 'log' => a instance of Zend_Log where logs are written to |
|
88 * 'logMessage' => message to be logged |
|
89 * 'logPriority' => priority which is used to write the log message |
|
90 * 'logUntranslated' => when true, untranslated messages are not logged |
|
91 * 'reload' => reloads the cache by reading the content again |
|
92 * 'scan' => searches for translation files using the LOCALE constants |
|
93 * 'tag' => tag to use for the cache |
|
94 * |
|
95 * @var array |
|
96 */ |
|
97 protected $_options = array( |
|
98 'clear' => false, |
|
99 'content' => null, |
|
100 'disableNotices' => false, |
|
101 'ignore' => '.', |
|
102 'locale' => 'auto', |
|
103 'log' => null, |
|
104 'logMessage' => "Untranslated message within '%locale%': %message%", |
|
105 'logPriority' => 5, |
|
106 'logUntranslated' => false, |
|
107 'reload' => false, |
|
108 'route' => null, |
|
109 'scan' => null, |
|
110 'tag' => 'Zend_Translate' |
|
111 ); |
|
112 |
|
113 /** |
|
114 * Translation table |
|
115 * @var array |
|
116 */ |
|
117 protected $_translate = array(); |
|
118 |
|
119 /** |
|
120 * Generates the adapter |
|
121 * |
|
122 * @param array|Zend_Config $options Translation options for this adapter |
|
123 * @throws Zend_Translate_Exception |
|
124 * @return void |
|
125 */ |
|
126 public function __construct($options = array()) |
|
127 { |
|
128 if ($options instanceof Zend_Config) { |
|
129 $options = $options->toArray(); |
|
130 } else if (func_num_args() > 1) { |
|
131 $args = func_get_args(); |
|
132 $options = array(); |
|
133 $options['content'] = array_shift($args); |
|
134 |
|
135 if (!empty($args)) { |
|
136 $options['locale'] = array_shift($args); |
|
137 } |
|
138 |
|
139 if (!empty($args)) { |
|
140 $opt = array_shift($args); |
|
141 $options = array_merge($opt, $options); |
|
142 } |
|
143 } else if (!is_array($options)) { |
|
144 $options = array('content' => $options); |
|
145 } |
|
146 |
|
147 if (array_key_exists('cache', $options)) { |
|
148 self::setCache($options['cache']); |
|
149 unset($options['cache']); |
|
150 } |
|
151 |
|
152 if (isset(self::$_cache)) { |
|
153 $id = 'Zend_Translate_' . $this->toString() . '_Options'; |
|
154 $result = self::$_cache->load($id); |
|
155 if ($result) { |
|
156 $this->_options = $result; |
|
157 } |
|
158 } |
|
159 |
|
160 if (empty($options['locale']) || ($options['locale'] === "auto")) { |
|
161 $this->_automatic = true; |
|
162 } else { |
|
163 $this->_automatic = false; |
|
164 } |
|
165 |
|
166 $locale = null; |
|
167 if (!empty($options['locale'])) { |
|
168 $locale = $options['locale']; |
|
169 unset($options['locale']); |
|
170 } |
|
171 |
|
172 $this->setOptions($options); |
|
173 $options['locale'] = $locale; |
|
174 |
|
175 if (!empty($options['content'])) { |
|
176 $this->addTranslation($options); |
|
177 } |
|
178 |
|
179 if ($this->getLocale() !== (string) $options['locale']) { |
|
180 $this->setLocale($options['locale']); |
|
181 } |
|
182 } |
|
183 |
|
184 /** |
|
185 * Add translations |
|
186 * |
|
187 * This may be a new language or additional content for an existing language |
|
188 * If the key 'clear' is true, then translations for the specified |
|
189 * language will be replaced and added otherwise |
|
190 * |
|
191 * @param array|Zend_Config $options Options and translations to be added |
|
192 * @throws Zend_Translate_Exception |
|
193 * @return Zend_Translate_Adapter Provides fluent interface |
|
194 */ |
|
195 public function addTranslation($options = array()) |
|
196 { |
|
197 if ($options instanceof Zend_Config) { |
|
198 $options = $options->toArray(); |
|
199 } else if (func_num_args() > 1) { |
|
200 $args = func_get_args(); |
|
201 $options = array(); |
|
202 $options['content'] = array_shift($args); |
|
203 |
|
204 if (!empty($args)) { |
|
205 $options['locale'] = array_shift($args); |
|
206 } |
|
207 |
|
208 if (!empty($args)) { |
|
209 $opt = array_shift($args); |
|
210 $options = array_merge($opt, $options); |
|
211 } |
|
212 } else if (!is_array($options)) { |
|
213 $options = array('content' => $options); |
|
214 } |
|
215 |
|
216 $originate = null; |
|
217 if (!empty($options['locale'])) { |
|
218 $originate = (string) $options['locale']; |
|
219 } |
|
220 |
|
221 if ((array_key_exists('log', $options)) && !($options['log'] instanceof Zend_Log)) { |
|
222 require_once 'Zend/Translate/Exception.php'; |
|
223 throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log'); |
|
224 } |
|
225 |
|
226 try { |
|
227 if (!($options['content'] instanceof Zend_Translate) && !($options['content'] instanceof Zend_Translate_Adapter)) { |
|
228 if (empty($options['locale'])) { |
|
229 $options['locale'] = null; |
|
230 } |
|
231 |
|
232 $options['locale'] = Zend_Locale::findLocale($options['locale']); |
|
233 } |
|
234 } catch (Zend_Locale_Exception $e) { |
|
235 require_once 'Zend/Translate/Exception.php'; |
|
236 throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e); |
|
237 } |
|
238 |
|
239 $options = $options + $this->_options; |
|
240 if (is_string($options['content']) and is_dir($options['content'])) { |
|
241 $options['content'] = realpath($options['content']); |
|
242 $prev = ''; |
|
243 foreach (new RecursiveIteratorIterator( |
|
244 new RecursiveDirectoryIterator($options['content'], RecursiveDirectoryIterator::KEY_AS_PATHNAME), |
|
245 RecursiveIteratorIterator::SELF_FIRST) as $directory => $info) { |
|
246 $file = $info->getFilename(); |
|
247 if (is_array($options['ignore'])) { |
|
248 foreach ($options['ignore'] as $key => $ignore) { |
|
249 if (strpos($key, 'regex') !== false) { |
|
250 if (preg_match($ignore, $directory)) { |
|
251 // ignore files matching the given regex from option 'ignore' and all files below |
|
252 continue 2; |
|
253 } |
|
254 } else if (strpos($directory, DIRECTORY_SEPARATOR . $ignore) !== false) { |
|
255 // ignore files matching first characters from option 'ignore' and all files below |
|
256 continue 2; |
|
257 } |
|
258 } |
|
259 } else { |
|
260 if (strpos($directory, DIRECTORY_SEPARATOR . $options['ignore']) !== false) { |
|
261 // ignore files matching first characters from option 'ignore' and all files below |
|
262 continue; |
|
263 } |
|
264 } |
|
265 |
|
266 if ($info->isDir()) { |
|
267 // pathname as locale |
|
268 if (($options['scan'] === self::LOCALE_DIRECTORY) and (Zend_Locale::isLocale($file, true, false))) { |
|
269 $options['locale'] = $file; |
|
270 $prev = (string) $options['locale']; |
|
271 } |
|
272 } else if ($info->isFile()) { |
|
273 // filename as locale |
|
274 if ($options['scan'] === self::LOCALE_FILENAME) { |
|
275 $filename = explode('.', $file); |
|
276 array_pop($filename); |
|
277 $filename = implode('.', $filename); |
|
278 if (Zend_Locale::isLocale((string) $filename, true, false)) { |
|
279 $options['locale'] = (string) $filename; |
|
280 } else { |
|
281 $parts = explode('.', $file); |
|
282 $parts2 = array(); |
|
283 foreach($parts as $token) { |
|
284 $parts2 += explode('_', $token); |
|
285 } |
|
286 $parts = array_merge($parts, $parts2); |
|
287 $parts2 = array(); |
|
288 foreach($parts as $token) { |
|
289 $parts2 += explode('-', $token); |
|
290 } |
|
291 $parts = array_merge($parts, $parts2); |
|
292 $parts = array_unique($parts); |
|
293 $prev = ''; |
|
294 foreach($parts as $token) { |
|
295 if (Zend_Locale::isLocale($token, true, false)) { |
|
296 if (strlen($prev) <= strlen($token)) { |
|
297 $options['locale'] = $token; |
|
298 $prev = $token; |
|
299 } |
|
300 } |
|
301 } |
|
302 } |
|
303 } |
|
304 |
|
305 try { |
|
306 $options['content'] = $info->getPathname(); |
|
307 $this->_addTranslationData($options); |
|
308 } catch (Zend_Translate_Exception $e) { |
|
309 // ignore failed sources while scanning |
|
310 } |
|
311 } |
|
312 } |
|
313 } else { |
|
314 $this->_addTranslationData($options); |
|
315 } |
|
316 |
|
317 if ((isset($this->_translate[$originate]) === true) and (count($this->_translate[$originate]) > 0)) { |
|
318 $this->setLocale($originate); |
|
319 } |
|
320 |
|
321 return $this; |
|
322 } |
|
323 |
|
324 /** |
|
325 * Sets new adapter options |
|
326 * |
|
327 * @param array $options Adapter options |
|
328 * @throws Zend_Translate_Exception |
|
329 * @return Zend_Translate_Adapter Provides fluent interface |
|
330 */ |
|
331 public function setOptions(array $options = array()) |
|
332 { |
|
333 $change = false; |
|
334 $locale = null; |
|
335 foreach ($options as $key => $option) { |
|
336 if ($key == 'locale') { |
|
337 $locale = $option; |
|
338 } else if ((isset($this->_options[$key]) and ($this->_options[$key] != $option)) or |
|
339 !isset($this->_options[$key])) { |
|
340 if (($key == 'log') && !($option instanceof Zend_Log)) { |
|
341 require_once 'Zend/Translate/Exception.php'; |
|
342 throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log'); |
|
343 } |
|
344 |
|
345 if ($key == 'cache') { |
|
346 self::setCache($option); |
|
347 continue; |
|
348 } |
|
349 |
|
350 $this->_options[$key] = $option; |
|
351 $change = true; |
|
352 } |
|
353 } |
|
354 |
|
355 if ($locale !== null) { |
|
356 $this->setLocale($locale); |
|
357 } |
|
358 |
|
359 if (isset(self::$_cache) and ($change == true)) { |
|
360 $id = 'Zend_Translate_' . $this->toString() . '_Options'; |
|
361 if (self::$_cacheTags) { |
|
362 self::$_cache->save($this->_options, $id, array($this->_options['tag'])); |
|
363 } else { |
|
364 self::$_cache->save($this->_options, $id); |
|
365 } |
|
366 } |
|
367 |
|
368 return $this; |
|
369 } |
|
370 |
|
371 /** |
|
372 * Returns the adapters name and it's options |
|
373 * |
|
374 * @param string|null $optionKey String returns this option |
|
375 * null returns all options |
|
376 * @return integer|string|array|null |
|
377 */ |
|
378 public function getOptions($optionKey = null) |
|
379 { |
|
380 if ($optionKey === null) { |
|
381 return $this->_options; |
|
382 } |
|
383 |
|
384 if (isset($this->_options[$optionKey]) === true) { |
|
385 return $this->_options[$optionKey]; |
|
386 } |
|
387 |
|
388 return null; |
|
389 } |
|
390 |
|
391 /** |
|
392 * Gets locale |
|
393 * |
|
394 * @return Zend_Locale|string|null |
|
395 */ |
|
396 public function getLocale() |
|
397 { |
|
398 return $this->_options['locale']; |
|
399 } |
|
400 |
|
401 /** |
|
402 * Sets locale |
|
403 * |
|
404 * @param string|Zend_Locale $locale Locale to set |
|
405 * @throws Zend_Translate_Exception |
|
406 * @return Zend_Translate_Adapter Provides fluent interface |
|
407 */ |
|
408 public function setLocale($locale) |
|
409 { |
|
410 if (($locale === "auto") or ($locale === null)) { |
|
411 $this->_automatic = true; |
|
412 } else { |
|
413 $this->_automatic = false; |
|
414 } |
|
415 |
|
416 try { |
|
417 $locale = Zend_Locale::findLocale($locale); |
|
418 } catch (Zend_Locale_Exception $e) { |
|
419 require_once 'Zend/Translate/Exception.php'; |
|
420 throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist", 0, $e); |
|
421 } |
|
422 |
|
423 if (!isset($this->_translate[$locale])) { |
|
424 $temp = explode('_', $locale); |
|
425 if (!isset($this->_translate[$temp[0]]) and !isset($this->_translate[$locale])) { |
|
426 if (!$this->_options['disableNotices']) { |
|
427 if ($this->_options['log']) { |
|
428 $this->_options['log']->log("The language '{$locale}' has to be added before it can be used.", $this->_options['logPriority']); |
|
429 } else { |
|
430 trigger_error("The language '{$locale}' has to be added before it can be used.", E_USER_NOTICE); |
|
431 } |
|
432 } |
|
433 } |
|
434 |
|
435 $locale = $temp[0]; |
|
436 } |
|
437 |
|
438 if (empty($this->_translate[$locale])) { |
|
439 if (!$this->_options['disableNotices']) { |
|
440 if ($this->_options['log']) { |
|
441 $this->_options['log']->log("No translation for the language '{$locale}' available.", $this->_options['logPriority']); |
|
442 } else { |
|
443 trigger_error("No translation for the language '{$locale}' available.", E_USER_NOTICE); |
|
444 } |
|
445 } |
|
446 } |
|
447 |
|
448 if ($this->_options['locale'] != $locale) { |
|
449 $this->_options['locale'] = $locale; |
|
450 |
|
451 if (isset(self::$_cache)) { |
|
452 $id = 'Zend_Translate_' . $this->toString() . '_Options'; |
|
453 if (self::$_cacheTags) { |
|
454 self::$_cache->save($this->_options, $id, array($this->_options['tag'])); |
|
455 } else { |
|
456 self::$_cache->save($this->_options, $id); |
|
457 } |
|
458 } |
|
459 } |
|
460 |
|
461 return $this; |
|
462 } |
|
463 |
|
464 /** |
|
465 * Returns the available languages from this adapter |
|
466 * |
|
467 * @return array |
|
468 */ |
|
469 public function getList() |
|
470 { |
|
471 $list = array_keys($this->_translate); |
|
472 $result = null; |
|
473 foreach($list as $value) { |
|
474 if (!empty($this->_translate[$value])) { |
|
475 $result[$value] = $value; |
|
476 } |
|
477 } |
|
478 return $result; |
|
479 } |
|
480 |
|
481 /** |
|
482 * Returns the message id for a given translation |
|
483 * If no locale is given, the actual language will be used |
|
484 * |
|
485 * @param string $message Message to get the key for |
|
486 * @param string|Zend_Locale $locale (optional) Language to return the message ids from |
|
487 * @return string|array|false |
|
488 */ |
|
489 public function getMessageId($message, $locale = null) |
|
490 { |
|
491 if (empty($locale) or !$this->isAvailable($locale)) { |
|
492 $locale = $this->_options['locale']; |
|
493 } |
|
494 |
|
495 return array_search($message, $this->_translate[(string) $locale]); |
|
496 } |
|
497 |
|
498 /** |
|
499 * Returns all available message ids from this adapter |
|
500 * If no locale is given, the actual language will be used |
|
501 * |
|
502 * @param string|Zend_Locale $locale (optional) Language to return the message ids from |
|
503 * @return array |
|
504 */ |
|
505 public function getMessageIds($locale = null) |
|
506 { |
|
507 if (empty($locale) or !$this->isAvailable($locale)) { |
|
508 $locale = $this->_options['locale']; |
|
509 } |
|
510 |
|
511 return array_keys($this->_translate[(string) $locale]); |
|
512 } |
|
513 |
|
514 /** |
|
515 * Returns all available translations from this adapter |
|
516 * If no locale is given, the actual language will be used |
|
517 * If 'all' is given the complete translation dictionary will be returned |
|
518 * |
|
519 * @param string|Zend_Locale $locale (optional) Language to return the messages from |
|
520 * @return array |
|
521 */ |
|
522 public function getMessages($locale = null) |
|
523 { |
|
524 if ($locale === 'all') { |
|
525 return $this->_translate; |
|
526 } |
|
527 |
|
528 if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) { |
|
529 $locale = $this->_options['locale']; |
|
530 } |
|
531 |
|
532 return $this->_translate[(string) $locale]; |
|
533 } |
|
534 |
|
535 /** |
|
536 * Is the wished language available ? |
|
537 * |
|
538 * @see Zend_Locale |
|
539 * @param string|Zend_Locale $locale Language to search for, identical with locale identifier, |
|
540 * @see Zend_Locale for more information |
|
541 * @return boolean |
|
542 */ |
|
543 public function isAvailable($locale) |
|
544 { |
|
545 $return = isset($this->_translate[(string) $locale]); |
|
546 return $return; |
|
547 } |
|
548 |
|
549 /** |
|
550 * Load translation data |
|
551 * |
|
552 * @param mixed $data |
|
553 * @param string|Zend_Locale $locale |
|
554 * @param array $options (optional) |
|
555 * @return array |
|
556 */ |
|
557 abstract protected function _loadTranslationData($data, $locale, array $options = array()); |
|
558 |
|
559 /** |
|
560 * Internal function for adding translation data |
|
561 * |
|
562 * This may be a new language or additional data for an existing language |
|
563 * If the options 'clear' is true, then the translation data for the specified |
|
564 * language is replaced and added otherwise |
|
565 * |
|
566 * @see Zend_Locale |
|
567 * @param array|Zend_Config $content Translation data to add |
|
568 * @throws Zend_Translate_Exception |
|
569 * @return Zend_Translate_Adapter Provides fluent interface |
|
570 */ |
|
571 private function _addTranslationData($options = array()) |
|
572 { |
|
573 if ($options instanceof Zend_Config) { |
|
574 $options = $options->toArray(); |
|
575 } else if (func_num_args() > 1) { |
|
576 $args = func_get_args(); |
|
577 $options['content'] = array_shift($args); |
|
578 |
|
579 if (!empty($args)) { |
|
580 $options['locale'] = array_shift($args); |
|
581 } |
|
582 |
|
583 if (!empty($args)) { |
|
584 $options += array_shift($args); |
|
585 } |
|
586 } |
|
587 |
|
588 if (($options['content'] instanceof Zend_Translate) || ($options['content'] instanceof Zend_Translate_Adapter)) { |
|
589 $options['usetranslateadapter'] = true; |
|
590 if (!empty($options['locale']) && ($options['locale'] !== 'auto')) { |
|
591 $options['content'] = $options['content']->getMessages($options['locale']); |
|
592 } else { |
|
593 $content = $options['content']; |
|
594 $locales = $content->getList(); |
|
595 foreach ($locales as $locale) { |
|
596 $options['locale'] = $locale; |
|
597 $options['content'] = $content->getMessages($locale); |
|
598 $this->_addTranslationData($options); |
|
599 } |
|
600 |
|
601 return $this; |
|
602 } |
|
603 } |
|
604 |
|
605 try { |
|
606 $options['locale'] = Zend_Locale::findLocale($options['locale']); |
|
607 } catch (Zend_Locale_Exception $e) { |
|
608 require_once 'Zend/Translate/Exception.php'; |
|
609 throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e); |
|
610 } |
|
611 |
|
612 if ($options['clear'] || !isset($this->_translate[$options['locale']])) { |
|
613 $this->_translate[$options['locale']] = array(); |
|
614 } |
|
615 |
|
616 $read = true; |
|
617 if (isset(self::$_cache)) { |
|
618 $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString(); |
|
619 $temp = self::$_cache->load($id); |
|
620 if ($temp) { |
|
621 $read = false; |
|
622 } |
|
623 } |
|
624 |
|
625 if ($options['reload']) { |
|
626 $read = true; |
|
627 } |
|
628 |
|
629 if ($read) { |
|
630 if (!empty($options['usetranslateadapter'])) { |
|
631 $temp = array($options['locale'] => $options['content']); |
|
632 } else { |
|
633 $temp = $this->_loadTranslationData($options['content'], $options['locale'], $options); |
|
634 } |
|
635 } |
|
636 |
|
637 if (empty($temp)) { |
|
638 $temp = array(); |
|
639 } |
|
640 |
|
641 $keys = array_keys($temp); |
|
642 foreach($keys as $key) { |
|
643 if (!isset($this->_translate[$key])) { |
|
644 $this->_translate[$key] = array(); |
|
645 } |
|
646 |
|
647 if (array_key_exists($key, $temp) && is_array($temp[$key])) { |
|
648 $this->_translate[$key] = $temp[$key] + $this->_translate[$key]; |
|
649 } |
|
650 } |
|
651 |
|
652 if ($this->_automatic === true) { |
|
653 $find = new Zend_Locale($options['locale']); |
|
654 $browser = $find->getEnvironment() + $find->getBrowser(); |
|
655 arsort($browser); |
|
656 foreach($browser as $language => $quality) { |
|
657 if (isset($this->_translate[$language])) { |
|
658 $this->_options['locale'] = $language; |
|
659 break; |
|
660 } |
|
661 } |
|
662 } |
|
663 |
|
664 if (($read) and (isset(self::$_cache))) { |
|
665 $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString(); |
|
666 if (self::$_cacheTags) { |
|
667 self::$_cache->save($temp, $id, array($this->_options['tag'])); |
|
668 } else { |
|
669 self::$_cache->save($temp, $id); |
|
670 } |
|
671 } |
|
672 |
|
673 return $this; |
|
674 } |
|
675 |
|
676 /** |
|
677 * Translates the given string |
|
678 * returns the translation |
|
679 * |
|
680 * @see Zend_Locale |
|
681 * @param string|array $messageId Translation string, or Array for plural translations |
|
682 * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with |
|
683 * locale identifier, @see Zend_Locale for more information |
|
684 * @return string |
|
685 */ |
|
686 public function translate($messageId, $locale = null) |
|
687 { |
|
688 if ($locale === null) { |
|
689 $locale = $this->_options['locale']; |
|
690 } |
|
691 |
|
692 $plural = null; |
|
693 if (is_array($messageId)) { |
|
694 if (count($messageId) > 2) { |
|
695 $number = array_pop($messageId); |
|
696 if (!is_numeric($number)) { |
|
697 $plocale = $number; |
|
698 $number = array_pop($messageId); |
|
699 } else { |
|
700 $plocale = 'en'; |
|
701 } |
|
702 |
|
703 $plural = $messageId; |
|
704 $messageId = $messageId[0]; |
|
705 } else { |
|
706 $messageId = $messageId[0]; |
|
707 } |
|
708 } |
|
709 |
|
710 if (!Zend_Locale::isLocale($locale, true, false)) { |
|
711 if (!Zend_Locale::isLocale($locale, false, false)) { |
|
712 // language does not exist, return original string |
|
713 $this->_log($messageId, $locale); |
|
714 // use rerouting when enabled |
|
715 if (!empty($this->_options['route'])) { |
|
716 if (array_key_exists($locale, $this->_options['route']) && |
|
717 !array_key_exists($locale, $this->_routed)) { |
|
718 $this->_routed[$locale] = true; |
|
719 return $this->translate($messageId, $this->_options['route'][$locale]); |
|
720 } |
|
721 } |
|
722 |
|
723 $this->_routed = array(); |
|
724 if ($plural === null) { |
|
725 return $messageId; |
|
726 } |
|
727 |
|
728 $rule = Zend_Translate_Plural::getPlural($number, $plocale); |
|
729 if (!isset($plural[$rule])) { |
|
730 $rule = 0; |
|
731 } |
|
732 |
|
733 return $plural[$rule]; |
|
734 } |
|
735 |
|
736 $locale = new Zend_Locale($locale); |
|
737 } |
|
738 |
|
739 $locale = (string) $locale; |
|
740 if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { |
|
741 // return original translation |
|
742 if ($plural === null) { |
|
743 $this->_routed = array(); |
|
744 return $this->_translate[$locale][$messageId]; |
|
745 } |
|
746 |
|
747 $rule = Zend_Translate_Plural::getPlural($number, $locale); |
|
748 if (isset($this->_translate[$locale][$plural[0]][$rule])) { |
|
749 $this->_routed = array(); |
|
750 return $this->_translate[$locale][$plural[0]][$rule]; |
|
751 } |
|
752 } else if (strlen($locale) != 2) { |
|
753 // faster than creating a new locale and separate the leading part |
|
754 $locale = substr($locale, 0, -strlen(strrchr($locale, '_'))); |
|
755 |
|
756 if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { |
|
757 // return regionless translation (en_US -> en) |
|
758 if ($plural === null) { |
|
759 $this->_routed = array(); |
|
760 return $this->_translate[$locale][$messageId]; |
|
761 } |
|
762 |
|
763 $rule = Zend_Translate_Plural::getPlural($number, $locale); |
|
764 if (isset($this->_translate[$locale][$plural[0]][$rule])) { |
|
765 $this->_routed = array(); |
|
766 return $this->_translate[$locale][$plural[0]][$rule]; |
|
767 } |
|
768 } |
|
769 } |
|
770 |
|
771 $this->_log($messageId, $locale); |
|
772 // use rerouting when enabled |
|
773 if (!empty($this->_options['route'])) { |
|
774 if (array_key_exists($locale, $this->_options['route']) && |
|
775 !array_key_exists($locale, $this->_routed)) { |
|
776 $this->_routed[$locale] = true; |
|
777 return $this->translate($messageId, $this->_options['route'][$locale]); |
|
778 } |
|
779 } |
|
780 |
|
781 $this->_routed = array(); |
|
782 if ($plural === null) { |
|
783 return $messageId; |
|
784 } |
|
785 |
|
786 $rule = Zend_Translate_Plural::getPlural($number, $plocale); |
|
787 if (!isset($plural[$rule])) { |
|
788 $rule = 0; |
|
789 } |
|
790 |
|
791 return $plural[$rule]; |
|
792 } |
|
793 |
|
794 /** |
|
795 * Translates the given string using plural notations |
|
796 * Returns the translated string |
|
797 * |
|
798 * @see Zend_Locale |
|
799 * @param string $singular Singular translation string |
|
800 * @param string $plural Plural translation string |
|
801 * @param integer $number Number for detecting the correct plural |
|
802 * @param string|Zend_Locale $locale (Optional) Locale/Language to use, identical with |
|
803 * locale identifier, @see Zend_Locale for more information |
|
804 * @return string |
|
805 */ |
|
806 public function plural($singular, $plural, $number, $locale = null) |
|
807 { |
|
808 return $this->translate(array($singular, $plural, $number), $locale); |
|
809 } |
|
810 |
|
811 /** |
|
812 * Logs a message when the log option is set |
|
813 * |
|
814 * @param string $message Message to log |
|
815 * @param String $locale Locale to log |
|
816 */ |
|
817 protected function _log($message, $locale) { |
|
818 if ($this->_options['logUntranslated']) { |
|
819 $message = str_replace('%message%', $message, $this->_options['logMessage']); |
|
820 $message = str_replace('%locale%', $locale, $message); |
|
821 if ($this->_options['log']) { |
|
822 $this->_options['log']->log($message, $this->_options['logPriority']); |
|
823 } else { |
|
824 trigger_error($message, E_USER_NOTICE); |
|
825 } |
|
826 } |
|
827 } |
|
828 |
|
829 /** |
|
830 * Translates the given string |
|
831 * returns the translation |
|
832 * |
|
833 * @param string $messageId Translation string |
|
834 * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale |
|
835 * identifier, @see Zend_Locale for more information |
|
836 * @return string |
|
837 */ |
|
838 public function _($messageId, $locale = null) |
|
839 { |
|
840 return $this->translate($messageId, $locale); |
|
841 } |
|
842 |
|
843 /** |
|
844 * Checks if a string is translated within the source or not |
|
845 * returns boolean |
|
846 * |
|
847 * @param string $messageId Translation string |
|
848 * @param boolean $original (optional) Allow translation only for original language |
|
849 * when true, a translation for 'en_US' would give false when it can |
|
850 * be translated with 'en' only |
|
851 * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale identifier, |
|
852 * see Zend_Locale for more information |
|
853 * @return boolean |
|
854 */ |
|
855 public function isTranslated($messageId, $original = false, $locale = null) |
|
856 { |
|
857 if (($original !== false) and ($original !== true)) { |
|
858 $locale = $original; |
|
859 $original = false; |
|
860 } |
|
861 |
|
862 if ($locale === null) { |
|
863 $locale = $this->_options['locale']; |
|
864 } |
|
865 |
|
866 if (!Zend_Locale::isLocale($locale, true, false)) { |
|
867 if (!Zend_Locale::isLocale($locale, false, false)) { |
|
868 // language does not exist, return original string |
|
869 return false; |
|
870 } |
|
871 |
|
872 $locale = new Zend_Locale($locale); |
|
873 } |
|
874 |
|
875 $locale = (string) $locale; |
|
876 if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { |
|
877 // return original translation |
|
878 return true; |
|
879 } else if ((strlen($locale) != 2) and ($original === false)) { |
|
880 // faster than creating a new locale and separate the leading part |
|
881 $locale = substr($locale, 0, -strlen(strrchr($locale, '_'))); |
|
882 |
|
883 if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { |
|
884 // return regionless translation (en_US -> en) |
|
885 return true; |
|
886 } |
|
887 } |
|
888 |
|
889 // No translation found, return original |
|
890 return false; |
|
891 } |
|
892 |
|
893 /** |
|
894 * Returns the set cache |
|
895 * |
|
896 * @return Zend_Cache_Core The set cache |
|
897 */ |
|
898 public static function getCache() |
|
899 { |
|
900 return self::$_cache; |
|
901 } |
|
902 |
|
903 /** |
|
904 * Sets a cache for all Zend_Translate_Adapters |
|
905 * |
|
906 * @param Zend_Cache_Core $cache Cache to store to |
|
907 */ |
|
908 public static function setCache(Zend_Cache_Core $cache) |
|
909 { |
|
910 self::$_cache = $cache; |
|
911 self::_getTagSupportForCache(); |
|
912 } |
|
913 |
|
914 /** |
|
915 * Returns true when a cache is set |
|
916 * |
|
917 * @return boolean |
|
918 */ |
|
919 public static function hasCache() |
|
920 { |
|
921 if (self::$_cache !== null) { |
|
922 return true; |
|
923 } |
|
924 |
|
925 return false; |
|
926 } |
|
927 |
|
928 /** |
|
929 * Removes any set cache |
|
930 * |
|
931 * @return void |
|
932 */ |
|
933 public static function removeCache() |
|
934 { |
|
935 self::$_cache = null; |
|
936 } |
|
937 |
|
938 /** |
|
939 * Clears all set cache data |
|
940 * |
|
941 * @param string $tag Tag to clear when the default tag name is not used |
|
942 * @return void |
|
943 */ |
|
944 public static function clearCache($tag = null) |
|
945 { |
|
946 require_once 'Zend/Cache.php'; |
|
947 if (self::$_cacheTags) { |
|
948 if ($tag == null) { |
|
949 $tag = 'Zend_Translate'; |
|
950 } |
|
951 |
|
952 self::$_cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array($tag)); |
|
953 } else { |
|
954 self::$_cache->clean(Zend_Cache::CLEANING_MODE_ALL); |
|
955 } |
|
956 } |
|
957 |
|
958 /** |
|
959 * Returns the adapter name |
|
960 * |
|
961 * @return string |
|
962 */ |
|
963 abstract public function toString(); |
|
964 |
|
965 /** |
|
966 * Internal method to check if the given cache supports tags |
|
967 * |
|
968 * @param Zend_Cache $cache |
|
969 */ |
|
970 private static function _getTagSupportForCache() |
|
971 { |
|
972 $backend = self::$_cache->getBackend(); |
|
973 if ($backend instanceof Zend_Cache_Backend_ExtendedInterface) { |
|
974 $cacheOptions = $backend->getCapabilities(); |
|
975 self::$_cacheTags = $cacheOptions['tags']; |
|
976 } else { |
|
977 self::$_cacheTags = false; |
|
978 } |
|
979 |
|
980 return self::$_cacheTags; |
|
981 } |
|
982 } |