<?php
/**
*
* @author Benjamin Gillissen <hide@address.com>
*
* **************************************************************
Copyright (C) 2009 Benjamin Gillissen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details at:
http://www.gnu.org/copyleft/gpl.html
* **************************************************************
*/
class langs {
private static $charset;
private static $CC;
private static $_LANG;
private static $_DB;
private static $_DICO;
private static $DICACHE;
public static function load(){
if ( isset(self::$_LANG) ){ return TRUE; }
if ( ! isset(self::$CC) ){
$run = Array(client_configs::SESSION=>'profile');
$store = Array(client_configs::PROFILE=>'site_profile');
$run_update = Array(client_configs::GET=>'', client_configs::POST=>'');
$store_update= Array(client_configs::POST=>'');
self::$CC = new client_configs($run, $store, $run_update, $store_update);
unset($run, $store, $run_update, $store_update);
}
$lang = self::negotiateLanguage();
$class = 'lang_'.$lang;
self::$_LANG = new $class();
self::$charset = self::negotiateCharset();
if ( FALSE === function_exists('iconv') AND FALSE === function_exists('libiconv') ){
errors::raise('Missing PHP feature : libiconv, No charset convertion will be possible.', CORE_LOG_WARNING, 'LANG');
}
if ( ! headers_sent($file, $line) ){
//here we know, lang and charset. let's make it know to client browser
header("Content-type: text/html; charset=".self::$charset);
errors::raise('Langs is using lang : '.self::$_LANG->lang().', charset : '.self::$charset, CORE_LOG_NOTICE, 'LANG');
self::recode_from_client();
} else {
errors::raise('Langs could not send Content-Type Header, output started at : '.$file.':'.$line, CORE_LOG_ERROR, 'LANG');
}
return TRUE;
}
public static function getlangs(){ return configs::get('lang', 'langs'); }
public static function islang($lang){ return (FALSE !== array_search($lang, self::getlangs())); }
public static function getcharsets($lang=NULL){
if ( $lang !== NULL ){
if ( FALSE === self::islang($lang) ){ return FALSE; }
//CORE::inclass("lang_$lang");
$cb = "lang_$lang::charsets";
errors::raise('lang::getcharsets('.$lang.') cb => '.$cb, CORE_LOG_ERROR, 'LANG');
$r = @call_user_func($cb);
errors::raise('cb result => '.print_r($r, TRUE), CORE_LOG_ERROR, 'LANG');
if ( !empty($r) ){ return split(',', $r); }
return FALSE;
}
if ( ! isset(self::$_LANG) ){ self::load(); }
return split(',', self::$_LANG->charsets() );
}
public static function charset(){
if ( !isset(self::$_LANG) ){ self::load(); }
return self::$charset;
}
public static function lang(){
if ( !isset(self::$_LANG) ){ self::load(); }
return self::$_LANG->lang();
}
public static function fallback(){
if ( !isset(self::$_LANG) ){ self::load(); }
return self::$_LANG->fallback();
}
private static function negotiateLanguage(){
if ( self::$CC->is_updated('lang') ){
$new = self::$CC->get_updated('lang');
if ( FALSE === self::islang($new) ){
unset($new);self::$CC->del_update('lang');
} else {
//store to sess, only profile page update profile eh
self::$CC->store_updated('lang');
}
} elseif ( self::$CC->is_stored('lang') ){
$new = self::$CC->get_stored('lang');
if ( FALSE === self::islang($new) ){ unset($new);self::$CC->del_stored('lang'); }
} elseif ( isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ){
//errors::raise("Negotiating Language :: ".strtoupper($_SERVER['HTTP_ACCEPT_LANGUAGE']), CORE_LOG_NOTICE, 'LANG');
$new = self::negotiate(self::getlangs(), strtoupper($_SERVER['HTTP_ACCEPT_LANGUAGE']));
if ( FALSE !== $new ){ return $new; }
unset($new);
}
if ( ! isset($new) ){ $new = configs::get('lang', 'baselang'); }
if ( FALSE === $new ){
errors::raise('Active lang could not be determined !, plz check your lang.opt.php file', CORE_LOG_ERROR, 'LANG');
}
if ( FALSE === self::islang($new) ){ $new = 'EN'; }
return $new;
}
private static function negotiateCharset(){
$langcharset = self::getcharsets();
if ( self::$CC->is_updated('charset') ){
$new = self::$CC->get_updated('charset');
if ( FALSE === array_search($new, $langcharset) ){
unset($new);self::$CC->del_update('charset');
} else {
//store to sess, only profile page update profile eh
self::$CC->store_updated('charset');
}
} elseif ( self::$CC->is_stored('charset') ){
$new = self::$CC->get_stored('charset');
if ( FALSE === array_search($new, $langcharset) ){ unset($new);self::$CC->del_stored($var); }
} elseif ( isset($_SERVER['HTTP_ACCEPT_CHARSET']) ){
//errors::raise("Negociating Charset :: ".strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']), CORE_LOG_NOTICE, 'LANG');
$new = self::negotiate($langcharset, strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']));
if ( FALSE === $new ){ unset($new); }
}
if ( ! isset($new) ){ $new = $langcharset[0]; }
return $new;
}
private static function negotiate($opts, $accept){
$accepts = split(',', $accept);
foreach($accepts as $k => $opt ){
$opt = array_map('trim', explode(';', $opt));
$o = $opt[0];
$q = 1;
if ( isset($opt[1]) ){ $q = (float) str_replace('Q=', '', $opt[1]); }
if ( FALSE !== array_search($o, $opts) ){
$matches[$o] = ($q * 1000) - @count($matches);
}
}
if ( isset($matches) ){
asort($matches, SORT_NUMERIC);
///errors::raise("Negotiation Results :: ".print_r($matches, TRUE), CORE_LOG_DEBUG, 'LANG');
$matches = array_keys($matches);
return end($matches);
}
return FALSE;
}
public static function dico_translate($ref, $args, $dico, $forcefb=NULL){
if ( !isset(self::$_LANG) ){ self::load(); }
if ( !chrono::isinit('dico') ){ chrono::init('dico'); }
$chr = chrono::start('dico');
if ( !isset(self::$DICACHE[$dico]) ){
$ps = split(":", configs::get('lang', 'dicos'));
if ( isset($forcefb) ){ $lang = $forcefb; } else { $lang = self::lang(); }
foreach($ps as $k=>&$path){ $path .= '/'.$lang; }
$file = CORE::getdeps($ps, $dico, NULL,'dico', 'htm');
unset($ps);
if ( FALSE === $file ){ chrono::pause('dico', $chr);return FALSE; }
$obj = new dico_tidy();
if ( FALSE === $obj->load($file) ){ chrono::pause('dico', $chr);return FALSE; }
self::$DICACHE[$dico] = $obj->readall();
}
if ( is_array($args) ){ $cref="S_"; } else { $cref="W_"; }
$cref .= md5(html_entity_decode($ref));
if ( isset(self::$DICACHE[$dico][$cref]) ){
$o = self::$DICACHE[$dico][$cref];
if ( is_array($args) ){ foreach($args as $k => $val ){ $o = str_replace('%'.$k.'%', $val, $o); } }
chrono::pause('dico', $chr);
return $o;
}
chrono::pause('dico', $chr);
return $ref;
}
/*
private static function dico_search($dico, $fbkey=NULL){
$ps = split(":", configs::get('lang', 'dicos'));
$fb = self::fallback();
if ( $fbkey === NULL ){
foreach($ps as $k=>$path){ $ps[$k] .= '/'.self::lang(); }
} else {
foreach($ps as $k=>$path){ $ps[$k] .= '/'.$fb[$fbkey]; }
}
if ( $dico !== NULL ){
$o[0] = CORE::getdeps($ps, $dico, NULL,'dico', 'htm');
if ( FALSE == $o[0] ){ return FALSE; }
return $o;
} else {
return CORE::searchdeps($ps, '', NULL, 'dico', 'htm');
}
}
private static function dico_getref($file, $tl, $ref, $args=NULL){
$obj = new dico_tidy();
if ( FALSE === $obj->load($file) ){ return FALSE; }
if ( $tl != $obj->lang() ){
errors::raise("Language do not match for file $file, expected:$tl and got:".$obj->lang(), CORE_LOG_WARNING, 'LANG');
return FALSE;
}
$o = $obj->get($ref, $args);
$obj->unload();
return $o;
}
public static function dico_translate_old($ref, $args=NULL, $dico=NULL){
//return $ref;
if ( !isset(self::$_LANG) ){ self::load(); }
if ( !chrono::isinit('dico') ){ chrono::init('dico'); }
$chr = chrono::start('dico');
$dicos = self::dico_search($dico);
if (FALSE !== $dicos){
//some dicos has been found, lets search for $ref in them
foreach($dicos as $k => $file){
$o = self::dico_getref($file, self::lang(), $ref, $args);
if ( FALSE !== $o ){
chrono::pause('dico', $chr);
return $o;
}
}
if ($dico === NULL ) { errors::raise("Ref '$ref' was not found in ".self::lang()." Dicos, trying fallbacks !", CORE_LOG_WARNING, 'LANG');
} else { errors::raise("Ref '$ref' was not found in ".self::lang()." Dico '$dico', trying fallbacks !", CORE_LOG_WARNING, 'LANG'); }
} elseif ($dico === NULL ) { errors::raise('No Dicos could be found in '.self::lang().', trying fallback language', CORE_LOG_WARNING, 'LANG');
} else { errors::raise("Dico '$dico' was not found, trying fallback language", CORE_LOG_WARNING, 'LANG'); }
//hmm not found in base language, lets checks in fallbacks ones.
$fb = self::fallback();
$sl = self::getlangs();
if ( !is_array($fb) ){ chrono::pause('dico', $chr);return FALSE; }
foreach($fb as $k =>$lang){
if ( FALSE !== array_search($lang, $sl) ){
$tr[] = $lang;
$dicos = self::dico_search($dico, $k);
if (FALSE !== $dicos){
foreach($dicos as $k => $file){
$o = self::dico_getref($file, $lang, $ref, $args);
if ( FALSE !== $o ){ chrono::pause('dico', $chr);return $o; }
}
}
} else { errors::raise("Fallback language '$lang' is not supported by this website, skiping !", CORE_LOG_NOTICE, 'LANG'); }
}
if ( isset($tr) ){
if ($dico === NULL ) { errors::raise("Ref '$ref' was not found in ".implode(', ', $tr)." Dicos !", CORE_LOG_ERROR, 'LANG');
} else { errors::raise("Ref '$ref' was not found in ".implode(', ', $tr)." Dico '$dico' !", CORE_LOG_ERROR, 'LANG'); }
}
chrono::pause('dico', $chr);
return FALSE;
}
public static function dbobj_translate($obj, $objid, $field, $args=NULL){
$cnf = configs::get('lang', 'object_CNF');
return self::db_translate($cnf, $obj, $objid, $field, $args);
}
public static function get_country($ccode){
$cnf = configs::get('lang', 'countries_CNF');
return self::db_translate($cnf, '', $ccode, '');
}
public static function get_language($lang){
$cnf = configs::get('lang', 'languages_CNF');
return self::db_translate($cnf, '', $lang, '');
}
private static function db_translate($cnf, $obj, $objid, $field, $args=NULL){
if ( !isset(self::$_LANG) ){ self::load(); }
$obj = new dico_db($cnf);
$o = $obj->get_databyinfos($obj, $objid, $field, self::lang());
if ( FALSE === $o ){
$o = $obj->get_databyinfos($obj, $objid, $field, self::fallback());
if ( FALSE === $o ){ return FALSE; }
}
if ( $args === NULL ){ return $o; }
foreach($args as $k => $val ){ $o = str_replace("%$k%", $val, $o); }
return $o;
}
*/
public static function date_notime($stamp){
if ( !isset(self::$_LANG) ){ self::load(); }
return self::$_LANG->date_notime($stamp);
}
public static function date_time($stamp){
if ( !isset(self::$_LANG) ){ self::load(); }
return self::$_LANG->date_time($stamp);
}
public static function number($real, $prec=0){
if ( ! isset(self::$_LANG) ){ self::load(); }
return self::$_LANG->number($real, $prec);
}
public static function periode($intsec){
if ( !isset(self::$_LANG) ){ self::load(); }
return 'notdoneyet';
}
public static function output_for_client($str){
echo self::recode_for_client($str);
return TRUE;
}
public static function recode_for_client($str){
$int = CORE::getintcharset();
if ( empty($int) ){ $int = 'UTF-8'; }
return self::recode($str, $int, self::$charset);
}
private static function recode_from_client(){
$int = CORE::getintcharset();
if ( isset($_GET) ){ $_GET = self::recode($_GET, self::$charset, $int); }
if ( isset($_POST) ){ $_POST = self::recode($_POST, self::$charset, $int); }
if ( isset($_FILES) ){ $_FILES = self::recode($_FILES, self::$charset, $int); }
}
public static function recode($str, $from, $to){
//if ( $from == $to ){ return $str; }
if ( is_array($str) ){
foreach($str as $k => $v ){ $o[self::recode($k, $from, $to)] = self::recode($v, $from, $to); }
if ( isset($o) ){ return $o; } else { return Array(); }
} else {
$int = CORE::getintcharset();
$len = strlen($str);
$offset=0;
$BUFF = '';
while( $offset <= $len ){
$char = mb_substr($str, $offset, 1, $from);
if ( function_exists('iconv') ){
$n = @iconv($from, $to.'//TRANSLITE', $char);
if ( FALSE === $n ){ $n = iconv($int, $to.'//TRANSLITE', '?'); }
} elseif ( function_exists('libiconv') ){
$n = @libiconv($from, $to.'//TRANSLITE', $char);
if ( FALSE === $n ){ $n = libiconv($int, $to.'//TRANSLITE', '?'); }
} else {
$n = $char;
}
$BUFF .= $n;
$offset++;
}
return $BUFF;
}
}
public static function translate($ref, $args=NULL, $dico=NULL){
return self::dico_translate($ref, $args, $dico);
}
public static function dbtranslate($obj, $objid, $field){
return self::dbobj_translate($obj, $objid, $field);
}
public static function template_define(){
$o['lang'] = self::lang();
$o['charset'] = self::charset();
return $o;
}
}