fix image text
[pear] / I18Nv2.php
1 <?php
2 // +----------------------------------------------------------------------+
3 // | PEAR :: I18Nv2                                                       |
4 // +----------------------------------------------------------------------+
5 // | This source file is subject to version 3.0 of the PHP license,       |
6 // | that is available at http://www.php.net/license/3_0.txt              |
7 // | If you did not receive a copy of the PHP license and are unable      |
8 // | to obtain it through the world-wide-web, please send a note to       |
9 // | license@php.net so we can mail you a copy immediately.               |
10 // +----------------------------------------------------------------------+
11 // | Copyright (c) 2004 Michael Wallner <mike@iworks.at>                  |
12 // +----------------------------------------------------------------------+
13 //
14 // $Id: I18Nv2.php,v 1.36 2006/03/08 13:07:18 mike Exp $
15
16 /**
17  * I18Nv2
18  * 
19  * @package     I18Nv2
20  * @category    Internationalization
21  */
22
23 define('I18Nv2_WIN', defined('OS_WINDOWS') ? OS_WINDOWS : (strToUpper(substr(PHP_OS, 0,3)) === 'WIN'));
24
25 /** 
26  * I18Nv2 - Internationalization v2
27  *
28  * @author      Michael Wallner <mike@php.net>
29  * @version     $Revision: 1.36 $
30  * @package     I18Nv2
31  * @access      public
32  * @static
33  */
34 class I18Nv2
35 {
36     /**
37      * Set Locale
38      * 
39      * Example:
40      * <code>
41      * I18Nv2::setLocale('en_GB');
42      * </code>
43      * 
44      * @static
45      * @access  public
46      * @return  mixed   &type.string; used locale or false on failure
47      * @param   string  $locale     a valid locale like en_US or de_DE
48      * @param   int     $cat        the locale category - usually LC_ALL
49      */
50     static function setLocale($locale = null, $cat = LC_ALL)
51     {
52         if (!strlen($locale)) {
53             return setLocale($cat, null);
54         }
55         
56         $locales = I18Nv2::getStaticProperty('locales');
57         
58         // get complete standard locale code (en => en_US)
59         if (isset($locales[$locale])) {
60             $locale = $locales[$locale];
61         }
62         
63         // get Win32 locale code (en_US => enu)
64         if (I18Nv2_WIN) {
65             $windows   = I18Nv2::getStaticProperty('windows');
66             $setlocale = isset($windows[$locale]) ? $windows[$locale] : $locale;
67         } else {
68             $setlocale = $locale;
69         }
70
71         $syslocale = setLocale($cat, $setlocale);
72         
73         // if the locale is not recognized by the system, check if there 
74         // is a fallback locale and try that, otherwise return false
75         if (!$syslocale) {
76             $fallbacks = &I18Nv2::getStaticProperty('fallbacks');
77             if (isset($fallbacks[$locale])) {
78                 // avoid endless recursion with circular fallbacks
79                 $trylocale = $fallbacks[$locale];
80                 unset($fallbacks[$locale]);
81                 if ($retlocale = I18Nv2::setLocale($trylocale, $cat)) {
82                     $fallbacks[$locale] = $trylocale;
83                     return $retlocale;
84                 }
85             }
86             return false;
87         }
88         
89         $language = substr($locale, 0,2);
90         
91         if (I18Nv2_WIN) {
92             @putEnv('LANG='     . $language);
93             @putEnv('LANGUAGE=' . $language);
94         } else {
95             @putEnv('LANG='     . $locale);
96             @putEnv('LANGUAGE=' . $locale);
97         }
98         
99         // unshift locale stack
100         $last = &I18Nv2::getStaticProperty('last');
101         array_unshift($last, 
102             array(
103                 0           => $locale, 
104                 1           => $language, 
105                 2           => $syslocale,
106                 'locale'    => $locale,
107                 'language'  => $language,
108                 'syslocale' => $syslocale,
109             )
110         );
111         
112         // fetch locale specific information
113         $info = &I18Nv2::getStaticProperty('info');
114         $info = localeConv();
115         
116         return $syslocale;
117     }
118     
119     /**
120      * Get current/prior Locale
121      *
122      * @static
123      * @access  public
124      * @return  mixed   last locale as string or array
125      * @param   int     $prior  if 0, the current otherwise n prior to current
126      * @param   bool    $part   true|all|0=locale|1=language|2=syslocale
127      */
128     function lastLocale($prior = 0, $part = 0)
129     {
130         $last = I18Nv2::getStaticProperty('last');
131         if (!isset($last)) {
132             return I18Nv2::setLocale();
133         }
134         if (!isset($last[$prior])) {
135             return null;
136         }
137         if ($part === true || $part == 'all') {
138             return $last[$prior];
139         }
140         return $last[$prior][$part];
141     }
142     
143     /**
144      * Get several locale specific information
145      * 
146      * @see     http://www.php.net/localeconv
147      * 
148      * <code>
149      * $locale = I18Nv2::setLocale('en_US');
150      * $dollar = I18Nv2::getInfo('currency_symbol');
151      * $point  = I18Nv2::getInfo('decimal_point');
152      * </code>
153      * 
154      * @static
155      * @access  public
156      * @return  mixed
157      * @param   string  $part
158      */
159     function getInfo($part = null)
160     {
161         $info = &I18Nv2::getStaticProperty('info');
162         return isset($part, $info[$part]) ? $info[$part] : $info;
163     }
164     
165     /**
166      * Create a Locale object
167      *
168      * @static
169      * @access  public
170      * @return  object  I18Nv2_Locale
171      * @param   string  $locale     The locale to use.
172      * @param   bool    $paranoid   Whether to operate in paranoid mode.
173      */
174     function &createLocale($locale = null, $paranoid = false)
175     {
176         require_once 'I18Nv2/Locale.php';
177         $obj = new I18Nv2_Locale($locale, $paranoid);
178         return $obj;
179     }
180     
181     /**
182      * Create a Negotiator object
183      *
184      * @static
185      * @access  public
186      * @return  object  I18Nv2_Negotiator
187      * @param   string  $defLang        default language
188      * @param   string  $defEnc         default encoding
189      * @param   string  $defCtry        default country
190      */
191     function &createNegotiator($defLang = 'en', $defEnc = 'iso-8859-1', $defCtry = '')
192     {
193         require_once 'I18Nv2/Negotiator.php';
194         $obj = new I18Nv2_Negotiator($defLang, $defEnc, $defCtry);
195         return $obj;
196     }
197     
198     /**
199      * Automatically transform output between encodings
200      *
201      * This method utilizes ob_iconv_handler(), so you should call it at the 
202      * beginning of your script (prior to output).  If any output buffering has 
203      * been started before, the contents will be fetched with ob_get_contents() 
204      * and the buffers will be destroyed by ob_end_clean() if $refetchOB is set
205      * to true.
206      * 
207      * <code>
208      * require_once('I18Nv2.php');
209      * I18Nv2::autoConv('CP1252');
210      * print('...'); // some iso-8859-1 stuff gets converted to Windows-1252
211      * // ...
212      * </code>
213      * 
214      * @static
215      * @access  public
216      * @return  mixed   Returns &true; on success or 
217      *                  <classname>PEAR_Error</classname> on failure.
218      * @param   string  $oe             desired output encoding
219      * @param   string  $ie             internal encoding
220      * @param   bool    $decodeRequest  whether to decode request variables
221      *                                  ($_GET and $_POST) from $oe to $ie
222      * @param   bool    $refetchOB      whether contents of already active 
223      *                                  output buffers should be fetched, the
224      *                                  output buffer handlers destroyed and
225      *                                  the fetched data be passed through
226      *                                  ob_iconvhandler
227      */
228     function autoConv($oe = 'UTF-8', $ie = 'ISO-8859-1', $decodeRequest = true, $refetchOB = true)
229     {
230         if (!strcasecmp($oe, $ie)) {
231             return true;
232         }
233         
234         if (!extension_loaded('iconv')) {
235             require_once 'PEAR.php';
236             if (!PEAR::loadExtension('iconv')) {
237                 return PEAR::staticRaiseError('Error: ext/iconv is not available');
238             }
239         }
240         
241         iconv_set_encoding('internal_encoding', $ie);
242         iconv_set_encoding('output_encoding', $oe);
243         iconv_set_encoding('input_encoding', $oe);
244         
245         $buffer = '';
246         if ($refetchOB && $level = ob_get_level()) {
247             while ($level--) {
248                 $buffer .= ob_get_contents();
249                 ob_end_clean();
250             }
251         }
252         
253         if (!ob_start('ob_iconv_handler')) {
254             require_once 'PEAR.php';
255             return PEAR::staticRaiseError('Couldn\'t start output buffering');
256         }
257         echo $buffer;
258         
259         if ($decodeRequest) {
260             I18Nv2::recursiveIconv($_GET, $oe, $ie);
261             I18Nv2::recursiveIconv($_POST, $oe, $ie);
262         }
263         
264         return true;
265     }
266     
267     /**
268      * Recursive Iconv
269      * 
270      * @static
271      * @access  public
272      * @return  void
273      * @param   array   $value
274      * @param   string  $from
275      * @param   string  $to
276      */
277     function recursiveIconv(&$value, $from, $to)
278     {
279         foreach ($value as $key => $val) {
280             if (is_array($val)) {
281                 I18Nv2::recursiveIconv($value[$key], $from, $to);
282             } else {
283                 $value[$key] = iconv($from, $to .'//TRANSLIT', $val);
284             }
285         }
286     }
287     
288     /**
289      * Traverse locales to languages
290      * 
291      * Returns en-US, de-DE from en_US and de_DE
292      *
293      * @static
294      * @access  public
295      * @return  array
296      * @param   array   $locales
297      */
298     function locales2langs($locales)
299     {
300         return array_map(array('I18Nv2','l2l'), (array) $locales);
301     }
302     
303     /**
304      * Traverse languages to locales
305      *
306      * Returns en_US, de_DE from en-US and de-DE
307      *
308      * @static
309      * @access  public
310      * @return  array
311      * @param   array   $languages
312      */
313     function langs2locales($languages)
314     {
315         return array_map(array('I18Nv2','l2l'), (array) $languages);
316     }
317     
318     /**
319      * Locale to language or language to locale
320      *
321      * @static
322      * @access  public
323      * @return  string
324      * @param   string  $localeOrLanguage
325      */
326     function l2l($localeOrLanguage)
327     {
328         return strtr($localeOrLanguage, '-_', '_-');
329     }
330     
331     /**
332      * Split locale code
333      * 
334      * Splits locale codes into its language and country part
335      *
336      * @static
337      * @access  public
338      * @return  array
339      * @param   string  $locale
340      */
341     function splitLocale($locale)
342     {
343         @list($l, $c) = preg_split('/[_-]/', $locale, 2, PREG_SPLIT_NO_EMPTY);
344         return array($l, $c);
345     }
346     
347     /**
348      * Get language code of locale
349      *
350      * @static
351      * @access  public
352      * @return  string
353      * @patram  string  $locale
354      */
355     function languageOf($locale)
356     {
357         return current($a = I18Nv2::splitLocale($locale));
358     }
359     
360     /**
361      * Get country code of locale
362      *
363      * @static
364      * @access  public
365      * @return  string
366      * @param   string  $locale
367      */
368     function countryOf($locale)
369     {
370         return end($a = I18Nv2::splitLocale($locale));
371     }
372     
373     /**
374      * Get access to static property
375      * 
376      * @static
377      * @access  public
378      * @return  mixed   Returns a reference to a static property
379      * @param   string  $property   the static property
380      */
381     static function &getStaticProperty($property)
382     {
383         static $properties;
384         return $properties[$property];
385     }
386     
387     /**
388      * This one gets called automatically
389      *
390      * @ignore
391      * @static
392      * @internal
393      * @access  private
394      * @return  void
395      */
396     static function _main()
397     {
398         // initialize the locale stack
399         $last = &I18Nv2::getStaticProperty('last');
400         $last = array();
401         
402         // map of "fully qualified locale" codes
403         $locales = &I18Nv2::getStaticProperty('locales');
404         $locales = array(
405             'af' => 'af_ZA',
406             'de' => 'de_DE',
407             'en' => 'en_US',
408             'fr' => 'fr_FR',
409             'it' => 'it_IT',
410             'es' => 'es_ES',
411             'pt' => 'pt_PT',
412             'sv' => 'sv_SE',
413             'nb' => 'nb_NO',
414             'nn' => 'nn_NO',
415             'no' => 'no_NO',
416             'fi' => 'fi_FI',
417             'is' => 'is_IS',
418             'da' => 'da_DK',
419             'nl' => 'nl_NL',
420             'pl' => 'pl_PL',
421             'sl' => 'sl_SI',
422             'hu' => 'hu_HU',
423             'ru' => 'ru_RU',
424             'cs' => 'cs_CZ',
425         );
426         
427         // define locale fallbacks
428         $fallbacks = &I18Nv2::getStaticProperty('fallbacks');
429         $fallbacks = array(
430             'no_NO' => 'nb_NO',
431             'nb_NO' => 'no_NO',
432         );
433         
434         // include Win32 locale codes
435         if (I18Nv2_WIN) {
436             include_once 'I18Nv2/Locale/Windows.php';
437         }
438     }
439 }
440
441 I18Nv2::_main();
442