Toolserver:TSMessages.php/source

This page was moved from the Toolserver wiki.
Toolserver has been replaced by Toolforge. As such, the instructions here may no longer work, but may still be of historical interest.
Please help by updating examples, links, template links, etc. If a page is still relevant, move it to a normal title and leave a redirect.

<?php
/*
Script by Duesentrieb
Modified by Luxo


*/
class TSLanguageSelector {
    function __construct($default = "en", $varname = "lang", $cookiePrefix = "", $cookiePath = NULL, $cookieDomain = NULL) {
	$this->defaultLanguage = $default;
	$this->varname = $varname;
	$this->cookiePrefix = $cookiePrefix;
	$this->cookiePath = $cookiePath;
	$this->cookieDomain = $cookieDomain;
	
	if (isset($_REQUEST[$this->varname])) {
		$this->language = $_REQUEST[$this->varname];

		setcookie( $this->cookiePrefix . $this->varname,
			$this->language,
			time() + 3024000, //+5 weeks;
			$this->cookiePath,
			$this->cookieDomain );
	} else { 
		$this->language = $this->getUserLanguageFromBrowser();
	}
    }

    function getUserLanguage() {
	return $this->language;
    }

    function getUserLanguageFromBrowser()
    {
      #http://www.w3.org/International/articles/language-tags/
      $lang = strtolower(trim($_SERVER["HTTP_ACCEPT_LANGUAGE"]));
      if(strstr($lang,",")) {
        $lang = substr($lang,0,strpos($lang,","));
      }
      if(strstr($lang,"-")) {
        $lang = substr($lang,0,strpos($lang,"-"));
      }
      return $lang;
    }

    function getSelectorFormHTML($messages, $auto_submit = true, $name = "languageselector") {

	$html = "";

	$html .= "<form name=\"$name\" id=\"$name\">";
	$html .= $this->getSelectorHTML($messages,$auto_submit);
	$html .= "<input type=\"submit\" value=\"".$messages->getMessageEscaped("Ok")."\" id=\"".$name."submit\"/> ";
	$html .= "</form>";
  if($auto_submit == true) $html .= "<script type='text/javascript'>document.getElementById(\"".$name."submit\").style.display = \"none\";</script>";

	return $html;
    }

    function getSelectorHTML($messages,$auto_submit) {
	$html = "";

	$languages = $messages->getAvailableLanguages();
  
	$html.= "\n\t\t<select name=\"".htmlspecialchars($this->varname)."\" id=\"".htmlspecialchars($this->varname)."\"";
  if($auto_submit == true) $html.= " OnChange=\"this.form.submit();\"";
  $html.=">\n";

	foreach ($languages as $choice => $name) {
	    $sel = $choice == $this->getUserLanguage() ? " selected=\"selected\"" : "";
	    $html.=  "\t\t\t<option value=\"".htmlspecialchars($choice)."\"$sel>".htmlspecialchars($name)."</option>\n";
	}

	$html.= "</select>";
	return $html;
    }
    
    function getSelectorListHTML($messages) {
      $html = "";
      $languages = $messages->getAvailableLanguages();
      foreach($languages as $choice => $name) {
        $html .= "<a href=\"?".htmlspecialchars($this->varname)."=".htmlspecialchars($choice)."\" title=\"".htmlspecialchars($name)."\">".htmlspecialchars($choice)."</a> | ";
      }
      return $html;
    }

    static function getSelector() {
	static $selector = NULL;
	if (!$selector) $selector = new Selector(); #TODO: use global config vars!

	return $selector;
    }


}

class TSMessagesFactory {
  
  function __construct($file = NULL, $connection = NULL, $prefix = NULL, $multilang = true, $memcachedserver = "localhost", $memcachedport = 11211) {
      $this->file = $file;
      $this->connection = ($connection == NULL) ? self::db_connect() : $connection;
      $this->prefix = $prefix;
      $this->useMultiLanguageFile = $multilang;
      $this->doublecheck = array();
      $this->memcachedserver = $memcachedserver;
      $this->memcachedport = $memcachedport;
      $this->keys = array();

  }
  
  static function db_connect() 
  {
    static $connection = NULL;
    if(!$connection) {
      $path = "/home/".get_current_user()."/.my.cnf";
      $x = parse_ini_file($path);
      $s = 'sql-s2';
      $connection = mysql_connect($s, $x['user'],$x['password']);
      if (!$connection) throw new Exception("cannot connect to '$s' using username '".$x['user']."'");
    }
    return $connection;  
  }

  static function memcached_connect() 
  {
    static $m = NULL;
    if(class_exists("Memcached")) {
      if(!$m) {
        $m = new Memcached();
        $m->addServer(self::$memcachedserver, self::$memcachedport);
      }     
    } else { $m = false; }
    return $m;  
  }

  
  function createDefaultMessageObject($tool, $lang = NULL) {
      if (is_string($tool)) $tool = array( $tool, "toolserver");
      if ($lang == NULL) $lang = ToolLanguageSelector::getSelector();
      if (is_object($lang)) $lang = $lang->getUserLanguage();
      if (is_string($lang)) $lang = array( $lang, "en" );
      
      foreach($tool as $tn => $tk) {
        if(is_array($tk)) {
          $this->keys[$tn] = $tk;
          $tool[$tn] = $tn;
        } else if(is_string($tn)) {
          $tool[$tn] = $tn;
        }
      }
      
      return $this->createMessageObject($tool, $lang, NULL);
  }


  function createMessageObject($tool, $lang, $parent = NULL) {
      if (is_array($lang)) {
	  $m = NULL;
	  $langs = array_reverse($lang);
	  foreach ($langs as $lang) {
 	      $m = $this->createMessageObject($tool, $lang, $parent);
	      $parent = $m;    
	  }

	  return $m;
      }

      if (is_array($tool)) {
	  $m = NULL;
	  $tools = array_reverse($tool);
	  foreach ($tools as $tool) {
 	      $m = $this->createMessageObject($tool, $lang, $parent);
	      $parent = $m; 
	  }

	  return $m;
      }


      
      if($this->doublecheck[$lang][$tool] != true)
      {
        if ($this->file) $m = $this->createFileMessageObject($tool, $lang, $parent);
        else $m = $parent;
    
        if ($this->connection) $m = $this->createDatabaseMessageObject($tool, $lang, $m);
 
        $this->doublecheck[$lang][$tool] = true;    
      } else {
        $m = $parent;
      }
    
        return $m;
      
  }

  protected function createFileMessageObject($tool, $lang, $parent = NULL) {
      if ($this->useMultiLanguageFile) 
	  return new MultiLanguagePhpFileMessages($this->file, $tool, $lang, $parent, $this->prefix);
      else 
	  return new SingleLanguagePhpFileMessages($this->file, $tool, $lang, $parent, $this->prefix);
  }

  protected function createDatabaseMessageObject($tool, $lang, $parent = NULL) {
        return new DatabaseMessages($this->connection, $tool, $lang, $parent, $this->prefix, $this->keys);
  } 
}

class TSMessages {
  var $parent;
  var $prefix;
  var $messages;
  var $tool;
  var $language;
  


  function __construct($tool, $language, $messages, TSMessages $parent = NULL, $prefix = NULL) {
    $this->parent = $parent;
    $this->prefix = $prefix;
    $this->tool = $tool;
    $this->language = $language;
    $this->messages = $messages;
  }
  

  function dump() {
    print get_class($this);
    
    print "#{$this->tool}";
    if ($this->prefix) print "(prefix:$prefix)";
    
    print ":{$this->language}";

    if ($this->parent) {
	print " -> ";
	$this->parent->dump();
    }
  }

  function getMessageEscaped($key,$replacers=array(),$parse=true) {
    $m = $this->getMessage($key,$replacers,$parse);
    return $this->escape($m);
  }

  function escape($s) {
    return htmlspecialchars($s);
  }

  function getMessage($key,$replacers=array(),$parse=true) { 
    if ($this->prefix!==NULL) $key = $prefix.$key;

    if (isset($this->messages[$key])) 
      $msg = $this->messages[$key];//this language text
    else
      if ($this->parent) $msg = $this->parent->getMessage($key,array(),false);//parent language text
      else $msg = "*$key*";//key not found
    
    if($parse == true)
      $msg = $this->replace_wildcard($msg,$replacers);
      $msg = $this->parse_plural($msg);
      $msg = $this->set_bold($msg);
      $msg = $this->set_italic($msg);
    return $msg;
  }
  
  function replace_wildcard($msg,$replacers) 
  {
  
    $r = 0; //array-counter
    $c = 1; //text-counter
    while($c != false)
    {
      if(!$replacers[$r])
        $replacers[$r] = '*$'.$c.'*';
      $msg = str_replace('$'.$c,$replacers[$r],$msg,$count);
      if($count != 0) {
        $r++; $c++;
      } else {
        $c = false;
      }
    }
    return $msg;
  }
  
  function parse_plural($msg) 
  {
    $rgx_search  = "/\{\{PLURAL:([0-9]{1,2})\|([^\}\|]*)\|([^\}\|]*)\}\}/ei";
    do
      $msg = preg_replace($rgx_search,'$this->plural_select("\\1","\\2","\\3")',$msg,-1,$ct);
    while($ct != 0);
    
    return $msg;
    
  }
  
  function plural_select($nr,$singular,$plural) 
  {
    settype($nr,"int");
     if($nr == 1)
      return $singular;
    else
      return $plural;
  }
  function set_bold($msg) 
  {
    $rgx_search  = "/'''(.*)'''/U";
    do
      $msg = preg_replace($rgx_search,'<b>$1</b>',$msg,-1,$ct);
    while($ct != 0);
    return $msg;
  }
  
  function set_italic($msg) 
  {
    $rgx_search  = "/''(.*)''/U";
    do
      $msg = preg_replace($rgx_search,'<i>$1</i>',$msg,-1,$ct);
    while($ct != 0);
    return $msg;
  }

  function getKeys() {
    $keys = array_keys($this->messages);
    if ($this->parent) {
      $pkeys = $this->parent->getKeys();
      $keys = array_unique(array_merge($keys, $pkeys));
    }
    sort($keys);

    return $keys;
  }
  
  function getAvailableLanguages() {  
    $usedsource = TSMessages::usedsource(NULL,NULL,NULL,true);
    $languages = array();
    if($usedsource['db'] == 1) $languages = $this->getLanguagesFromDB($languages);
    if($usedsource['file'] == 1) $languages = $this->getLanguagesFromDir($languages,$usedsource['path']);
    if($usedsource['multilang'] == 1) $languages = $this->getLanguagesFromFile($languages,$usedsource['path']);
    

    $sql  =  "SELECT `lang`,`native_name` FROM toolserver.language WHERE";    
    foreach($languages as $language) {
      $sql .= " `lang` = '" . mysql_real_escape_string($language)."' OR";
    }
    $sql = substr($sql,0,-2);
    $r = mysql_query( $sql, $this->connection );
    if ( !$r ) throw new Exception( mysql_error() . " (" . mysql_errno() . ")");
    while ($row = mysql_fetch_array($r)) {
      $langname[$row["lang"]] = $row["native_name"];
    }
    foreach($languages as $language) {
      $languages[$language] = $langname[$language];
    }
    return $languages;
  }
  
  private function getLanguagesFromDB($languages) {
    $sql  =  "SELECT `language` FROM toolserver.message ";
    $sql .= "WHERE `component` = '" . mysql_real_escape_string($this->maintool) . "'";
  
    $r = mysql_query( $sql, $this->connection );
    if ( !$r ) throw new Exception( mysql_error() . " (" . mysql_errno() . ")");
    while ( $row = mysql_fetch_assoc( $r ) ) {
      $k = $row["language"];
      $languages[$k] = $k; // $languages[de] = de
    }
    return $languages;
  }
  
  private function getLanguagesFromDir($languages,$curl) {
    $dh = opendir($curl);
    while(!is_bool($file = readdir($dh)))
    {
      if(substr($file, -9) == ".i18n.php")
      {
        $k = substr($file,strrpos($file,"-")+1,-9);
        $languages[$k] = $k;
      }
    }
    closedir($dh);
    return($languages);
  }
  
  private function getLanguagesFromFile($languages,$curl) {
    include($curl);
    if (!isset($messages)) throw new Exception("including $file did not define \$messages");
    foreach($messages as $lang => $x) {
      $languages[$lang] = $lang;
    } 
    return($languages);
  }
  
  static function usedsource($x,$filepath = NULL, $multilang = NULL, $return = false)
  {
    static $source = array("db" => 0, "file" => 0, "multilang" => NULL, "path" => NULL);
    switch($x) {
      case "db":
        $source['db'] = 1;
        break;
      case "file":
        $source['file'] = 1;
        $source['path'] = $filepath;
        break;
      case "multilang":
        $source['multilang'] = 1;
        $source['path'] = $multilang;
        break;           
    }
    if($return == true) return $source;
  }
  
}

class MultiLanguagePhpFileMessages extends TSMessages {

  function __construct($file, $tool, $language, TSMessages $parent = NULL, $prefix = NULL) {
    parent::__construct( $tool, $language, self::loadMessages($file, $tool, $language), $parent, $prefix );
  }
  
  static function loadMessages($file, $tool, $language) {
    if (is_dir($file)) {
      $file = "$file/$tool.i18n.php";
    }

    if (!file_exists($file)) return array();

    include($file);

    if (!isset($messages)) throw new Exception("including $file did not define \$messages");
    TSMessages::usedsource("multilang",NULL,$file);
    return $messages[$language];
  }  
}

class SingleLanguagePhpFileMessages extends TSMessages {

  function __construct($filebase, $tool, $language, TSMessages $parent = NULL, $prefix = NULL) {
    parent::__construct( $tool, $language, self::loadMessages($filebase, $tool, $language), $parent, $prefix );
  }
  
  static function loadMessages($filebase, $tool, $language) {
    if (is_dir($filebase)) {
      $file = "$filebase/$tool-$language.i18n.php";
    } else if (!file_exists($filebase)) {
      $file = "$filebase-$language.i18n.php";
    } else {
      $file = $filebase;
    }
    
    if(is_dir(dirname($file))) TSMessages::usedsource("file",dirname($file));
    if (!file_exists($file)) return array();

    include($file);
    if (!isset($messages)) throw new Exception("including $file did not define \$messages");
    
    return $messages;
  }  
}

class DatabaseMessages extends TSMessages {
  
  static $messageDatabase = "toolserver";
  static $messageTable = "message";


  function __construct($connection, $tool, $language, TSMessages $parent = NULL, $prefix = NULL, $toolkeys = NULL) {
    parent::__construct( $tool, $language, self::loadMessages($connection, $tool, $language, $toolkeys), $parent, $prefix, $toolkeys );
  $this->connection = $connection;
  $this->maintool   = $tool;
  }

  static function loadMessages($connection, $tool, $language, $toolkeys) {
    $m = TSMessagesFactory::memcached_connect();
    if(is_array($toolkeys[$tool]))sort($toolkeys[$tool]);
    if($m !== false) {
      $memcached_key = $tool."#".$language;
      if(is_array($toolkeys[$tool])) $memcached_key .= "#".md5(implode("+",$toolkeys[$tool]));
      $ret = $m->get($memcached_key);
      if($ret) return $ret;
    }
    $db = self::$messageDatabase;
    $tb = self::$messageTable;
    $sql = "SELECT name, message FROM $db.$tb ";
    $sql .= " WHERE component = '" . mysql_real_escape_string($tool) . "'";
    $sql .= " AND language = '" . mysql_real_escape_string($language) . "'";
    if(is_array($toolkeys[$tool])) {
      if(count($toolkeys[$tool]) > 0){
        $sql .= " AND (";
        foreach($toolkeys[$tool] as $$toolkey) {
          $sql .= "name = '" . mysql_real_escape_string($$toolkey) . "' OR ";
        }
        $sql = substr($sql,0,-4).")";
      } else { $sql .= " LIMIT 0 , 200"; }
    } else { $sql .= " LIMIT 0 , 200"; }

    $r = mysql_query( $sql, $connection );
    if ( !$r ) throw new Exception( mysql_error() . " (" . mysql_errno() . ")");

    $messages = array();

    while ( $row = mysql_fetch_assoc( $r ) ) {
      $k = $row["name"];
      $messages[$k] = $row["message"];
    }
    TSMessages::usedsource("db");
    if($m !== false) $m->set($memcached_key, $messages, time() + 7200); //2h cached
    self::testfunction($sql);
    return $messages;
    
  }
 
  static function testfunction($sql,$ret=false)
  {
    static $text = "";
    $text .= $sql."\n<br>";
    if($ret == true) return $text;
  }
  
}

?>

Category:Documentation