3 Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
5 Drop in replacement for native gettext.
7 This file is part of PHP-gettext.
9 PHP-gettext is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 PHP-gettext is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with PHP-gettext; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 require(dirname(__FILE__) .'/streams.php');
35 require(dirname(__FILE__) .'/gettext.php');
39 global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
40 $text_domains = array();
41 $default_domain = 'messages';
42 $LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
50 * Utility function to get a StreamReader for the given text domain.
52 function _get_reader($domain=null, $category=5, $enable_cache=true) {
53 global $text_domains, $default_domain, $LC_CATEGORIES;
54 if (!isset($domain)) $domain = $default_domain;
55 if (!isset($text_domains[$domain]->l10n)) {
56 // get the current locale
57 $locale = _setlocale(LC_MESSAGES, 0);
58 $p = isset($text_domains[$domain]->path) ? $text_domains[$domain]->path : './';
59 $path = $p . "$locale/". $LC_CATEGORIES[$category] ."/$domain.mo";
60 if (file_exists($path)) {
61 $input = new FileReader($path);
66 $text_domains[$domain]->l10n = new gettext_reader($input, $enable_cache);
68 return $text_domains[$domain]->l10n;
72 * Returns whether we are using our emulated gettext API or PHP built-in one.
74 function locale_emulation() {
75 global $EMULATEGETTEXT;
76 return $EMULATEGETTEXT;
80 * Checks if the current locale is supported on this system.
82 function _check_locale() {
83 global $EMULATEGETTEXT;
84 return !$EMULATEGETTEXT;
88 * Get the codeset for the given domain.
90 function _get_codeset($domain=null) {
91 global $text_domains, $default_domain, $LC_CATEGORIES;
92 if (!isset($domain)) $domain = $default_domain;
93 return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
97 * Convert the given string to the encoding set by bind_textdomain_codeset.
99 function _encode($text) {
100 $source_encoding = mb_detect_encoding($text);
101 $target_encoding = _get_codeset();
102 if ($source_encoding != $target_encoding) {
103 return mb_convert_encoding($text, $target_encoding, $source_encoding);
113 // Custom implementation of the standard gettext related functions
116 * Sets a requested locale, if needed emulates it.
118 function _setlocale($category, $locale) {
119 global $CURRENTLOCALE, $EMULATEGETTEXT;
120 if ($locale === 0) { // use === to differentiate between string "0"
121 if ($CURRENTLOCALE != '')
122 return $CURRENTLOCALE;
124 // obey LANG variable, maybe extend to support all of LC_* vars
125 // even if we tried to read locale without setting it first
126 return _setlocale($category, $CURRENTLOCALE);
129 if (function_exists('setlocale')) // I don't know if this ever happens ;)
130 $ret = setlocale($category, $locale);
131 if (($ret and $locale == '') or ($ret == $locale)) {
133 $CURRENTLOCALE = $ret;
135 if ($locale == '') // emulate variable support
136 $CURRENTLOCALE = getenv('LANG');
138 $CURRENTLOCALE = $locale;
141 return $CURRENTLOCALE;
146 * Sets the path for a domain.
148 function _bindtextdomain($domain, $path) {
149 global $text_domains;
150 // ensure $path ends with a slash
151 if ($path[strlen($path) - 1] != '/') $path .= '/';
152 elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
153 $text_domains[$domain]->path = $path;
157 * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
159 function _bind_textdomain_codeset($domain, $codeset) {
160 global $text_domains;
161 $text_domains[$domain]->codeset = $codeset;
165 * Sets the default domain.
167 function _textdomain($domain) {
168 global $default_domain;
169 $default_domain = $domain;
173 * Lookup a message in the current domain.
175 function _gettext($msgid) {
176 $l10n = _get_reader();
177 //return $l10n->translate($msgid);
178 return _encode($l10n->translate($msgid));
183 function __($msgid) {
184 return _gettext($msgid);
187 * Plural version of gettext.
189 function _ngettext($single, $plural, $number) {
190 $l10n = _get_reader();
191 //return $l10n->ngettext($single, $plural, $number);
192 return _encode($l10n->ngettext($single, $plural, $number));
196 * Override the current domain.
198 function _dgettext($domain, $msgid) {
199 $l10n = _get_reader($domain);
200 //return $l10n->translate($msgid);
201 return _encode($l10n->translate($msgid));
204 * Plural version of dgettext.
206 function _dngettext($domain, $single, $plural, $number) {
207 $l10n = _get_reader($domain);
208 //return $l10n->ngettext($single, $plural, $number);
209 return _encode($l10n->ngettext($single, $plural, $number));
213 * Overrides the domain and category for a single lookup.
215 function _dcgettext($domain, $msgid, $category) {
216 $l10n = _get_reader($domain, $category);
217 //return $l10n->translate($msgid);
218 return _encode($l10n->translate($msgid));
221 * Plural version of dcgettext.
223 function _dcngettext($domain, $single, $plural, $number, $category) {
224 $l10n = _get_reader($domain, $category);
225 //return $l10n->ngettext($single, $plural, $number);
226 return _encode($l10n->ngettext($single, $plural, $number));
231 // Wrappers to use if the standard gettext functions are available, but the current locale is not supported by the system.
232 // Use the standard impl if the current locale is supported, use the custom impl otherwise.
234 function T_setlocale($category, $locale) {
235 return _setlocale($category, $locale);
238 function T_bindtextdomain($domain, $path) {
239 if (_check_locale()) return bindtextdomain($domain, $path);
240 else return _bindtextdomain($domain, $path);
242 function T_bind_textdomain_codeset($domain, $codeset) {
243 // bind_textdomain_codeset is available only in PHP 4.2.0+
244 if (_check_locale() and function_exists('bind_textdomain_codeset')) return bind_textdomain_codeset($domain, $codeset);
245 else return _bind_textdomain_codeset($domain, $codeset);
247 function T_textdomain($domain) {
248 if (_check_locale()) return textdomain($domain);
249 else return _textdomain($domain);
251 function T_gettext($msgid) {
252 if (_check_locale()) return gettext($msgid);
253 else return _gettext($msgid);
255 function T_($msgid) {
256 if (_check_locale()) return _($msgid);
259 function T_ngettext($single, $plural, $number) {
260 if (_check_locale()) return ngettext($single, $plural, $number);
261 else return _ngettext($single, $plural, $number);
263 function T_dgettext($domain, $msgid) {
264 if (_check_locale()) return dgettext($domain, $msgid);
265 else return _dgettext($domain, $msgid);
267 function T_dngettext($domain, $single, $plural, $number) {
268 if (_check_locale()) return dngettext($domain, $single, $plural, $number);
269 else return _dngettext($domain, $single, $plural, $number);
271 function T_dcgettext($domain, $msgid, $category) {
272 if (_check_locale()) return dcgettext($domain, $msgid, $category);
273 else return _dcgettext($domain, $msgid, $category);
275 function T_dcngettext($domain, $single, $plural, $number, $category) {
276 if (_check_locale()) return dcngettext($domain, $single, $plural, $number, $category);
277 else return _dcngettext($domain, $single, $plural, $number, $category);
282 // Wrappers used as a drop in replacement for the standard gettext functions
284 if (!function_exists('gettext')) {
285 function bindtextdomain($domain, $path) {
286 return _bindtextdomain($domain, $path);
288 function bind_textdomain_codeset($domain, $codeset) {
289 return _bind_textdomain_codeset($domain, $codeset);
291 function textdomain($domain) {
292 return _textdomain($domain);
294 function gettext($msgid) {
295 return _gettext($msgid);
300 function ngettext($single, $plural, $number) {
301 return _ngettext($single, $plural, $number);
303 function dgettext($domain, $msgid) {
304 return _dgettext($domain, $msgid);
306 function dngettext($domain, $single, $plural, $number) {
307 return _dngettext($domain, $single, $plural, $number);
309 function dcgettext($domain, $msgid, $category) {
310 return _dcgettext($domain, $msgid, $category);
312 function dcngettext($domain, $single, $plural, $number, $category) {
313 return _dcngettext($domain, $single, $plural, $number, $category);