Translation update done using Pootle.
[phpmyadmin-themes.git] / libraries / php-gettext / gettext.inc
blob00b966692cc7d16e1acc19ed21bd0e1fd3afa46c
1 <?php
2 /*
3    Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
4    Copyright (c) 2009 Danilo Segan <danilo@kvota.net>
6    Drop in replacement for native gettext.
8    This file is part of PHP-gettext.
10    PHP-gettext is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
15    PHP-gettext is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
20    You should have received a copy of the GNU General Public License
21    along with PHP-gettext; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 LC_CTYPE        0
27 LC_NUMERIC      1
28 LC_TIME         2
29 LC_COLLATE      3
30 LC_MONETARY     4
31 LC_MESSAGES     5
32 LC_ALL          6
35 // LC_MESSAGES is not available if php-gettext is not loaded
36 // while the other constants are already available from session extension.
37 if (!defined('LC_MESSAGES')) {
38   define('LC_MESSAGES', 5);
41 require('streams.php');
42 require('gettext.php');
45 // Variables
47 global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
48 $text_domains = array();
49 $default_domain = 'messages';
50 $LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
51 $EMULATEGETTEXT = 0;
52 $CURRENTLOCALE = '';
54 /* Class to hold a single domain included in $text_domains. */
55 class domain {
56   var $l10n;
57   var $path;
58   var $codeset;
61 // Utility functions
63 /**
64  * Return a list of locales to try for any POSIX-style locale specification.
65  */
66 function get_list_of_locales($locale) {
67   /* Figure out all possible locale names and start with the most
68    * specific ones.  I.e. for sr_CS.UTF-8@latin, look through all of
69    * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
70    */
71   $locale_names = array();
72   $lang = NULL;
73   $country = NULL;
74   $charset = NULL;
75   $modifier = NULL;
76   if ($locale) {
77     if (preg_match("/^(?P<lang>[a-z]{2,3})"              // language code
78                    ."(?:_(?P<country>[A-Z]{2}))?"           // country code
79                    ."(?:\.(?P<charset>[-A-Za-z0-9_]+))?"    // charset
80                    ."(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/",  // @ modifier
81                    $locale, $matches)) {
83       if (isset($matches["lang"])) $lang = $matches["lang"];
84       if (isset($matches["country"])) $country = $matches["country"];
85       if (isset($matches["charset"])) $charset = $matches["charset"];
86       if (isset($matches["modifier"])) $modifier = $matches["modifier"];
88       if ($modifier) {
89         if ($country) {
90           if ($charset)
91             array_push($locale_names, "${lang}_$country.$charset@$modifier");
92           array_push($locale_names, "${lang}_$country@$modifier");
93         } elseif ($charset)
94             array_push($locale_names, "${lang}.$charset@$modifier");
95         array_push($locale_names, "$lang@$modifier");
96       }
97       if ($country) {
98         if ($charset)
99           array_push($locale_names, "${lang}_$country.$charset");
100         array_push($locale_names, "${lang}_$country");
101       } elseif ($charset)
102           array_push($locale_names, "${lang}.$charset");
103       array_push($locale_names, $lang);
104     }
106     // If the locale name doesn't match POSIX style, just include it as-is.
107     if (!in_array($locale, $locale_names))
108       array_push($locale_names, $locale);
109   }
110   return $locale_names;
114  * Utility function to get a StreamReader for the given text domain.
115  */
116 function _get_reader($domain=null, $category=5, $enable_cache=true) {
117     global $text_domains, $default_domain, $LC_CATEGORIES;
118     if (!isset($domain)) $domain = $default_domain;
119     if (!isset($text_domains[$domain]->l10n)) {
120         // get the current locale
121         $locale = _setlocale(LC_MESSAGES, 0);
122         $bound_path = isset($text_domains[$domain]->path) ?
123           $text_domains[$domain]->path : './';
124         $subpath = $LC_CATEGORIES[$category] ."/$domain.mo";
126         $locale_names = get_list_of_locales($locale);
127         $input = null;
128         foreach ($locale_names as $locale) {
129           $full_path = $bound_path . $locale . "/" . $subpath;
130           if (file_exists($full_path)) {
131             $input = new FileReader($full_path);
132             break;
133           }
134         }
136         if (!array_key_exists($domain, $text_domains)) {
137           // Initialize an empty domain object.
138           $text_domains[$domain] = new domain();
139         }
140         $text_domains[$domain]->l10n = new gettext_reader($input,
141                                                           $enable_cache);
142     }
143     return $text_domains[$domain]->l10n;
147  * Returns whether we are using our emulated gettext API or PHP built-in one.
148  */
149 function locale_emulation() {
150     global $EMULATEGETTEXT;
151     return $EMULATEGETTEXT;
155  * Checks if the current locale is supported on this system.
156  */
157 function _check_locale_and_function($function=false) {
158     global $EMULATEGETTEXT;
159     if ($function and !function_exists($function))
160         return false;
161     return !$EMULATEGETTEXT;
165  * Get the codeset for the given domain.
166  */
167 function _get_codeset($domain=null) {
168     global $text_domains, $default_domain, $LC_CATEGORIES;
169     if (!isset($domain)) $domain = $default_domain;
170     return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
174  * Convert the given string to the encoding set by bind_textdomain_codeset.
175  */
176 function _encode($text) {
177     $source_encoding = mb_detect_encoding($text);
178     $target_encoding = _get_codeset();
179     if ($source_encoding != $target_encoding) {
180         return mb_convert_encoding($text, $target_encoding, $source_encoding);
181     }
182     else {
183         return $text;
184     }
188 // Custom implementation of the standard gettext related functions
191  * Returns passed in $locale, or environment variable $LANG if $locale == ''.
192  */
193 function _get_default_locale($locale) {
194   if ($locale == '') // emulate variable support
195     return getenv('LANG');
196   else
197     return $locale;
201  * Sets a requested locale, if needed emulates it.
202  */
203 function _setlocale($category, $locale) {
204     global $CURRENTLOCALE, $EMULATEGETTEXT;
205     if ($locale === 0) { // use === to differentiate between string "0"
206         if ($CURRENTLOCALE != '')
207             return $CURRENTLOCALE;
208         else
209             // obey LANG variable, maybe extend to support all of LC_* vars
210             // even if we tried to read locale without setting it first
211             return _setlocale($category, $CURRENTLOCALE);
212     } else {
213         if (function_exists('setlocale')) {
214           $ret = setlocale($category, $locale);
215           if (($locale == '' and !$ret) or // failed setting it by env
216               ($locale != '' and $ret != $locale)) { // failed setting it
217             // Failed setting it according to environment.
218             $CURRENTLOCALE = _get_default_locale($locale);
219             $EMULATEGETTEXT = 1;
220           } else {
221             $CURRENTLOCALE = $ret;
222             $EMULATEGETTEXT = 0;
223           }
224         } else {
225           // No function setlocale(), emulate it all.
226           $CURRENTLOCALE = _get_default_locale($locale);
227           $EMULATEGETTEXT = 1;
228         }
229         // Allow locale to be changed on the go for one translation domain.
230         global $text_domains, $default_domain;
231         if (array_key_exists($default_domain, $text_domains)) {
232             unset($text_domains[$default_domain]->l10n);
233         }
234         return $CURRENTLOCALE;
235     }
239  * Sets the path for a domain.
240  */
241 function _bindtextdomain($domain, $path) {
242     global $text_domains;
243     // ensure $path ends with a slash ('/' should work for both, but lets still play nice)
244     if (substr(php_uname(), 0, 7) == "Windows") {
245       if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/')
246         $path .= '\\';
247     } else {
248       if ($path[strlen($path)-1] != '/')
249         $path .= '/';
250     }
251     if (!array_key_exists($domain, $text_domains)) {
252       // Initialize an empty domain object.
253       $text_domains[$domain] = new domain();
254     }
255     $text_domains[$domain]->path = $path;
259  * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
260  */
261 function _bind_textdomain_codeset($domain, $codeset) {
262     global $text_domains;
263     $text_domains[$domain]->codeset = $codeset;
267  * Sets the default domain.
268  */
269 function _textdomain($domain) {
270     global $default_domain;
271     $default_domain = $domain;
275  * Lookup a message in the current domain.
276  */
277 function _gettext($msgid) {
278     $l10n = _get_reader();
279     return _encode($l10n->translate($msgid));
283  * Alias for gettext.
284  */
285 function __($msgid) {
286     return _gettext($msgid);
290  * Plural version of gettext.
291  */
292 function _ngettext($singular, $plural, $number) {
293     $l10n = _get_reader();
294     return _encode($l10n->ngettext($singular, $plural, $number));
298  * Override the current domain.
299  */
300 function _dgettext($domain, $msgid) {
301     $l10n = _get_reader($domain);
302     return _encode($l10n->translate($msgid));
306  * Plural version of dgettext.
307  */
308 function _dngettext($domain, $singular, $plural, $number) {
309     $l10n = _get_reader($domain);
310     return _encode($l10n->ngettext($singular, $plural, $number));
314  * Overrides the domain and category for a single lookup.
315  */
316 function _dcgettext($domain, $msgid, $category) {
317     $l10n = _get_reader($domain, $category);
318     return _encode($l10n->translate($msgid));
321  * Plural version of dcgettext.
322  */
323 function _dcngettext($domain, $singular, $plural, $number, $category) {
324     $l10n = _get_reader($domain, $category);
325     return _encode($l10n->ngettext($singular, $plural, $number));
329  * Context version of gettext.
330  */
331 function _pgettext($context, $msgid) {
332     $l10n = _get_reader();
333     return _encode($l10n->pgettext($context, $msgid));
337  * Override the current domain in a context gettext call.
338  */
339 function _dpgettext($domain, $context, $msgid) {
340     $l10n = _get_reader($domain);
341     return _encode($l10n->pgettext($context, $msgid));
345  * Overrides the domain and category for a single context-based lookup.
346  */
347 function _dcpgettext($domain, $context, $msgid, $category) {
348     $l10n = _get_reader($domain, $category);
349     return _encode($l10n->pgettext($context, $msgid));
353  * Context version of ngettext.
354  */
355 function _npgettext($context, $singular, $plural) {
356     $l10n = _get_reader();
357     return _encode($l10n->npgettext($context, $singular, $plural));
361  * Override the current domain in a context ngettext call.
362  */
363 function _dnpgettext($domain, $context, $singular, $plural) {
364     $l10n = _get_reader($domain);
365     return _encode($l10n->npgettext($context, $singular, $plural));
369  * Overrides the domain and category for a plural context-based lookup.
370  */
371 function _dcnpgettext($domain, $context, $singular, $plural, $category) {
372     $l10n = _get_reader($domain, $category);
373     return _encode($l10n->npgettext($context, $singular, $plural));
378 // Wrappers to use if the standard gettext functions are available,
379 // but the current locale is not supported by the system.
380 // Use the standard impl if the current locale is supported, use the
381 // custom impl otherwise.
383 function T_setlocale($category, $locale) {
384     return _setlocale($category, $locale);
387 function T_bindtextdomain($domain, $path) {
388     if (_check_locale_and_function()) return bindtextdomain($domain, $path);
389     else return _bindtextdomain($domain, $path);
391 function T_bind_textdomain_codeset($domain, $codeset) {
392     // bind_textdomain_codeset is available only in PHP 4.2.0+
393     if (_check_locale_and_function('bind_textdomain_codeset'))
394         return bind_textdomain_codeset($domain, $codeset);
395     else return _bind_textdomain_codeset($domain, $codeset);
397 function T_textdomain($domain) {
398     if (_check_locale_and_function()) return textdomain($domain);
399     else return _textdomain($domain);
401 function T_gettext($msgid) {
402     if (_check_locale_and_function()) return gettext($msgid);
403     else return _gettext($msgid);
405 function T_($msgid) {
406     if (_check_locale_and_function()) return _($msgid);
407     return __($msgid);
409 function T_ngettext($singular, $plural, $number) {
410     if (_check_locale_and_function())
411         return ngettext($singular, $plural, $number);
412     else return _ngettext($singular, $plural, $number);
414 function T_dgettext($domain, $msgid) {
415     if (_check_locale_and_function()) return dgettext($domain, $msgid);
416     else return _dgettext($domain, $msgid);
418 function T_dngettext($domain, $singular, $plural, $number) {
419     if (_check_locale_and_function())
420         return dngettext($domain, $singular, $plural, $number);
421     else return _dngettext($domain, $singular, $plural, $number);
423 function T_dcgettext($domain, $msgid, $category) {
424     if (_check_locale_and_function())
425         return dcgettext($domain, $msgid, $category);
426     else return _dcgettext($domain, $msgid, $category);
428 function T_dcngettext($domain, $singular, $plural, $number, $category) {
429     if (_check_locale_and_function())
430       return dcngettext($domain, $singular, $plural, $number, $category);
431     else return _dcngettext($domain, $singular, $plural, $number, $category);
434 function T_pgettext($context, $msgid) {
435   if (_check_locale_and_function('pgettext'))
436       return pgettext($context, $msgid);
437   else
438       return _pgettext($context, $msgid);
441 function T_dpgettext($domain, $context, $msgid) {
442   if (_check_locale_and_function('dpgettext'))
443       return dpgettext($domain, $context, $msgid);
444   else
445       return _dpgettext($domain, $context, $msgid);
448 function T_dcpgettext($domain, $context, $msgid, $category) {
449   if (_check_locale_and_function('dcpgettext'))
450       return dcpgettext($domain, $context, $msgid, $category);
451   else
452       return _dcpgettext($domain, $context, $msgid, $category);
455 function T_npgettext($context, $singular, $plural, $number) {
456     if (_check_locale_and_function('npgettext'))
457         return npgettext($context, $singular, $plural, $number);
458     else
459         return _npgettext($context, $singular, $plural, $number);
462 function T_dnpgettext($domain, $context, $singular, $plural, $number) {
463   if (_check_locale_and_function('dnpgettext'))
464       return dnpgettext($domain, $context, $singular, $plural, $number);
465   else
466       return _dnpgettext($domain, $context, $singular, $plural, $number);
469 function T_dcnpgettext($domain, $context, $singular, $plural,
470                        $number, $category) {
471     if (_check_locale_and_function('dcnpgettext'))
472         return dcnpgettext($domain, $context, $singular,
473                            $plural, $number, $category);
474     else
475         return _dcnpgettext($domain, $context, $singular,
476                             $plural, $number, $category);
481 // Wrappers used as a drop in replacement for the standard gettext functions
483 if (!function_exists('gettext')) {
484     function bindtextdomain($domain, $path) {
485         return _bindtextdomain($domain, $path);
486     }
487     function bind_textdomain_codeset($domain, $codeset) {
488         return _bind_textdomain_codeset($domain, $codeset);
489     }
490     function textdomain($domain) {
491         return _textdomain($domain);
492     }
493     function gettext($msgid) {
494         return _gettext($msgid);
495     }
496     function _($msgid) {
497         return __($msgid);
498     }
499     function ngettext($singular, $plural, $number) {
500         return _ngettext($singular, $plural, $number);
501     }
502     function dgettext($domain, $msgid) {
503         return _dgettext($domain, $msgid);
504     }
505     function dngettext($domain, $singular, $plural, $number) {
506         return _dngettext($domain, $singular, $plural, $number);
507     }
508     function dcgettext($domain, $msgid, $category) {
509         return _dcgettext($domain, $msgid, $category);
510     }
511     function dcngettext($domain, $singular, $plural, $number, $category) {
512         return _dcngettext($domain, $singular, $plural, $number, $category);
513     }
514     function pgettext($context, $msgid) {
515         return _pgettext($context, $msgid);
516     }
517     function npgettext($context, $singular, $plural, $number) {
518         return _npgettext($context, $singular, $plural, $number);
519     }
520     function dpgettext($domain, $context, $msgid) {
521         return _dpgettext($domain, $context, $msgid);
522     }
523     function dnpgettext($domain, $context, $singular, $plural, $number) {
524         return _dnpgettext($domain, $context, $singular, $plural, $number);
525     }
526     function dcpgettext($domain, $context, $msgid, $category) {
527         return _dcpgettext($domain, $context, $msgid, $category);
528     }
529     function dcnpgettext($domain, $context, $singular, $plural,
530                          $number, $category) {
531       return _dcnpgettext($domain, $context, $singular, $plural,
532                           $number, $category);
533     }