. */ class it_text { var $actlanguage; # Selected language var $defaultlanguage; # Browser language var $languages = array(); # Active languages var $languages_available = array(); # Available languages var $statictext = array(); # Text array, read from php file on init /** * Constructor * Loads all texts.php in include path for translated labels. Singleton; if instanciated mutiple times, texts are merged * Example texts.php: array('en'=>"English", 'de'=>"Deutsch"), 'edit'=>array('en'=>"Edit", 'de'=>("Editieren"))); * @param $p['cookiename'] optional cookie name (default: 'LANGUAGE') * @param $p['debug'] optional debug mode: display label of unknown texts, set to 'label' to always display labels instead of actual text * @param $p['fallbacklanguage'] optional language to use for undefined texts (useful for partially translated projects) * @param $p['forcelanguage'] optional language to use instead of user's preferred language * @param $p['phpfile'] optional texts file(s), default: all texts.php in include path */ function it_text($p = null) { $this->p = (array)$p + array('cookiename' => 'LANGUAGE', 'debug' => (EDC('label') ? "label" : "")); $phpfiles = array(); if ($p['phpfile']) $phpfiles = (array)$p['phpfile']; else { # Find texts.php in path (abs path in case we need to save) foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $dir) if (file_exists($phpfile = "$dir/texts.php")) $phpfiles[] = $phpfile; } # Read and merge texts from php files if none defined yet foreach ($phpfiles as $phpfile) { $oldtexts = $this->statictexts; if (is_array($ret = @include($phpfile))) $this->statictext += $ret; else $this->statictext = $oldtexts + $this->statictext; # FIXME: compatibility mode } # Get array of supported languages and their names $this->languages_available = (array)$this->statictext['_']; foreach($this->languages_available as $code => $languagename) { # Only use a language in browser/cookie detection below if it's not disabled by a leading '-' if (substr($languagename, 0, 1) != '-') { $this->languages[$code] = $languagename; if (!$this->actlanguage) $this->initlang($code, "setting failsafe language"); } } # Set our default language according to browser preference if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { foreach(explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $code) if ($this->initlang($code, "setting language from browser") || $this->initlang(substr($code, 0, 2), "setting language family from browser")) break; } $this->defaultlanguage = $this->actlanguage; $this->initlang(it::match('\.([a-z]{2})\.[^./]+$', $_SERVER['PHP_SELF']), "setting language from url override"); $this->initlang($this->languages[$_COOKIE[$this->p['cookiename']]], "setting language from cookie"); $this->initlang($this->p['forcelanguage'], "setting language from programmer override"); # Make this object available under $GLOBALS['it_text'], or add my texts to $GLOBALS['it_text'] if it exists if (!$GLOBALS['it_text']) $GLOBALS['it_text'] =& $this; else $GLOBALS['it_text']->statictext += $this->statictext; } # internal: overwrite language setting if code is valid, return success function initlang($code, $debugmsg) { if ($this->languages[$code]) $this->actlanguage = $code; return $this->languages[$code]; } /** * Instanciate singleton if necessary */ function init() { if (!$GLOBALS['it_text']) new it_text; } /** * INTERNAL function for T(): : Return translated text in the selected language */ function text($label, $language = null) { if ($this->p['debug'] === 'label') return $label; if (!isset($language)) $language = $this->actlanguage; if (isset($this->statictext[$label][$language])) return $this->statictext[$label][$language]; elseif ($this->p['fallbacklanguage'] && isset($this->statictext[$label][$this->p['fallbacklanguage']])) return $this->statictext[$label][$this->p['fallbacklanguage']]; if ($fh = fopen($GLOBALS['ULTRAHOME'] . "/log/text_log", "a")) { fputs($fh, date("Y-m-d H:i:s") . "\t" . $_SERVER['REQUEST_URI'] . "\t" . $label . "\t" . $language . "\t" . it::replace(array('auto_prepend\S+\s+'=>''), it_debug::backtrace()) . "\n"); fclose($fh); } return $this->p['debug'] ? "$label ($language)" : ''; } /** * INTERNAL function for ET(): Return translated text with values replaced */ function etext($label, $values = null, $language = null) { return $this->transmogrify($this->text($label, $language), $values); } /** * INTERNAL function for T_set_language() */ function set_language($language, $setcookie = true) { # If $language is unknown, delete the cookie if ($this->languages_available[$language]) { if (!$this->languages[$language]) debug('Selected an existing but currently disabled language!', 6); $this->actlanguage = $language; if ($setcookie) SetCookie($this->p['cookiename'], $this->actlanguage, time() + 31536000, '/'); # 1 year } else { $this->actlanguage = $this->defaultlanguage; if ($setcookie) SetCookie($this->p['cookiename'], '', time() + 31536000, '/'); } } /** * INTERNAL function for T_lang(): Get active language */ function get_language() { return $this->actlanguage; } /** * INTERNAL function for T_exists(): Check if a text entry for a specific label exists */ function text_exists($label, $language = null) { return isset($this->statictext[$label][isset($language) ? $language : $this->actlanguage]); } /** * Create / overwrite a text in the selected language. Call dump_php() to make the change permanent. * @param $label Label of text to change * @param $text New text to set * @param $language Optional language that is to be manipulated */ function set($label, $text = null, $language = null) { if (!isset($language)) $language = $this->actlanguage; $this->statictext[$label][$language] = $text; } /** * Replaces variables of the form {obj.var} with value, e.g. {user.name} * NOTE: Invalid object names or non-existing variables are simply deleted. */ function transmogrify($text, $values = null) { while (preg_match('/{([\w.]+)}/', $text, $regs)) { $path = explode('.', $regs[1]); if ($values) $value =& $values; else $value =& $GLOBALS; # Recurse into nested arrays/object members foreach ($path as $key) { if (is_object($value)) $value =& $value->$key; else $value =& $value[$key]; } $text = str_replace($regs[0], $value, $text); } return $text; } /** * Re-create php text file from $this->statictext * @return true if successful, false if not (usually if file is not writeable by user www) */ function dump_php() { $result = false; # Special sorting: natural, but _ is the first entry $keys = array_keys($this->statictext); natsort($keys); foreach($keys as $key) $text[$key] = $this->statictext[$key]; $this->statictext = array_merge(array('_' => $text['_']), $text); $oldmask = umask(002); if ($f = fopen($this->p['phpfile'], 'w')) { $result = (fputs($f, 'statictext, true), array("=> \n array (" => "=> array(", "array (\n '_'" => "array(\n'_'", "\n ),\n " => "\n),\n", "\n ),\n" => "\n)\n")) . ";\n?>\n") !== false); fclose($f); } umask($oldmask); return $result; } } /* End class it_text */ ?>