toArray(); } else if (func_num_args() > 1) { $args = func_get_args(); $options = array(); $options['adapter'] = array_shift($args); if (!empty($args)) { $options['content'] = array_shift($args); } if (!empty($args)) { $options['locale'] = array_shift($args); } if (!empty($args)) { $opt = array_shift($args); $options = array_merge($opt, $options); } } else if (!is_array($options)) { $options = array('adapter' => $options); } // Use default (interface) locale, if not specified else if (!array_key_exists('locale',$options) || is_null($options['locale'])) { $options['locale'] = Broker::getLocale(); } $this->_locale = $options['locale']; // No notices $options['disableNotices'] = true; // Translation disabled in some kind of way $this->_use_translation = Broker::getConfig()->Bootstrap->use_translation; $this->_dev_translation = Broker::getConfig()->Bootstrap->dev_translation; // Zend $this->setAdapter($options); } /** * Sets a new adapter. * Catch Exception, if Adapter not readable * * @param array|Zend_Config $options Options to use * @throws Zend_Translate_Exception */ public function setAdapter($options = array()) { if ($options instanceof Zend_Config) { $options = $options->toArray(); } else if (func_num_args() > 1) { $args = func_get_args(); $options = array(); $options['adapter'] = array_shift($args); if (!empty($args)) { $options['content'] = array_shift($args); } if (!empty($args)) { $options['locale'] = array_shift($args); } if (!empty($args)) { $opt = array_shift($args); $options = array_merge($opt, $options); } } else if (!is_array($options)) { $options = array('adapter' => $options); } // Use concrete adapter first try { if (array_key_exists('adapter',$options) && is_string($options['adapter'])) { $classname = Factory::getMostSpecificClass('Translate_Adapter_'. ucfirst($options['adapter'])); $options['adapter'] = $classname; } } catch(Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::ERR); if (Zend_Loader::isReadable('Zend/Translate/Adapter/' . ucfirst($options['adapter']). '.php')) { $options['adapter'] = 'Zend_Translate_Adapter_' . ucfirst($options['adapter']); } if (!class_exists($options['adapter'])) { Zend_Loader::loadClass($options['adapter']); } } if (array_key_exists('cache', $options)) { Zend_Translate_Adapter::setCache($options['cache']); } $adapter = $options['adapter']; unset($options['adapter']); $this->_adapter = new $adapter($options); if (!$this->_adapter instanceof Zend_Translate_Adapter) { require_once 'Zend/Translate/Exception.php'; throw new Zend_Translate_Exception("Adapter " . $adapter . " does not extend Zend_Translate_Adapter"); } } /** * Returns the adapters name and it's options * * @return Zend_Translate_Adapter */ public function getAdapter() { return $this->_adapter; } /** * Returns the set cache * * @return Zend_Cache_Core The set cache */ public static function getCache() { return self::$_cache; } /** * Sets a cache for all instances of Zend_Translate * * @param Zend_Cache_Core $cache Cache to store to * @return void */ public static function setCache(Zend_Cache_Core $cache) { self::$_cache = $cache; } /** * Returns true when a cache is set * * @return boolean */ public static function hasCache() { if (self::$_cache !== null) { return true; } return false; } /** * Removes any set cache * * @return void */ public static function removeCache() { self::$_cache = null; } /** * Clears all set cache data * * @param string $tag Tag to clear when the default tag name is not used * @return void */ public static function clearCache($tag = null) { self::$_cache->clean(); } /** * Calls all methods from the adapter */ public function __call($method, array $options) { if (method_exists($this->_adapter, $method)) { return call_user_func_array(array($this->_adapter, $method), $options); } throw new Zend_Translate_Exception("Unknown method '" . $method . "' called!"); } /** * Get all message from given module as an array * Loads the module-text first * * @param String $module Modulename. * @param String $locale Optional: use another locale. * * @return Array */ public function getAll($module, $locale = null) { $returnArray = $moduleValues = array(); if (is_null($locale)) { $locale = $this->_locale; } /* * Load the module translation file from module */ if ($module != '') { $path = Path::get(Redspark_RsPath::FILE_MODULE_TRANSLATION, array('module'=>$module)); } else { $path = Path::get(Path::FILE_TRANSLATION_APP); } /** * Load only if not loaded * * @todo: better caching, &cache=0, etc. */ try { if (file_exists($path) && !in_array($path, $this->_language_files)) { $this->addTranslation($path); $this->_language_files[] = $path; } } catch (Exception $e) { /* * Only warning log written if translation file unreadable */ Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); //throw new Redspark_Exception_Warning($e->getMessage()); } $returnArray = $this->getMessages($locale); /* * Filter only module specific values */ foreach ($returnArray as $key=>$val) { if (strpos($key,ucfirst($module).'-') === 0) { $moduleValues[$key] = $val; } } return $moduleValues; } /** * Get all languages, supported in this module. * * Loads the module-text first. * * @param String $module Modulename * * @return Array */ public function getLanguages($module) { $returnArray = array(); /* * Load the module translation file from module */ if ($module == 'all') { $modules = Broker::getModuleBroker()->getInstalledModules(); $result = Array(); foreach ($modules AS $mod => $app) { $arr = $this->getLanguages($mod); if (is_array($arr)) { $result = array_merge($result,$arr); } } return $result; } else if ($module != '') { $path = Path::get(Redspark_RsPath::FILE_MODULE_TRANSLATION, array('module'=>$module)); } else { $path = Path::get(Path::FILE_TRANSLATION_APP); } /** * Load only if not loaded * * @todo: better caching, &cache=0, etc. */ try { if (file_exists($path) && !in_array($path, $this->_language_files)) { $this->addTranslation($path); $this->_language_files[] = $path; } } catch (Exception $e) { /* * Only warning log written if translation file unreadable */ Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); //throw new Redspark_Exception_Warning($e->getMessage()); } $returnArray = $this->getList(); // cast to array, if list was empty if (is_null($returnArray)) { $returnArray = array(); } return $returnArray; } /** * Get the Filename of the Translation files for this module * In Redspark, these are located within the module dir * * @param String $module * * @return String */ protected function _getTranslationFileName($module) { /* No Module -> Application */ if (empty($module)) { return Path::get(Path::FILE_TRANSLATION_APP); } // Filename $file = Path::get(Redspark_RsPath::FILE_DYNAMIC_TRANSLATION, array('module'=>$module)); // File not found? copy from module if (!file_exists($file)) { $modfile = Path::get(Redspark_RsPath::FILE_MODULE_TRANSLATION, array('module'=>$module)); copy($modfile, $file); chmod($file, 0777); } return $file; } /** * Get the message from given module-text. * * Loads the module-text first. * * @param String $module * @param String $messageId untranslated message * * @return String translated message */ public function get($module, $messageId) { /** * No translation for unit-testing */ if (Zend_Session::$_unitTestEnabled) { return self::UNITTEST_PRE_MARKER.$messageId.self::UNITTEST_POST_MARKER; } /* * Generate key from messageId */ $key = $this->_prepareKey($module, $messageId); /* * Use message ID by default */ $translation = $messageId; /* * Load the module translation file from temp folder */ if (!in_array($module, $this->_loaded_languages)) { $filename = $this->_getTranslationFileName($module); if (file_exists($filename)) { Redspark_RsProfiling::log('load TMX start: '.basename($filename)); $this->addTranslation(Array('content' => $filename, 'locale' => $this->_locale)); Redspark_RsProfiling::log('load TMX end'); } $this->_loaded_languages[] = $module; } /* * Check if translation is switched off for development */ if ($this->_use_translation && !$this->_dev_translation) { // Key is already translated if ($this->isTranslated($key, false, $this->_locale)) { $translation = $this->translate($key, $this->_locale); // Key is not translated, handle as untranslated (log or write to db) } else { $translation = $this->_handleNonTranslated($module, $translation); } } elseif ($this->_dev_translation) { // Attach marker to translated systemtext $translation = self::TRANSLATED_PRE_MARKER.$translation.self::TRANSLATED_POST_MARKER; } else { // show only systemtext, no translation and no marker - used for unittesting $translation = $translation; } return $translation; } /** * Called if a non translated text was found. Implementation is overwritten * in RedSparkCore. * This implementation will automatically extend the temp file for the missing translates * * @param String Modulename * @param String Translation * * @return String Translation */ protected function _handleNonTranslated($module, $translation) { $key = $this->_prepareKey($module, $translation); // check if already added in this run if (in_array($translation, $this->_added)) { return $translation; } // Missing translate $missing = sprintf( "\t\t\n". //"\t\t\t\n". "\t\t\t\n". "\t\t\n", $key, //$this->_locale->getLanguage(), //$translation, $translation ); // Scaffolding marker inside translate file $scaffolding = "\t\t\n"; // Code for initial translate file $initial = "\n". "\n". "\n". "\t
\n". "\t\n". $scaffolding. "\t\n". "
" ; // Translation file $file = Path::get(Redspark_RsPath::FILE_DYNAMIC_TRANSLATION, Array('module' => $module)); // Check if translation files exists, or try to create it if (!file_exists($file)) { Path::createDir(Redspark_RsPath::DIR_DYNAMIC_TRANSLATION); file_put_contents($file, $initial); chmod($file, 0777); } // Update file contents $content = file_get_contents($file); $content = str_replace($scaffolding, $missing.$scaffolding, $content); file_put_contents($file, $content); // Copy file to data folder (as backup) $backup = Path::getDir(Redspark_RsPath::DIR_DATA_CUSTOM, Array('custom_path' => 'translate')).basename($file); if (!file_exists($backup)) { Path::createDir(Redspark_RsPath::DIR_DATA_CUSTOM, Array('custom_path' => 'translate')); } copy($file, $backup); // Clear translate cache $this->purgeCache(); $this->_added[] = $translation; return $translation; } /** * Recreate translation xml files. * called after translation-text was edited and saved * * -> to be implemented in concrete app * * @param String $module Modulename * @param String $locale Locale string * * @return Boolean */ public function createModuleTranslationXml($module, $locale=null) { return false; /* * To be implemented in App */ } /** * Get the number of translation entries * * @param String $locale all locales if null * * @return Int */ public function getTranslatedCount($locale=null) { /* Load all module translations */ $modules = Broker::getModuleBroker()->getInstalledModules(); foreach ($modules AS $mod => $app) { try { $path = $this->_getTranslationFileName($mod); $this->addTranslation($path); } catch (Exception $e) {} } /* Locale not available means 0 entries */ if (!$this->_adapter->isAvailable($locale)) { return 0; } $messages = $this->_adapter->getMessageIds($locale); return count($messages); } /** * Generate a key from the messageId by stripping special characters * * @param String $module Module name * @param String $messageId Untranslated text * * @return String Key */ protected function _prepareKey($module, $messageId) { /* * Filter special chars from key */ // Singleton static $filter = null; if (is_null($filter)) { $filter = new Zend_Filter_Alnum(true); } $key = $module.'-'.str_replace(' ','_',$filter->filter($messageId)); // Line-related bytes are not caught by Zend_Filter_Alnum $key = str_replace("\n",'',$key); $key = str_replace("\r",'',$key); $key = str_replace("\t",'',$key); // @todo Hash keys, that are too long // $filter = new Redspark_Filter_Hash(128); // $key = $filter->filter($key); return $key; } /** * Purge translate cache. This can be difficult, of cache is disabled * */ public function purgeCache() { // Must purge the whole backend, because memcache has no tagging support Broker::getCache()->purgeBackend('memcached'); // This seems not to work properly, because old stale cache remains if /* $adapter = $this->getAdapter(); if ($adapter->hasCache()) { $adapter->clearCache(); $adapter->removeCache(); }*/ } }