e107inc/e107

View on GitHub
e107_handlers/language_class.php

Summary

Maintainability
A
2 hrs
Test Coverage
F
15%
<?php
/*
 * e107 website system
 *
 * Copyright (C) 2008-2010 e107 Inc (e107.org)
 * Released under the terms and conditions of the
 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
 *
 * Language handler
 *
 */

/**
 * @package e107
 * @subpackage    e107_handlers
 * @version $Id$
 */

class language{

// http://www.loc.gov/standards/iso639-2/php/code_list.php

// Valid Language Pack Names are shown directly below on the right. 
    public $detect = false;
    public $e_language = 'English'; // replaced later with $pref
    public $_cookie_domain = '';
    
    /**
     * Cached list of Installed Language Packs
     * @var array
     */
    protected $lanlist = null; // null is important!!!

    // code / folder.
    protected $list = array(
            "aa" => "Afar",
            "ab" => "Abkhazian",
            "af" => "Afrikaans",
            "am" => "Amharic",
            "ar" => "Arabic",
            "as" => "Assamese",
            "ae" => "Avestan",
            "ay" => "Aymara",
            "az" => "Azerbaijani",
            "ba" => "Bashkir",
            "be" => "Belarusian",
            "bn" => "Bengali",
            "bh" => "Bihari",
            "bi" => "Bislama",
            "bo" => "Tibetan",
            "bs" => "Bosnian",

            "br" => "Brazilian",

            "bg" => "Bulgarian",
            "my" => "Burmese",
            "ca" => "Catalan",
            "cs" => "Czech",
            "ch" => "Chamorro",
            "ce" => "Chechen",
            "cn" => "ChineseSimp",
            "tw" => "ChineseTrad",
            "cv" => "Chuvash",
            "kw" => "Cornish",
            "co" => "Corsican",

            "da" => "Danish",
            "nl" => "Dutch",
            "dz" => "Dzongkha",
            "de" => "German",


            "en" => "English",
            "eo" => "Esperanto",
            "et" => "Estonian",
            "eu" => "Basque",
            "fo" => "Faroese",
            "fa" => "Persian",
            "fj" => "Fijian",
            "fi" => "Finnish",
            "fr" => "French",
            "fy" => "Frisian",
            "gd" => "Gaelic",
            "el" => "Greek",
            "ga" => "Irish",
            "gl" => "Gallegan",

            "gn" => "Guarani",
            "gu" => "Gujarati",
            "ha" => "Hausa",
            "he" => "Hebrew",
            "hz" => "Herero",
            "hi" => "Hindi",
            "ho" => "Hiri Motu",
            "hr" => "Croatian",
            "hu" => "Hungarian",
            "hy" => "Armenian",
            "iu" => "Inuktitut",
            "ie" => "Interlingue",
            "id" => "Indonesian",
            "ik" => "Inupiaq",
            "is" => "Icelandic",
            "it" => "Italian",
            "jw" => "Javanese",
            "ja" => "Japanese",
            "kl" => "Kalaallisut",
            "kn" => "Kannada",
            "ks" => "Kashmiri",
            "ka" => "Georgian",
            "kk" => "Kazakh",
            "km" => "Khmer",
            "ki" => "Kikuyu",
            "rw" => "Kinyarwanda",
            "ky" => "Kirghiz",
            "kv" => "Komi",
            "ko" => "Korean",
            "ku" => "Kurdish",
            "lo" => "Lao",
            "la" => "Latin",
            "lv" => "Latvian",
            "ln" => "Lingala",
            "lt" => "Lithuanian",
            "lb" => "Letzeburgesch",
            "mh" => "Marshall",
            "ml" => "Malayalam",
            "mr" => "Marathi",
            "mk" => "Macedonian",
            "mg" => "Malagasy",
            "mt" => "Maltese",
            "mo" => "Moldavian",
            "mn" => "Mongolian",
            "mi" => "Maori",
            "ms" => "Malay",
            "gv" => "Manx",

            "na" => "Nauru",
            "nv" => "Navajo",

            "ng" => "Ndonga",
            "ne" => "Nepali",

            "no" => "Norwegian",

            "ny" => "Chichewa",
            "or" => "Oriya",
            "om" => "Oromo",
            "pa" => "Panjabi",
            "pi" => "Pali",
            "pl" => "Polish",
            "pt" => "Portuguese",

            "ps" => "Pushto",
            "qu" => "Quechua",
            "ro" => "Romanian",
            "rn" => "Rundi",
            "ru" => "Russian",
            "sg" => "Sango",
            "sa" => "Sanskrit",
            "si" => "Sinhala",
            "sk" => "Slovak",
            "sl" => "Slovenian",

            "sm" => "Samoan",
            "sn" => "Shona",
            "sd" => "Sindhi",
            "so" => "Somali",

            "es" => "Spanish",
            "sq" => "Albanian",
            "sc" => "Sardinian",
            "sr" => "Serbian",
            "ss" => "Swati",
            "su" => "Sundanese",
            "sw" => "Swahili",
            "sv" => "Swedish",
            "ty" => "Tahitian",
            "ta" => "Tamil",
            "tt" => "Tatar",
            "te" => "Telugu",
            "tg" => "Tajik",
            "tl" => "Tagalog",
            "th" => "Thai",
            "ti" => "Tigrinya",

            "tn" => "Tswana",
            "ts" => "Tsonga",
            "tk" => "Turkmen",
            "tr" => "Turkish",

            "ug" => "Uighur",
            "uk" => "Ukrainian",
            "ur" => "Urdu",
            "uz" => "Uzbek",
            "vi" => "Vietnamese",

            "cy" => "Welsh",
            "wo" => "Wolof",
            "xh" => "Xhosa",
            "yi" => "Yiddish",
            "yo" => "Yoruba",
            "za" => "Zhuang",
           // "zh" => "Chinese",
            "zu" => "Zulu"
        );

        protected $names = array(
            "Arabic"         => "العربية",
            "Bengali"        => "বাংলা",
            "Bosnian"        => "Bosanski",
            "Bulgarian"        => "Български",
            "Croatian"        => "Hrvatski",
            "ChineseTrad"      => "繁体中文",
            "ChineseSimp"      => "简体中文",
            "Czech"            => "Čeština",
            "Dutch"            => "Nederlands",
            "English"        => "English",
            "Estonian"        => "Eesti",
            "French"        => "Français",
            "Finnish"        => "Suomi",
            "German"        => "Deutsch",
            "Greek"            => "Ελληνικά",
            "Hebrew"        => "עִבְרִית",
            "Hindi"            => "हिन्दी",
            "Hungarian"        => "Magyar",
            "Icelandic"        => "íslenska",
            "Indonesian"    => "Bahasa Indonesia",
            "Italian"        => "Italiano",
            "Japanese"        => "日本語",
            "Khmer"            => "ខ្មែរ",
            "Korean"        => "한국어",
            "Lithuanian"    => "Lietuvių",
            "Mongolian"        => "Монгол",
            "Nepali"        => "नेपाली",
            "Norwegian"        => "Norsk",
            "Persian"           => "فارسي",
            "Portuguese"    => "Português",
            "Brazilian"     => "Português do Brasil",
            "Polish"        => "Polski",
            "Romanian"        => "Română",
            "Russian"        => "Pусский",
            "Serbian"        => "Српски",
            "Sinhala"        => "සිංහල",
            "Spanish"        => "Español",
            "Slovenian"        => "Slovensko",
            "Slovakian"        => "Slovensky",
            "Slovak"        => "Slovensky",
            "Swedish"        => "Svenska",
            "Thai"            => "ภาษาไทย",
            "Turkish"        => "Türkçe",
            "Vietnamese"    => "Tiếng Việt",
            "Welsh"         => "Cymraeg"
        );

    /**
     * Converts iso to language-name and visa-versa.
     * @param string $data
     * @return string
     */
    function convert($data){

        if(strlen($data) > 2)
        {
            $tmp = array_flip($this->list);
            return isset($tmp[$data]) ? $tmp[$data] : false;
        }
        else
        {
            return (isset($this->list[$data])) ? $this->list[$data] : false;
        }
    }

// -------------------------------------------------------------------
    /**
     * Check if a Language is installed and valid
     * @param object $lang - Language to check. eg. 'es' or 'Spanish'
     * @return false or the name of the valid Language
     */
    function isValid($lang='')
    {
        if(empty($lang))
        {
            return false;
        }

        global $pref;

        if(!$lang)
        {
            return (ADMIN_AREA &&  vartrue($pref['adminlanguage'])) ? $pref['adminlanguage'] : $pref['sitelanguage'];
        }

        if(strpos($lang,"debug")!==false)
        {
             return false;
        }

        if($lang == 'E_SITELANGUAGE') // allows for overriding language using a scripted 'define' before class2.php is loaded.
        {
            $lang = $pref['sitelanguage'];
        }

        if($lang == 'E_ADMINLANGUAGE')
        {
            $lang = $pref['adminlanguage'];
        }

        if(strlen($lang)== 2)
        {
            $iso = $lang;
            $lang = $this->convert($lang);    
        }
        else
        {
            $iso = $this->convert($lang);
        }
            
        if($iso==false || $lang==false)
        {
            $diz = ($lang) ? $lang : $iso;
            trigger_error("The selected language (".$diz.") is invalid. See e107_handlers/language_class.php for a list of valid languages. ", E_USER_ERROR);
            return false;
        }
        
        if(is_readable(e_LANGUAGEDIR.$lang.'/'.$lang.'.php'))
        {
            return $lang;    
        }
        else
        {
            trigger_error("The selected language (".$lang.") was not found.", E_USER_ERROR);
            return false;
        }

    }

    /**
     * Check if the specified domain has multi-language subdomains enabled.
     * @param string $domain
     * @return bool|int|string
     */
    function isLangDomain($domain='')
    {
        if(!$domain)
        {
            return false;
        }
        
        global $pref;
        $mtmp = explode("\n", $pref['multilanguage_subdomain']);
        foreach($mtmp as $val)
        {
            if($domain == trim($val))
            {
                return true;
            }
        }

        if(!empty($pref['multilanguage_domain']) && is_array($pref['multilanguage_domain']))
        {
            foreach($pref['multilanguage_domain'] as $lng=>$val)
            {
                if($domain == trim($val))
                {
                    return $lng;
                }
            }

        }
        
        return false;
        
    }


    /**
     * Generic variable translator for LAN definitions. 
     * @example $lng->translate("My name is [x] and I own a [y]", array('x'=>"John", 'y'=>"Cat")); 
     * @deprecated Use $tp->lanVars() instead. 
     */
    function translate($lan, $array= array())
    {
        trigger_error('<b>'.__METHOD__.' is deprecated.</b> Use $tp->lanVars() instead.', E_USER_DEPRECATED); // NO LAN

        $search = array();
        $replace = array();

        foreach($array as $k=>$v)
        {
            $search[] = "[".$k."]";
            $replace[] = "<b>".$v."</b>";
        }
        
        return str_replace($search, $replace, $lan);
    }




    

    /**
     * Return a list of Installed Language Packs
     * @param str $type - English or Native.
     * @example type = english: array(0=>'English', 1=>'French' ...)
     * @example type = native: array('English'=>'English', 'French'=>'Francais'...)
     * @example type = abbr: array('en'=>'English, 'fr'=>'French' ... )
     * @return array
     */
    function installed($type='english')
    {
        if(null == $this->lanlist)
        {
            $fl = e107::getFile();
            $dirArray = $fl->get_dirs(e_LANGUAGEDIR);
        //    $handle = opendir(e_LANGUAGEDIR);
            $lanlist = array();
        //    while ($file = readdir($handle))
            foreach($dirArray as $file)
            {
                if ($file != '.' && $file != '..' && is_readable(e_LANGUAGEDIR.$file.'/'.$file.'.php'))
                {
                    $lanlist[] = $file;
                }
            }
            // closedir($handle);
            
            $this->lanlist = array_intersect($lanlist,$this->list);
        }

        switch($type)
        {
            case "native":
                $natList = array();
                foreach($this->lanlist as $lang)
                {
                    $natList[$lang] = $this->toNative($lang);
                }

                natsort($natList);

                return $natList;
                break;

            case "abbr":
                $natList = array();
                foreach($this->lanlist as $lang)
                {
                    $iso = $this->convert($lang);
                    $natList[$iso] = $lang;
                }

                natsort($natList);

                return $natList;
                break;

            case 'count':
                return count($this->lanlist);
            break;

            case "english":
            default:
                return $this->lanlist;
        }


    }
    
    
    /**
     * Convert a Language to its Native title. eg. 'Spanish' becomes 'Español'
     * @param string $lang
     * @return string
     */
    function toNative($lang)
    {
        return (!empty($this->names[$lang])) ? $this->names[$lang] : $lang;
    }

    /**
     * Convert the current URL to a multi-lang for the specified language. 
     * eg. 'http://www.mydomain.com' becomes 'http://es.mydomain.com'
     * @param string $language eg. 'Spanish'
     * @return string url
     */
    function subdomainUrl($language, $url=e_REQUEST_URL)
    {

        $sitelanguage =  e107::getPref('sitelanguage',null);

        $iso = (strlen($language) == 2) ? $language : $this->convert($language);

        $codelnk = ($language == $sitelanguage) ? "www" : $iso;
        
        if($codelnk == '')
        {
            $codelnk = 'www';    
        }
        
      //  $urlval = str_replace($_SERVER['HTTP_HOST'],$codelnk.".".e_DOMAIN,e_SELF);
        
        /*    $urlval = (e_QUERY)
                    ? str_replace($_SERVER['HTTP_HOST'], $codelnk.'.'.e_DOMAIN, e_SELF).'?'.e_QUERY
                    : str_replace($_SERVER['HTTP_HOST'], $codelnk.'.'.e_DOMAIN, e_SELF);
        */


        $domain = deftrue('e_DOMAIN','example.com');

        $urlval = str_replace($_SERVER['HTTP_HOST'], $codelnk.'.'.$domain, $url) ;
        
        return (string) $urlval;
    }
    
    /**
     * Detect a Language Change
    * 1. Scripted Definition    eg. define('e_PAGE_LANGUAGE', 'English');
    * 2. Parked Domain          eg. http://mylanguagedomain.com
     * 3. Parked subDomain        eg. http://es.mydomain.com (Preferred for SEO)
     * 4. e_MENU Query            eg. /index.php?[es]
     * 5. $_GET['elan']            eg. /index.php?elan=es
     * 6. $_POST['sitelanguage']    eg. <input type='hidden' name='sitelanguage' value='Spanish' />
     * 7. $GLOBALS['elan']        eg. <?php $GLOBALS['elan']='es' (deprecated)
     * 
     * @param boolean $force force detection, don't use cached value
     */
    function detect($force = false)
    {
        global $pref;
        
        
        if(false !== $this->detect && !$force) return $this->detect;
        $this->_cookie_domain = '';

        if(defined('e_PAGE_LANGUAGE') && ($detect_language = $this->isValid(e_PAGE_LANGUAGE))) // page specific override.
        {
            $doNothing = '';
            // Do nothing as $detect_language is set.
        }
        elseif(!empty($pref['multilanguage_subdomain']) && $this->isLangDomain(e_DOMAIN) && (defset('MULTILANG_SUBDOMAIN') !== false))
        {
            $detect_language = (e_SUBDOMAIN) ? $this->isValid(e_SUBDOMAIN) : $pref['sitelanguage'];
            // Done in session handler now, based on MULTILANG_SUBDOMAIN value
            //ini_set("session.cookie_domain", ".".e_DOMAIN); // Must be before session_start()
            $this->_cookie_domain = ".".e_DOMAIN;
            define('MULTILANG_SUBDOMAIN',true);
        }
        elseif(!empty($pref['multilanguage_domain']) &&  ($newLang = $this->isLangDomain(e_DOMAIN)))
        {
            $detect_language = $this->isValid($newLang);
            $this->_cookie_domain = ".".e_DOMAIN;
        }
        elseif(e_MENU && ($detect_language = $this->isValid(e_MENU))) // 
        {
            define("e_LANCODE",true);

        }
        elseif(isset($_GET['elan']) && ($detect_language = $this->isValid($_GET['elan']))) // eg: /index.php?elan=Spanish
        {
            $doNothing = '';// Do nothing
        }
        elseif(isset($_POST['setlanguage']) && ($detect_language = $this->isValid($_POST['sitelanguage'])))
        {
            $doNothing = '';// Do nothing
        }
        
        elseif(isset($GLOBALS['elan']) && ($detect_language = $this->isValid($GLOBALS['elan'])))
        {
            $doNothing = '';// Do nothing
        }
        else
        {
            $detect_language = false; // ie. No Change.
        }
        
        // Done in session handler now
        // ini_set("session.cookie_path", e_HTTP);
        
        $this->detect = $detect_language;    
        return $detect_language;
    }

    /**
     * Get domain to be used in cookeis (e.g. .domain.com), or empty
     * if multi-language subdomain settings not enabled
     * Available after self::detect() 
     * @return string
     */
    public function getCookieDomain()
    {
        return $this->_cookie_domain;
    }

    /**
     * Set the Language (Constants, $_SESSION and $_COOKIE) for the current page. 
     * @param string $language force set
     * @return void
     */
    function set($language = null)
    {
        $pref = e107::getPref();
        $session = e107::getSession(); // default core session namespace
        if($language && ($language = $this->isValid($language))) // force set
        {
            $this->detect = $language;
        }
        if($this->detect) // Language-Change Trigger Detected. 
        {
            // new - e_language moved to e107 namespace - $_SESSION['e107']['e_language']
            $oldlan = $session->get('e_language');
            
            if(!$session->has('e_language') || (($session->get('e_language') != $this->detect) && $this->isValid($this->detect)))
            {
                $session->set('e_language', $this->detect);    
            }
            
            if(varset($_COOKIE['e107_language'])!=$this->detect && (defset('MULTILANG_SUBDOMAIN') != TRUE))
            {
                setcookie('e107_language', $this->detect, time() + 86400, e_HTTP);
                $_COOKIE['e107_language'] = $this->detect; // Used only when a user returns to the site. Not used during this session. 
            }
            else // Multi-lang SubDomains should ignore cookies and remove old ones if they exist. 
            {
                if(isset($_COOKIE['e107_language']))
                {
                    unset($_COOKIE['e107_language']);
                }
            }
            $user_language = $this->detect;        

            // new system trigger 'lanset' 
            if($oldlan && $oldlan !== $this->detect)
            {
                e107::getEvent()->trigger('lanset', array('new' => $this->detect, 'old' => $oldlan));
            }
        }
        else // No Language-change Trigger Detected. 
        {
                            
            if($session->has('e_language'))
            {
                $user_language = $session->get('e_language');
            }
            elseif(isset($_COOKIE['e107_language']) && ($user_language = $this->isValid($_COOKIE['e107_language']))) 
            {
                $session->set('e_language', $user_language);             
            }
            else
            {
                                
                $user_language = $pref['sitelanguage'];    
                
                if($session->is('e_language'))
                {
                    $session->clear('e_language');
                }
            
                if(isset($_COOKIE['e107_language']))
                {
                    unset($_COOKIE['e107_language']);
                }    
            }    
        }
        
        $this->e_language = $user_language;
        $this->setDefs();

        if(e_LAN !== 'en')
        {
            e107::getParser()->setMultibyte(true);
        }

        return;
    }


    /**
     * Set Language-specific Constants
     * FIXME - language detection is a mess - db handler, mysql handler, session handler and language handler + constants invlolved,
     * SIMPLIFY, test, get feedback
     * @return void
     */
    function setDefs()
    {
        global $pref;
        
        $language = $this->e_language;
        //$session = e107::getSession();

        // SecretR - don't register lanlist in session, confusions, save it as class property (lan class is singleton) 
        e107::getSession()->set('language-list', null); // cleanup test installs, will be removed soon
        
        /*if(!$session->is('language-list'))
        {
            $session->set('language-list', implode(',',$this->installed()));
        }*/
        
        //define('e_LANLIST', $session->get('language-list'));
        define('e_LANLIST',  implode(',', $this->installed()));
        define('e_LANGUAGE', $language);
        define('USERLAN', $language); // Keep USERLAN for backward compatibility
        $iso = $this->convert($language);    
        define("e_LAN", $iso);
        
        // Below is for BC
        if(defined('e_LANCODE') && varset($pref['multilanguage']) && ($language != $pref['sitelanguage']))
        {            
            define("e_LANQRY", "[".$iso."]");
        }
        else
        {
            define("e_LANCODE", '');        
            define("e_LANQRY", false);
        }     
    }

    /**
     * @param $force
     * @return array
     */
    public function getLanSelectArray($force = false)
    {
        if($force ||null === $this->_select_array)
        {
            $lanlist = explode(',', e_LANLIST);
            $this->_select_array = array();
            foreach ($lanlist as $lan) 
            {
                $this->_select_array[$this->convert($lan)] = $this->toNative($lan);
            }
        }
        return $this->_select_array;
    }

    /**
     * Return an array of all language types. 
     */
    public function getList()
    {
        return $this->list;
    }


    /**
     * Define Legacy LAN constants based on a supplied array.
     * @param array $bcList legacyLAN => Replacement-LAN
     */
    public function bcDefs($bcList = null)
    {

        if(empty($bcList))
        {
            $bcList = array(
                'LAN_180'   => 'LAN_SEARCH'
            );
        }

        foreach($bcList as $old => $new)
        {
            if(!defined($old) && defined($new))
            {
                define($old, constant($new));
            }
            elseif(empty($new) && !defined($old))
            {
                define($old,'');
            }

        }

    }

}