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();
}*/
}
}