Completed
Push — master ( 303d1b...008899 )
by Stefan
02:32
created

php-gettext/gettext.inc::_get_reader()   C

Complexity

Conditions 7
Paths 26

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 7
eloc 20
c 1
b 0
f 1
nc 26
nop 3
dl 0
loc 29
rs 6.7272
1
<?php
2
/*
3
   Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
4
   Copyright (c) 2009 Danilo Segan <[email protected]>
5
6
   Drop in replacement for native gettext.
7
8
   This file is part of PHP-gettext.
9
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.
14
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.
19
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
23
24
*/
25
/*
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
33
*/
34
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);
39
}
40
41
require('streams.php');
42
require('gettext.php');
43
44
45
// Variables
46
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 = '';
53
54
/* Class to hold a single domain included in $text_domains. */
55
class domain {
56
  var $l10n;
57
  var $path;
58
  var $codeset;
59
}
60
61
// Utility functions
62
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)) {
82
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"];
87
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
    }
105
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;
111
}
112
113
/**
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";
125
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
        }
135
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;
144
}
145
146
/**
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;
152
}
153
154
/**
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;
162
}
163
164
/**
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');
171
}
172
173
/**
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
    }
185
}
186
187
188
// Custom implementation of the standard gettext related functions
189
190
/**
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;
198
}
199
200
/**
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
    }
236
}
237
238
/**
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;
256
}
257
258
/**
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;
264
}
265
266
/**
267
 * Sets the default domain.
268
 */
269
function _textdomain($domain) {
270
    global $default_domain;
271
    $default_domain = $domain;
272
}
273
274
/**
275
 * Lookup a message in the current domain.
276
 */
277
function _gettext($msgid) {
278
    $l10n = _get_reader();
279
    return _encode($l10n->translate($msgid));
280
}
281
282
/**
283
 * Alias for gettext.
284
 */
285
function __($msgid) {
286
    return _gettext($msgid);
287
}
288
289
/**
290
 * Plural version of gettext.
291
 */
292
function _ngettext($singular, $plural, $number) {
293
    $l10n = _get_reader();
294
    return _encode($l10n->ngettext($singular, $plural, $number));
295
}
296
297
/**
298
 * Override the current domain.
299
 */
300
function _dgettext($domain, $msgid) {
301
    $l10n = _get_reader($domain);
302
    return _encode($l10n->translate($msgid));
303
}
304
305
/**
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));
311
}
312
313
/**
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));
319
}
320
/**
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));
326
}
327
328
/**
329
 * Context version of gettext.
330
 */
331
function _pgettext($context, $msgid) {
332
    $l10n = _get_reader();
333
    return _encode($l10n->pgettext($context, $msgid));
334
}
335
336
/**
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));
342
}
343
344
/**
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));
350
}
351
352
/**
353
 * Context version of ngettext.
354
 */
355
function _npgettext($context, $singular, $plural) {
356
    $l10n = _get_reader();
357
    return _encode($l10n->npgettext($context, $singular, $plural));
358
}
359
360
/**
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));
366
}
367
368
/**
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));
374
}
375
376
377
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.
382
383
function T_setlocale($category, $locale) {
384
    return _setlocale($category, $locale);
385
}
386
387
function T_bindtextdomain($domain, $path) {
388
    if (_check_locale_and_function()) return bindtextdomain($domain, $path);
389
    else return _bindtextdomain($domain, $path);
390
}
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);
396
}
397
function T_textdomain($domain) {
398
    if (_check_locale_and_function()) return textdomain($domain);
399
    else return _textdomain($domain);
400
}
401
function T_gettext($msgid) {
402
    if (_check_locale_and_function()) return gettext($msgid);
403
    else return _gettext($msgid);
404
}
405
function T_($msgid) {
406
    if (_check_locale_and_function()) return _($msgid);
407
    return __($msgid);
408
}
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);
413
}
414
function T_dgettext($domain, $msgid) {
415
    if (_check_locale_and_function()) return dgettext($domain, $msgid);
416
    else return _dgettext($domain, $msgid);
417
}
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);
422
}
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);
427
}
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);
432
}
433
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);
439
}
440
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);
446
}
447
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);
453
}
454
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);
460
}
461
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);
467
}
468
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);
477
}
478
479
480
481
// Wrappers used as a drop in replacement for the standard gettext functions
482
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
    }
534
}
535
536
?>
537