00001 <?php
00026 require_once 'Zend/Locale.php';
00027
00031 require_once 'Zend/Translate/Plural.php';
00032
00042 abstract class Zend_Translate_Adapter {
00047 private $_automatic = true;
00048
00053 protected static $_cache = null;
00054
00059 const LOCALE_DIRECTORY = 'directory';
00060
00065 const LOCALE_FILENAME = 'filename';
00066
00074 protected $_options = array(
00075 'clear' => false,
00076 'disableNotices' => false,
00077 'ignore' => '.',
00078 'locale' => 'auto',
00079 'log' => null,
00080 'logMessage' => "Untranslated message within '%locale%': %message%",
00081 'logUntranslated' => false,
00082 'scan' => null
00083 );
00084
00089 protected $_translate = array();
00090
00101 public function __construct($data, $locale = null, array $options = array())
00102 {
00103 if (isset(self::$_cache)) {
00104 $id = 'Zend_Translate_' . $this->toString() . '_Options';
00105 $result = self::$_cache->load($id);
00106 if ($result) {
00107 $this->_options = unserialize($result);
00108 }
00109 }
00110
00111 if (($locale === "auto") or ($locale === null)) {
00112 $this->_automatic = true;
00113 } else {
00114 $this->_automatic = false;
00115 }
00116
00117 $this->addTranslation($data, $locale, $options);
00118 if ($this->getLocale() !== (string) $locale) {
00119 $this->setLocale($locale);
00120 }
00121 }
00122
00137 public function addTranslation($data, $locale = null, array $options = array())
00138 {
00139 try {
00140 $locale = Zend_Locale::findLocale($locale);
00141 } catch (Zend_Locale_Exception $e) {
00142 require_once 'Zend/Translate/Exception.php';
00143 throw new Zend_Translate_Exception("The given Language '{$locale}' does not exist");
00144 }
00145
00146 $originate = (string) $locale;
00147
00148 $this->setOptions($options);
00149 if (is_string($data) and is_dir($data)) {
00150 $data = realpath($data);
00151 $prev = '';
00152 foreach (new RecursiveIteratorIterator(
00153 new RecursiveDirectoryIterator($data, RecursiveDirectoryIterator::KEY_AS_PATHNAME),
00154 RecursiveIteratorIterator::SELF_FIRST) as $directory => $info) {
00155 $file = $info->getFilename();
00156 if (strpos($directory, DIRECTORY_SEPARATOR . $this->_options['ignore']) !== false) {
00157
00158 continue;
00159 }
00160
00161 if ($info->isDir()) {
00162
00163 if (($this->_options['scan'] === self::LOCALE_DIRECTORY) and (Zend_Locale::isLocale($file, true, false))) {
00164 if (strlen($prev) <= strlen($file)) {
00165 $locale = $file;
00166 $prev = (string) $locale;
00167 }
00168 }
00169 } else if ($info->isFile()) {
00170
00171 if ($this->_options['scan'] === self::LOCALE_FILENAME) {
00172 $filename = explode('.', $file);
00173 array_pop($filename);
00174 $filename = implode('.', $filename);
00175 if (Zend_Locale::isLocale((string) $filename, true, false)) {
00176 $locale = (string) $filename;
00177 } else {
00178 $parts = explode('.', $file);
00179 $parts2 = array();
00180 foreach($parts as $token) {
00181 $parts2 += explode('_', $token);
00182 }
00183 $parts = array_merge($parts, $parts2);
00184 $parts2 = array();
00185 foreach($parts as $token) {
00186 $parts2 += explode('-', $token);
00187 }
00188 $parts = array_merge($parts, $parts2);
00189 $parts = array_unique($parts);
00190 $prev = '';
00191 foreach($parts as $token) {
00192 if (Zend_Locale::isLocale($token, true, false)) {
00193 if (strlen($prev) <= strlen($token)) {
00194 $locale = $token;
00195 $prev = $token;
00196 }
00197 }
00198 }
00199 }
00200 }
00201 try {
00202 $this->_addTranslationData($info->getPathname(), (string) $locale, $this->_options);
00203 if ((isset($this->_translate[(string) $locale]) === true) and (count($this->_translate[(string) $locale]) > 0)) {
00204 $this->setLocale($locale);
00205 }
00206 } catch (Zend_Translate_Exception $e) {
00207
00208 }
00209 }
00210 }
00211 } else {
00212 $this->_addTranslationData($data, (string) $locale, $this->_options);
00213 if ((isset($this->_translate[(string) $locale]) === true) and (count($this->_translate[(string) $locale]) > 0)) {
00214 $this->setLocale($locale);
00215 }
00216 }
00217
00218 if ((isset($this->_translate[$originate]) === true) and (count($this->_translate[$originate]) > 0) and ($originate !== (string) $locale)) {
00219 $this->setLocale($originate);
00220 }
00221
00222 return $this;
00223 }
00224
00232 public function setOptions(array $options = array())
00233 {
00234 $change = false;
00235 $locale = null;
00236 foreach ($options as $key => $option) {
00237 if ($key == 'locale') {
00238 $locale = $option;
00239 } else if ((isset($this->_options[$key]) and ($this->_options[$key] != $option)) or
00240 !isset($this->_options[$key])) {
00241 if (($key == 'log') && !($option instanceof Zend_Log)) {
00242 require_once 'Zend/Translate/Exception.php';
00243 throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log');
00244 }
00245
00246 $this->_options[$key] = $option;
00247 $change = true;
00248 }
00249 }
00250
00251 if ($locale !== null) {
00252 $this->setLocale($locale);
00253 }
00254
00255 if (isset(self::$_cache) and ($change == true)) {
00256 $id = 'Zend_Translate_' . $this->toString() . '_Options';
00257 self::$_cache->save( serialize($this->_options), $id, array('Zend_Translate'));
00258 }
00259
00260 return $this;
00261 }
00262
00270 public function getOptions($optionKey = null)
00271 {
00272 if ($optionKey === null) {
00273 return $this->_options;
00274 }
00275
00276 if (isset($this->_options[$optionKey]) === true) {
00277 return $this->_options[$optionKey];
00278 }
00279
00280 return null;
00281 }
00282
00288 public function getLocale()
00289 {
00290 return $this->_options['locale'];
00291 }
00292
00300 public function setLocale($locale)
00301 {
00302 if (($locale === "auto") or ($locale === null)) {
00303 $this->_automatic = true;
00304 } else {
00305 $this->_automatic = false;
00306 }
00307
00308 try {
00309 $locale = Zend_Locale::findLocale($locale);
00310 } catch (Zend_Locale_Exception $e) {
00311 require_once 'Zend/Translate/Exception.php';
00312 throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist");
00313 }
00314
00315 if (!isset($this->_translate[$locale])) {
00316 $temp = explode('_', $locale);
00317 if (!isset($this->_translate[$temp[0]]) and !isset($this->_translate[$locale])) {
00318 if (!$this->_options['disableNotices']) {
00319 if ($this->_options['log']) {
00320 $this->_options['log']->notice("The language '{$locale}' has to be added before it can be used.");
00321 } else {
00322 trigger_error("The language '{$locale}' has to be added before it can be used.", E_USER_NOTICE);
00323 }
00324 }
00325 }
00326
00327 $locale = $temp[0];
00328 }
00329
00330 if (empty($this->_translate[$locale])) {
00331 if (!$this->_options['disableNotices']) {
00332 if ($this->_options['log']) {
00333 $this->_options['log']->notice("No translation for the language '{$locale}' available.");
00334 } else {
00335 trigger_error("No translation for the language '{$locale}' available.", E_USER_NOTICE);
00336 }
00337 }
00338 }
00339
00340 if ($this->_options['locale'] != $locale) {
00341 $this->_options['locale'] = $locale;
00342
00343 if (isset(self::$_cache)) {
00344 $id = 'Zend_Translate_' . $this->toString() . '_Options';
00345 self::$_cache->save( serialize($this->_options), $id, array('Zend_Translate'));
00346 }
00347 }
00348
00349 return $this;
00350 }
00351
00357 public function getList()
00358 {
00359 $list = array_keys($this->_translate);
00360 $result = null;
00361 foreach($list as $value) {
00362 if (!empty($this->_translate[$value])) {
00363 $result[$value] = $value;
00364 }
00365 }
00366 return $result;
00367 }
00368
00376 public function getMessageIds($locale = null)
00377 {
00378 if (empty($locale) or !$this->isAvailable($locale)) {
00379 $locale = $this->_options['locale'];
00380 }
00381
00382 return array_keys($this->_translate[(string) $locale]);
00383 }
00384
00393 public function getMessages($locale = null)
00394 {
00395 if ($locale === 'all') {
00396 return $this->_translate;
00397 }
00398
00399 if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) {
00400 $locale = $this->_options['locale'];
00401 }
00402
00403 return $this->_translate[(string) $locale];
00404 }
00405
00414 public function isAvailable($locale)
00415 {
00416 $return = isset($this->_translate[(string) $locale]);
00417 return $return;
00418 }
00419
00428 abstract protected function _loadTranslationData($data, $locale, array $options = array());
00429
00445 private function _addTranslationData($data, $locale, array $options = array())
00446 {
00447 try {
00448 $locale = Zend_Locale::findLocale($locale);
00449 } catch (Zend_Locale_Exception $e) {
00450 require_once 'Zend/Translate/Exception.php';
00451 throw new Zend_Translate_Exception("The given Language '{$locale}' does not exist");
00452 }
00453
00454 if ($options['clear'] || !isset($this->_translate[$locale])) {
00455 $this->_translate[$locale] = array();
00456 }
00457
00458 $read = true;
00459 if (isset(self::$_cache)) {
00460 $id = 'Zend_Translate_' . md5(serialize($data)) . '_' . $this->toString();
00461 $result = self::$_cache->load($id);
00462 if ($result) {
00463 $temp = unserialize($result);
00464 $read = false;
00465 }
00466 }
00467
00468 if ($read) {
00469 $temp = $this->_loadTranslationData($data, $locale, $options);
00470 }
00471
00472 if (empty($temp)) {
00473 $temp = array();
00474 }
00475
00476 $keys = array_keys($temp);
00477 foreach($keys as $key) {
00478 if (!isset($this->_translate[$key])) {
00479 $this->_translate[$key] = array();
00480 }
00481
00482 $this->_translate[$key] = $temp[$key] + $this->_translate[$key];
00483 }
00484
00485 if ($this->_automatic === true) {
00486 $find = new Zend_Locale($locale);
00487 $browser = $find->getEnvironment() + $find->getBrowser();
00488 arsort($browser);
00489 foreach($browser as $language => $quality) {
00490 if (isset($this->_translate[$language])) {
00491 $this->_options['locale'] = $language;
00492 break;
00493 }
00494 }
00495 }
00496
00497 if (($read) and (isset(self::$_cache))) {
00498 $id = 'Zend_Translate_' . md5(serialize($data)) . '_' . $this->toString();
00499 self::$_cache->save( serialize($temp), $id, array('Zend_Translate'));
00500 }
00501
00502 return $this;
00503 }
00504
00515 public function translate($messageId, $locale = null)
00516 {
00517 if ($locale === null) {
00518 $locale = $this->_options['locale'];
00519 }
00520
00521 $plural = null;
00522 if (is_array($messageId)) {
00523 if (count($messageId) > 2) {
00524 $number = array_pop($messageId);
00525 if (!is_numeric($number)) {
00526 $plocale = $number;
00527 $number = array_pop($messageId);
00528 } else {
00529 $plocale = 'en';
00530 }
00531
00532 $plural = $messageId;
00533 $messageId = $messageId[0];
00534 } else {
00535 $messageId = $messageId[0];
00536 }
00537 }
00538
00539 if (!Zend_Locale::isLocale($locale, true, false)) {
00540 if (!Zend_Locale::isLocale($locale, false, false)) {
00541
00542 $this->_log($messageId, $locale);
00543 if ($plural === null) {
00544 return $messageId;
00545 }
00546
00547 $rule = Zend_Translate_Plural::getPlural($number, $plocale);
00548 if (!isset($plural[$rule])) {
00549 $rule = 0;
00550 }
00551
00552 return $plural[$rule];
00553 }
00554
00555 $locale = new Zend_Locale($locale);
00556 }
00557
00558 $locale = (string) $locale;
00559 if (isset($this->_translate[$locale][$messageId])) {
00560
00561 if ($plural === null) {
00562 return $this->_translate[$locale][$messageId];
00563 }
00564
00565 $rule = Zend_Translate_Plural::getPlural($number, $locale);
00566 if (isset($this->_translate[$locale][$plural[0]][$rule])) {
00567 return $this->_translate[$locale][$plural[0]][$rule];
00568 }
00569 } else if (strlen($locale) != 2) {
00570
00571 $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
00572
00573 if (isset($this->_translate[$locale][$messageId])) {
00574
00575 if ($plural === null) {
00576 return $this->_translate[$locale][$messageId];
00577 }
00578
00579 $rule = Zend_Translate_Plural::getPlural($number, $locale);
00580 if (isset($this->_translate[$locale][$plural[0]][$rule])) {
00581 return $this->_translate[$locale][$plural[0]][$rule];
00582 }
00583 }
00584 }
00585
00586 $this->_log($messageId, $locale);
00587 if ($plural === null) {
00588 return $messageId;
00589 }
00590
00591 $rule = Zend_Translate_Plural::getPlural($number, $plocale);
00592 if (!isset($plural[$rule])) {
00593 $rule = 0;
00594 }
00595
00596 return $plural[$rule];
00597 }
00598
00611 public function plural($singular, $plural, $number, $locale = null)
00612 {
00613 return $this->translate(array($singular, $plural, $number), $locale);
00614 }
00615
00622 protected function _log($message, $locale) {
00623 if ($this->_options['logUntranslated']) {
00624 $message = str_replace('%message%', $message, $this->_options['logMessage']);
00625 $message = str_replace('%locale%', $locale, $message);
00626 if ($this->_options['log']) {
00627 $this->_options['log']->notice($message);
00628 } else {
00629 trigger_error($message, E_USER_NOTICE);
00630 }
00631 }
00632 }
00633
00643 public function _($messageId, $locale = null)
00644 {
00645 return $this->translate($messageId, $locale);
00646 }
00647
00660 public function isTranslated($messageId, $original = false, $locale = null)
00661 {
00662 if (($original !== false) and ($original !== true)) {
00663 $locale = $original;
00664 $original = false;
00665 }
00666
00667 if ($locale === null) {
00668 $locale = $this->_options['locale'];
00669 }
00670
00671 if (!Zend_Locale::isLocale($locale, true, false)) {
00672 if (!Zend_Locale::isLocale($locale, false, false)) {
00673
00674 $this->_log($messageId, $locale);
00675 return false;
00676 }
00677
00678 $locale = new Zend_Locale($locale);
00679 }
00680
00681 $locale = (string) $locale;
00682 if (isset($this->_translate[$locale][$messageId]) === true) {
00683
00684 return true;
00685 } else if ((strlen($locale) != 2) and ($original === false)) {
00686
00687 $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
00688
00689 if (isset($this->_translate[$locale][$messageId]) === true) {
00690
00691 return true;
00692 }
00693 }
00694
00695
00696 $this->_log($messageId, $locale);
00697 return false;
00698 }
00699
00705 public static function getCache()
00706 {
00707 return self::$_cache;
00708 }
00709
00715 public static function setCache(Zend_Cache_Core $cache)
00716 {
00717 self::$_cache = $cache;
00718 }
00719
00725 public static function hasCache()
00726 {
00727 if (self::$_cache !== null) {
00728 return true;
00729 }
00730
00731 return false;
00732 }
00733
00739 public static function removeCache()
00740 {
00741 self::$_cache = null;
00742 }
00743
00749 public static function clearCache()
00750 {
00751 require_once 'Zend/Cache.php';
00752 self::$_cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('Zend_Translate'));
00753 }
00754
00760 abstract public function toString();
00761 }