root/trunk/wifidog-auth/wifidog/classes/Locale.php @ 1149

Revision 1149, 15.9 KB (checked in by benoitg, 6 years ago)
  • install.php: Fix a few problems caused by obsolete magpierss detection code.
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5// +-------------------------------------------------------------------+
6// | WiFiDog Authentication Server                                     |
7// | =============================                                     |
8// |                                                                   |
9// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
10// | portal suite.                                                     |
11// +-------------------------------------------------------------------+
12// | PHP version 5 required.                                           |
13// +-------------------------------------------------------------------+
14// | Homepage:     http://www.wifidog.org/                             |
15// | Source Forge: http://sourceforge.net/projects/wifidog/            |
16// +-------------------------------------------------------------------+
17// | This program is free software; you can redistribute it and/or     |
18// | modify it under the terms of the GNU General Public License as    |
19// | published by the Free Software Foundation; either version 2 of    |
20// | the License, or (at your option) any later version.               |
21// |                                                                   |
22// | This program is distributed in the hope that it will be useful,   |
23// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
24// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
25// | GNU General Public License for more details.                      |
26// |                                                                   |
27// | You should have received a copy of the GNU General Public License |
28// | along with this program; if not, contact:                         |
29// |                                                                   |
30// | Free Software Foundation           Voice:  +1-617-542-5942        |
31// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
32// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
33// |                                                                   |
34// +-------------------------------------------------------------------+
35
36/**
37 * @package    WiFiDogAuthServer
38 * @author     Benoit Grégoire <bock@step.polymtl.ca>
39 * @copyright  2004-2006 Benoit Grégoire, Technologies Coeus inc.
40 * @version    Subversion $Id$
41 * @link       http://www.wifidog.org/
42 */
43
44error_reporting(E_ALL);
45
46// Detect Gettext support.
47if (!function_exists('gettext')) {
48    /**
49     * Define Gettext has NOT been found on the system
50     */
51    define('GETTEXT_AVAILABLE', false);
52
53    // Redefine the gettext functions if gettext isn't installed.
54
55    function gettext($string) {
56        return $string;
57    }
58
59    function _($string) {
60        return $string;
61    }
62} else {
63    /**
64     * Define Gettext has been found on the system
65     *
66     * @ignore
67     */
68    define('GETTEXT_AVAILABLE', true);
69}
70require_once('classes/Session.php');
71/**
72 * Designates a human language, possibly localized ie fr_CA
73 *
74 * @package    WiFiDogAuthServer
75 * @author     Benoit Grégoire <bock@step.polymtl.ca>
76 * @copyright  2004-2006 Benoit Grégoire, Technologies Coeus inc.
77 */
78class Locale {
79    // Private attributes
80    private $mLang;
81    private $mCountry;
82
83    /**
84     * Constructor
85     * @param string $p_locale Locale in POSIX format (excluding charset), such
86     * as fr ou fr_CA: "xx(x)_YY_(n*z)".  Both '_' and '-' are acceptable as
87     * separator.
88     */
89    function __construct($p_locale) {
90        $matches = self :: decomposeLocaleId($p_locale);
91        $locale = $matches[1];
92        $this->mLang = $matches[1];
93
94        if ($this->mLang == null) {
95            throw new Exception(_("Locale(): Could not a locale matching $locale"), EXCEPTION_CREATE_OBJECT_FAILED);
96        }
97
98        if (empty ($matches[2])) {
99            $this->mCountry = null;
100        } else {
101            $locale .= '_'.$matches[2];
102            $this->mCountry = $matches[2];
103        }
104
105        if (empty ($matches[3])) {
106            // TODO: Optionally support subcode ?
107        } else {
108                        // region
109            $locale .= '_'.$matches[3];
110                        // $this->mRegion = $matches[3];
111        }
112
113        $this->mId = $locale;
114    }
115
116    /**
117     * Get the Locale object
118     * @param string $content_id The content id
119     * @return The Content object, or null if there was an error (an exception is also thrown)
120     */
121    static function getObject($locale_id) {
122        return new self($locale_id);
123    }
124
125    public static function getCurrentLocale() {
126        $session = Session::getObject();
127        global $AVAIL_LOCALE_ARRAY;
128        $object = null;
129        $locale_id = $session->get(SESS_LANGUAGE_VAR);
130        //echo sprintf("Debug in /classes/Locale.php getCurrentLocale(): session->get(SESS_LANGUAGE_VAR)=%s", $session->get(SESS_LANGUAGE_VAR))."<br/>";
131
132        /* Try to guess the lang */
133        if (empty($locale_id) || empty($AVAIL_LOCALE_ARRAY[$locale_id])) {
134            $locale_id = self :: getBestLanguage();
135        }
136
137        /* If we still don't have it, fill in default */
138        if (empty ($locale_id)) {
139            $object = self :: getObject(DEFAULT_LANG);
140        } else {
141            $object = self :: getObject($locale_id);
142        }
143
144        return $object;
145    }
146
147    /**
148      * Try to find best language according to HTTP_ACCEPT_LANGUAGE passed
149      * by the browser.
150      * @return string Best language from list of available languages, otherwise
151      * empty.
152      */
153        public static function getBestLanguage($availableLanguages=false) {
154                global $AVAIL_LOCALE_ARRAY;
155                if (empty($availableLanguages)) $availableLanguages=$AVAIL_LOCALE_ARRAY;
156
157                // the HTTP_ACCEPT_LANGUAGE server string comes from the browser in the
158                // Accept-Language: header.  It is a list of browser language preferences separated by commas.
159                // the language preference is a 2 part field separated by semicolons.  the first part is the language.
160                // the languages are the iso codes.  the language may have a hyphen and a country code appended to
161                // it, like "fr-CA" or "en-gb".
162                // the second part of the language preference may be missing.  if it's not there it's assumed to be
163                // "q=1.0".  This part gives the preference rating and is an float between 0.0 and 1.0.  0.8 corresponds
164                // to 80%.
165
166                // $AVAIL_LOCALE_ARRAY, set in config.php.  this is a list of available locales.
167                // The format is different from that of HTTP_ACCEPT_LANGUAGE.  It is:
168                // LANGUAGE [ _COUNTRY [ .ENCODING ] ]
169                // where LANGUAGE and COUNTRY are 2 letter codes (usually), and encoding is something like iso88591 or utf8.
170                // for example:
171                // english or en or en_CA or en_CA.utf8 or en_CA.iso88591 or en_US.iso885915
172                // french or fr or fr_CA or fr_CA.utf8 or fr_CA.iso88591
173
174                $browser_preferences = array();
175                foreach(explode(',', empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? DEFAULT_LANG : $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
176                        //echo $lang."\n";
177                        if (preg_match('/^\s*([a-z_-]+).*?(?:;\s*q=([0-9.]+))?/i', $lang.';q=1.0', $split)) {
178                                $browser_preferences[sprintf('%f%d', $split[2], rand(0,9999))] = strtolower($split[1]);
179                        }
180                }
181
182                // sort preferences by key in reverse order, from high to low
183                // best is first, worst is last
184                krsort($browser_preferences);
185
186                foreach($browser_preferences as $score => $language_spec) {
187                        //echo "$score => $language_spec\n";
188                        @list($prefered_language, $prefered_country) = preg_split('/[-_]/', $language_spec);
189                        // better to use explode('-', $language_spec) except that $language_spec may come from
190                        // config.php DEFAULT_LANG, which may be given as a locale, with an underscore
191                        // between the language and country.
192
193                        $prefered_locale = empty($prefered_country) ? $prefered_language :
194                                $prefered_language . '_' . strtoupper($prefered_country);
195
196                        // if the browser's preference is matched exactly in $availableLanguages, great!
197                        if (!empty($availableLanguages[$prefered_locale])) return $prefered_locale;
198
199                        if (empty($prefered_country)) {
200                                // browser doesn't care what country
201                                // try to find a match in $availableLanguages ignoring the country
202                                foreach($availableLanguages as $my_locale => $language_name) {
203                                        @list($my_language, $my_country, $my_encoding) = preg_split('/[_.]/', $my_locale);
204                                        if ($my_language === $prefered_language) return $my_locale;
205                                }
206                        }
207                }
208
209                return false;
210
211                // return array_shift(array_merge(array_intersect($browser_preferences, $availableLanguages), $availableLanguages));
212        }
213
214    /** Initialise the system locale (gettext, setlocale, etc.)
215     * @return boolean true on success, false on failure.
216     */
217    public static function setCurrentLocale($locale) {
218        $session = Session::getObject();
219         global $AVAIL_LOCALE_ARRAY;
220        $retval = false;
221
222        // Get new locale ID, assume default if null
223        if ($locale != null) {
224            $locale_id = $locale->getId();
225            $retval = true;
226            $q = "parameter";
227        } else {
228            $locale_id = DEFAULT_LANG;
229            $retval = false;
230            $q = "default";
231        }
232        //pretty_print_r($locale);
233        //echo sprintf("Debug in /classes/Locale.php setCurentLocale(): locale_id=%s", $locale_id)."<br/>";
234
235        if (GETTEXT_AVAILABLE) {
236            $lang_only_locale_id = substr ($locale_id, 0 , 2);
237                   if(!isset($AVAIL_LOCALE_ARRAY[$locale_id]) && !isset($AVAIL_LOCALE_ARRAY[$lang_only_locale_id]))
238                   {
239                     echo sprintf("Warning in /classes/Locale.php setCurentLocale: Neither %s or %s are available in AVAIL_LOCALE_ARRAY", $locale_id, $lang_only_locale_id)."<br/>";
240                   }
241            // Try to set locale
242            $candidate_locale_array[] = str_ireplace('.UTF8', '', $locale_id).'.UTF-8';
243            $candidate_locale_array[] = str_ireplace('.UTF8', '', $locale_id);
244            $candidate_locale_array[] = $lang_only_locale_id.'.UTF-8';
245            $candidate_locale_array[] = $lang_only_locale_id;
246
247
248            $current_locale = setlocale(LC_ALL, $candidate_locale_array);
249               //echo sprintf("Warning in /classes/Locale.php setCurentLocale: Unable to setlocale() to %s: %s.  I tried %s, %s, %s, %s, and got return value: %s, current locale is: %s",$q, $locale_id, $candidate_locale_array[0], $candidate_locale_array[1], $candidate_locale_array[2], $candidate_locale_array[3], $current_locale, setlocale(LC_ALL, 0))."<br/>";
250
251            // Test it against current PHP locale
252            if (substr ($current_locale, 0 , 2) != $lang_only_locale_id) {
253                echo sprintf("Warning in /classes/Locale.php setCurentLocale: Unable to setlocale() to %s: %s.  I tried %s, %s, %s, %s, and got return value: %s, current locale is: %s",$q, $locale_id, $candidate_locale_array[0], $candidate_locale_array[1], $candidate_locale_array[2], $candidate_locale_array[3], $current_locale, setlocale(LC_ALL, 0))."<br/>";
254                $retval = false;
255            } else {
256                bindtextdomain('messages', WIFIDOG_ABS_FILE_PATH . 'locale');
257                bind_textdomain_codeset('messages', 'UTF-8');
258                textDomain('messages');
259
260                putenv("LC_ALL=".$current_locale);
261                putenv("LANGUAGE=".$current_locale);
262                $retval = true;
263            }
264        }
265        return $retval;
266    }
267
268    /**
269     * Example: 'fr_CA_montreal' will give
270     * $matches[0]=fr_CA_montreal
271     * $matches[1]=fr
272     * $matches[2]=CA
273     * $matches[3]=montreal
274     * Note:  Off course, matches 2 and 3 could be empty if the information
275     * wasn't present.
276     */
277    public static function decomposeLocaleId($locale_id) {
278        // Init values
279        $_matches = "";
280
281        $_regex = '/^([^-_]*)(?:[-_]([^-_]*))?(?:[-_]([^-_]*))?$/';
282        $_match_retval = preg_match($_regex, $locale_id, $_matches);
283        return $_matches;
284    }
285
286    /**
287     * Used by Langstring::GetString() (and other functions) to help select the
288     * best langstring_entry to display to the user.
289     * @return A sql fragment
290     */
291    public static function getSqlCaseStringSelect($locale_id) {
292        $decomposed_locale = Locale :: decomposeLocaleId($locale_id);
293
294        // The case will rate locales and choose the best one.
295
296        $sql = " (CASE\n";
297        // Look for part of the string or the full-length locale
298        $sql .= " WHEN locales_id='$decomposed_locale[0]' THEN 1\n";
299        // Look for a string or the language part of the locale (match generic language first)
300        $sql .= " WHEN locales_id='{$decomposed_locale[1]}' THEN 2\n";
301        // Look for the full string or any possible combination
302        $sql .= " WHEN locales_id LIKE '{$decomposed_locale[1]}%' THEN 3\n";
303
304        // Look for a string matching the language or the country of the user
305        if (!empty ($decomposed_locale[2])) {
306            $sql .= " WHEN locales_id LIKE '%{$decomposed_locale[2]}' THEN 4\n";
307        }
308
309        // Look for a string with no locale associated, it's more likely to be readable than a random string
310        $sql .= " WHEN locales_id IS NULL THEN 5\n";
311
312        $sql .= "      ELSE 20 ";
313        $sql .= "  END)\n";
314
315        return $sql;
316    }
317
318    public function GetId() {
319        return $this->mId;
320    }
321
322    /**
323     * Returns the locale in POSIX format, such as fr ou fr_CA "xx_YY".
324     * @return string Locale
325     */
326    function GetLocale() {
327        $retval = $this->mLang->GetShort();
328
329        if ($this->mCountry != null) {
330            $retval .= '_'.$this->mCountry->GetShort();
331        }
332
333        return $retval;
334    }
335
336    /**
337     * Returns the locale in W3C XML format (xs:language), such as fr ou fr-CA "xx-YY".
338     * @return string Locale
339     */
340    function GetXMLLanguage() {
341        return $this->mId;
342    }
343
344    /**
345     * Returns the language
346     * @return Lang.
347     */
348    function GetLang() {
349        return $this->mLang;
350    }
351
352    /**
353     * Returns the country, if available
354     * @return Country or null
355     */
356    function GetCountry() {
357        return $this->mCountry;
358    }
359
360    /**
361     * Returns a HTML formatted string for output to string (with an image)
362     */
363    function GetString() {
364        // Init values.
365        $str = "";
366        $resultats = "";
367        $preflang_result = "";
368
369        $tmp_loc = $this->GetLocale();
370
371        // Look for the country in the database and match the preferred locale
372        $sql = "SELECT * FROM languages_iso_639_1, locales LEFT JOIN countries ON (locales.countries_id = countries.countries_id) ";
373        $sql .= "WHERE locales.languages_iso_639_1_id = languages_iso_639_1.iso639_1_id ";
374        $sql .= "AND locales.locales_id = '$tmp_loc' ";
375        $this->mBd->ExecuterSqlResUnique($sql, $resultats, FALSE);
376
377        $tmp_pref_lang = $this->mSession->GetPrefLocale();
378        $sql = "SELECT * FROM locales WHERE locales.locales_id = '$tmp_pref_lang'";
379        $this->mBd->ExecuterSqlResUnique($sql, $preflang_result, FALSE);
380
381        switch ($preflang_result['languages_iso_639_1_id']) {
382            case ('fr') :
383                $str .= "$resultats[french_name], $resultats[country_french_name]";
384                break;
385
386            case ('en') :
387                $str .= "$resultats[english_name], $resultats[country_english_name]";
388                break;
389
390            case ('es') :
391                $str .= "$resultats[spanish_name], $resultats[country_spanish_name]";
392                break;
393
394            case ('de') :
395                $str .= "$resultats[german_name], $resultats[country_german_name]";
396                break;
397
398            case ('ja') :
399                $str .= "$resultats[japanese_name], $resultats[country_japanese_name]";
400                break;
401
402            case ('pt') :
403                $str .= "$resultats[portuguese_name], $resultats[country_portuguese_name]";
404                break;
405
406            default :
407                $str .= "$resultats[french_name], $resultats[country_french_name]";
408                break;
409        }
410
411        return $str;
412    }
413
414}
415
416/*
417 * Local variables:
418 * tab-width: 4
419 * c-basic-offset: 4
420 * c-hanging-comment-ender-p: nil
421 * End:
422 */
423
424
Note: See TracBrowser for help on using the browser.