web/Zend/Translate/Adapter.php
changeset 0 4eba9c11703f
equal deleted inserted replaced
-1:000000000000 0:4eba9c11703f
       
     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 }