diff -r 90b7a52bea45 -r b0a4d179be85 includes/lang.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/lang.php Sat Nov 03 07:40:54 2007 -0400 @@ -0,0 +1,432 @@ +lang_id = LANG_DEFAULT; + $this->lang_code = 'neutral'; + return true; + } + if ( is_string($lang) ) + { + $sql_col = 'lang_code="' . $db->escape($lang) . '"'; + } + else if ( is_int($lang) ) + { + $sql_col = 'lang_id=' . $lang . ''; + } + else + { + $db->_die('lang.php - attempting to pass invalid value to constructor'); + } + + $lang_default = ( $x = getConfig('default_language') ) ? intval($x) : 'def'; + $q = $db->sql_query("SELECT lang_id, lang_code, last_changed, ( lang_id = $lang_default ) AS is_default FROM " . table_prefix . "language WHERE $sql_col OR lang_id = $lang_default ORDER BY is_default DESC LIMIT 1;"); + + if ( !$q ) + $db->_die('lang.php - main select query'); + + if ( $db->numrows() < 1 ) + $db->_die('lang.php - There are no languages installed'); + + $row = $db->fetchrow(); + + $this->lang_id = intval( $row['lang_id'] ); + $this->lang_code = $row['lang_code']; + $this->lang_timestamp = $row['last_changed']; + } + + /** + * PHP 4 constructor. + * @param int|string Language ID or code to load. + */ + + function Language($lang) + { + $this->__construct($lang); + } + + /** + * Fetches language strings from the database, or a cache file if it's available. + * @param bool If true (default), allows the cache to be used. + */ + + function fetch($allow_cache = true) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $lang_file = ENANO_ROOT . "/cache/lang_{$this->lang_id}.php"; + // Attempt to load the strings from a cache file + if ( file_exists($lang_file) && $allow_cache ) + { + // Yay! found it + $this->load_cache_file($lang_file); + } + else + { + // No cache file - select and retrieve from the database + $q = $db->sql_unbuffered_query("SELECT string_category, string_name, string_content FROM " . table_prefix . "language_strings WHERE lang_id = {$this->lang_id};"); + if ( !$q ) + $db->_die('lang.php - selecting language string data'); + if ( $row = $db->fetchrow() ) + { + $strings = array(); + do + { + $cat =& $row['string_category']; + if ( !is_array($strings[$cat]) ) + { + $strings[$cat] = array(); + } + $strings[$cat][ $row['string_name'] ] = $row['string_content']; + } + while ( $row = $db->fetchrow() ); + // all done fetching + $this->merge($strings); + } + else + { + $db->_die('lang.php - No strings for language ' . $this->lang_code); + } + } + } + + /** + * Loads a file from the disk cache (treated as PHP) and merges it into RAM. + * @param string File to load + */ + + function load_cache_file($file) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // We're using eval() here because it makes handling scope easier. + + if ( !file_exists($file) ) + $db->_die('lang.php - requested cache file doesn\'t exist'); + + $contents = file_get_contents($file); + $contents = preg_replace('/([\s]*)<\?php/', '', $contents); + + @eval($contents); + + if ( !isset($lang_cache) || ( isset($lang_cache) && !is_array($lang_cache) ) ) + $db->_die('lang.php - the cache file is invalid (didn\'t set $lang_cache as an array)'); + + $this->merge($lang_cache); + } + + /** + * Merges a standard language assoc array ($arr[cat][stringid]) with the master in RAM. + * @param array + */ + + function merge($strings) + { + // This is stupidly simple. + foreach ( $strings as $cat_id => $contents ) + { + if ( !is_array($this->strings[$cat_id]) ) + $this->strings[$cat_id] = array(); + foreach ( $contents as $string_id => $string ) + { + $this->strings[$cat_id][$string_id] = $string; + } + } + } + + /** + * Imports a JSON-format language file into the database and merges with current strings. + * @param string Path to the JSON file to load + */ + + function import($file) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if ( !file_exists($file) ) + $db->_die('lang.php - can\'t import language file: string file doesn\'t exist'); + + $contents = trim(@file_get_contents($file)); + + if ( empty($contents) ) + $db->_die('lang.php - can\'t load the contents of the language file'); + + // Trim off all text before and after the starting and ending braces + $contents = preg_replace('/^([^{]+)\{/', '{', $contents); + $contents = preg_replace('/\}([^}]+)$/', '}', $contents); + + $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); + $langdata = $json->decode($contents); + + if ( !is_array($langdata) ) + $db->_die('lang.php - invalid language file'); + + if ( !isset($langdata['categories']) || !isset($langdata['strings']) ) + $db->_die('lang.php - language file does not contain the proper items'); + + $insert_list = array(); + $delete_list = array(); + + foreach ( $langdata['categories'] as $category ) + { + if ( isset($langdata['strings'][$category]) ) + { + foreach ( $langdata['strings'][$category] as $string_name => $string_value ) + { + $string_name = $db->escape($string_name); + $string_value = $db->escape($string_value); + $category_name = $db->escape($category); + $insert_list[] = "({$this->lang_id}, '$category_name', '$string_name', '$string_value')"; + $delete_list[] = "( lang_id = {$this->lang_id} AND string_category = '$category_name' AND string_name = '$string_name' )"; + } + } + } + + $delete_list = implode(" OR\n ", $delete_list); + $sql = "DELETE FROM " . table_prefix . "language_strings WHERE $delete_list;"; + + // Free some memory + unset($delete_list); + + // Run the query + $q = $db->sql_query($sql); + if ( !$q ) + $db->_die('lang.php - couldn\'t kill off them old strings'); + + $insert_list = implode(",\n ", $insert_list); + $sql = "INSERT INTO " . table_prefix . "language_strings(lang_id, string_category, string_name, string_content) VALUES\n $insert_list;"; + + // Free some memory + unset($insert_list); + + // Run the query + $q = $db->sql_query($sql); + if ( !$q ) + $db->_die('lang.php - couldn\'t insert strings in import()'); + + // YAY! done! + // This will regenerate the cache file if possible. + $this->regen_caches(); + } + + /** + * Refetches the strings and writes out the cache file. + */ + + function regen_caches() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $lang_file = ENANO_ROOT . "/cache/lang_{$this->lang_id}.php"; + + // Refresh the strings in RAM to the latest copies in the DB + $this->fetch(false); + + $handle = @fopen($lang_file, 'w'); + if ( !$handle ) + // Couldn't open the file. Silently fail and let the strings come from the database. + return false; + + // The file's open, that means we should be good. + fwrite($handle, 'var_export_string($this->strings); + if ( empty($exported) ) + // Ehh, that's not good + $db->_die('lang.php - var_export_string() failed'); + + fwrite($handle, $exported . '; ?>'); + + // Update timestamp in database + $q = $db->sql_query('UPDATE ' . table_prefix . 'language SET last_changed = ' . time() . ' WHERE lang_id = ' . $this->lang_id . ';'); + if ( !$q ) + $db->_die('lang.php - updating timestamp on language'); + + // Done =) + fclose($handle); + } + + /** + * Calls var_export() on whatever, and returns the function's output. + * @param mixed Whatever you want var_exported. Usually an array. + * @return string + */ + + function var_export_string($val) + { + ob_start(); + var_export($val); + $contents = ob_get_contents(); + ob_end_clean(); + return $contents; + } + + /** + * Fetches a language string from the cache in RAM. If it isn't there, it will call fetch() again and then try. If it still can't find it, it will ask for the string + * in the default language. If even then the string can't be found, this function will return what was passed to it. + * + * This will also templatize strings. If a string contains variables in the format %foo%, you may specify the second parameter as an associative array in the format + * of 'foo' => 'foo substitute'. + * + * @param string ID of the string to fetch. This will always be in the format of category_stringid. + * @param array Optional. Associative array of substitutions. + * @return string + */ + + function get($string_id, $substitutions = false) + { + // Extract the category and string ID + $category = substr($string_id, 0, ( strpos($string_id, '_') )); + $string_name = substr($string_id, ( strpos($string_id, '_') + 1 )); + $found = false; + if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) + { + $found = true; + $string = $this->strings[$category][$string_name]; + } + if ( !$found ) + { + // Ehh, the string wasn't found. Rerun fetch() and try again. + $this->fetch(); + if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) + { + $found = true; + $string = $this->strings[$category][$string_name]; + } + if ( !$found ) + { + // STILL not found. Check the default language. + $lang_default = ( $x = getConfig('default_language') ) ? intval($x) : $this->lang_id; + if ( $lang_default != $this->lang_id ) + { + if ( !is_object($this->default) ) + $this->default = new Language($lang_default); + return $this->default->get($string_id, $substitutions); + } + } + } + if ( !$found ) + { + // Alright, it's nowhere. Return the input, grumble grumble... + return $string_id; + } + // Found it! + // Perform substitutions. + // if ( is_array($substitutions) ) + // die('
' . print_r($substitutions, true) . '
'); + if ( !is_array($substitutions) ) + $substitutions = array(); + return $this->substitute($string, $substitutions); + } + + /** + * Processes substitutions. + * @param string + * @param array + * @return string + */ + + function substitute($string, $subs) + { + preg_match_all('/%this\.([a-z0-9_]+)%/', $string, $matches); + if ( count($matches[0]) > 0 ) + { + foreach ( $matches[1] as $i => $string_id ) + { + $result = $this->get($string_id); + $string = str_replace($matches[0][$i], $result, $string); + } + } + preg_match_all('/%config\.([a-z0-9_]+)%/', $string, $matches); + if ( count($matches[0]) > 0 ) + { + foreach ( $matches[1] as $i => $string_id ) + { + $result = getConfig($string_id); + $string = str_replace($matches[0][$i], $result, $string); + } + } + foreach ( $subs as $key => $value ) + { + $subs[$key] = strval($value); + $string = str_replace("%{$key}%", "{$subs[$key]}", $string); + } + return "L $string"; + } + +} // class Language + +?>