1<?php
2/*
3   Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
4
5   Drop in replacement for native gettext.
6
7   This file is part of PHP-gettext.
8
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.
13
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.
18
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
22
23*/
24/*
25LC_CTYPE		0
26LC_NUMERIC	1
27LC_TIME			2
28LC_COLLATE	3
29LC_MONETARY	4
30LC_MESSAGES	5
31LC_ALL			6
32*/
33
34require('streams.php');
35require('gettext.php');
36
37
38// Variables
39
40global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
41$text_domains = array();
42$default_domain = 'default';
43$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
44$EMULATEGETTEXT = 0;
45$CURRENTLOCALE = '';
46
47
48// Utility functions
49
50/**
51 * Utility function to get a StreamReader for the given text domain.
52 */
53function _get_reader($domain=null, $category=5, $enable_cache=true) {
54	global $text_domains, $default_domain, $LC_CATEGORIES;
55	if (!isset($domain)) $domain = $default_domain;
56	if (!isset($text_domains[$domain]->l10n)) {
57		// get the current locale
58		$locale = _setlocale(LC_MESSAGES, 0);
59		$p = isset($text_domains[$domain]->path) ? $text_domains[$domain]->path : './';
60		$path = $p . "$locale/". $LC_CATEGORIES[$category] ."/$domain.mo";
61		if (file_exists($path)) {
62			$input = new FileReader($path);
63		}
64		else {
65			$input = null;
66		}
67		$text_domains[$domain]->l10n = new gettext_reader($input, $enable_cache);
68	}
69	return $text_domains[$domain]->l10n;
70}
71
72/**
73 * Returns whether we are using our emulated gettext API or PHP built-in one.
74 */
75function locale_emulation() {
76    global $EMULATEGETTEXT;
77    return $EMULATEGETTEXT;
78}
79
80/**
81 * Checks if the current locale is supported on this system.
82 */
83function _check_locale() {
84    global $EMULATEGETTEXT;
85    return !$EMULATEGETTEXT;
86}
87
88/**
89 * Get the codeset for the given domain.
90 */
91function _get_codeset($domain=null) {
92	global $text_domains, $default_domain, $LC_CATEGORIES;
93	if (!isset($domain)) $domain = $default_domain;
94	return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
95}
96
97/**
98 * Convert the given string to the encoding set by bind_textdomain_codeset.
99 */
100/*
101function _encode($text) {
102	$source_encoding = mb_detect_encoding($text);
103	$target_encoding = _get_codeset();
104	if ($source_encoding != $target_encoding) {
105		return mb_convert_encoding($text, $target_encoding, $source_encoding);
106	}
107	else {
108		return $text;
109	}
110}
111 *
112 */
113
114/**
115 * Convert the given string to the encoding set by bind_textdomain_codeset.
116 */
117function _encode($text) {
118
119	// If the mbstring extension for PHP is not enabled, mb_detect_encoding and mb_convert_encoding
120	// are not available.  If you are having problems with character encodings not working on your
121	// translation, please check with your webhost about how to enable mbstring for your PHP instance.
122	// See http://www.php.net/mbstring for more information.
123
124	if (function_exists('mb_detect_encoding')) {
125		$source_encoding = mb_detect_encoding($text);
126	}
127	else {
128		$source_encoding = 'UTF-8';
129	}
130
131	$target_encoding = _get_codeset();
132	if (($source_encoding != $target_encoding) && (function_exists('mb_convert_encoding'))) {
133		return mb_convert_encoding($text, $target_encoding, $source_encoding);
134	}
135	else {
136		return $text;
137	}
138}
139
140
141
142// Custom implementation of the standard gettext related functions
143
144/**
145 * Sets a requested locale, if needed emulates it.
146 */
147function _setlocale($category, $locale) {
148    global $CURRENTLOCALE, $EMULATEGETTEXT;
149    if ($locale === 0) { // use === to differentiate between string "0"
150        if ($CURRENTLOCALE != '')
151            return $CURRENTLOCALE;
152        else
153            // obey LANG variable, maybe extend to support all of LC_* vars
154            // even if we tried to read locale without setting it first
155            return _setlocale($category, $CURRENTLOCALE);
156    } else {
157        $ret = 0;
158        if (function_exists('setlocale')) // I don't know if this ever happens ;)
159           $ret = @setlocale($category, $locale);
160        if (($ret and $locale == '') or ($ret == $locale)) {
161            $EMULATEGETTEXT = 0;
162            $CURRENTLOCALE = $ret;
163        } else {
164  	    if ($locale == '') // emulate variable support
165 	        $CURRENTLOCALE = getenv('LANG');
166	    else
167	        $CURRENTLOCALE = $locale;
168            $EMULATEGETTEXT = 1;
169        }
170        return $CURRENTLOCALE;
171    }
172}
173
174/**
175 * Sets the path for a domain.
176 */
177function _bindtextdomain($domain, $path) {
178	global $text_domains;
179	// ensure $path ends with a slash
180	if ($path[strlen($path) - 1] != '/') $path .= '/';
181	elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
182	$text_domains[$domain]->path = $path;
183}
184
185/**
186 * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
187 */
188function _bind_textdomain_codeset($domain, $codeset) {
189	global $text_domains;
190	$text_domains[$domain]->codeset = $codeset;
191}
192
193/**
194 * Sets the default domain.
195 */
196function _textdomain($domain) {
197	global $default_domain;
198	$default_domain = $domain;
199}
200
201/**
202 * Lookup a message in the current domain.
203 */
204function _gettext($msgid) {
205	$l10n = _get_reader();
206	//return $l10n->translate($msgid);
207	return _encode($l10n->translate($msgid));
208}
209/**
210 * Alias for gettext.
211 */
212function __($msgid) {
213	return _gettext($msgid);
214}
215/**
216 * Plural version of gettext.
217 */
218function _ngettext($single, $plural, $number) {
219	$l10n = _get_reader();
220	//return $l10n->ngettext($single, $plural, $number);
221	return _encode($l10n->ngettext($single, $plural, $number));
222}
223
224/**
225 * Override the current domain.
226 */
227function _dgettext($domain, $msgid) {
228	$l10n = _get_reader($domain);
229	//return $l10n->translate($msgid);
230	return _encode($l10n->translate($msgid));
231}
232/**
233 * Plural version of dgettext.
234 */
235function _dngettext($domain, $single, $plural, $number) {
236	$l10n = _get_reader($domain);
237	//return $l10n->ngettext($single, $plural, $number);
238	return _encode($l10n->ngettext($single, $plural, $number));
239}
240
241/**
242 * Overrides the domain and category for a single lookup.
243 */
244function _dcgettext($domain, $msgid, $category) {
245	$l10n = _get_reader($domain, $category);
246	//return $l10n->translate($msgid);
247	return _encode($l10n->translate($msgid));
248}
249/**
250 * Plural version of dcgettext.
251 */
252function _dcngettext($domain, $single, $plural, $number, $category) {
253	$l10n = _get_reader($domain, $category);
254	//return $l10n->ngettext($single, $plural, $number);
255	return _encode($l10n->ngettext($single, $plural, $number));
256}
257
258
259
260// Wrappers to use if the standard gettext functions are available, but the current locale is not supported by the system.
261// Use the standard impl if the current locale is supported, use the custom impl otherwise.
262
263function T_setlocale($category, $locale) {
264    return _setlocale($category, $locale);
265}
266
267function T_bindtextdomain($domain, $path) {
268	if (_check_locale()) return bindtextdomain($domain, $path);
269	else return _bindtextdomain($domain, $path);
270}
271function T_bind_textdomain_codeset($domain, $codeset) {
272    // bind_textdomain_codeset is available only in PHP 4.2.0+
273	if (_check_locale() and function_exists('bind_textdomain_codeset')) return bind_textdomain_codeset($domain, $codeset);
274	else return _bind_textdomain_codeset($domain, $codeset);
275}
276function T_textdomain($domain) {
277	if (_check_locale()) return textdomain($domain);
278	else return _textdomain($domain);
279}
280function T_gettext($msgid) {
281	if (_check_locale()) return gettext($msgid);
282	else return _gettext($msgid);
283}
284function T_($msgid) {
285	if (_check_locale()) return _($msgid);
286	return __($msgid);
287}
288function T_ngettext($single, $plural, $number) {
289	if (_check_locale()) return ngettext($single, $plural, $number);
290	else return _ngettext($single, $plural, $number);
291}
292function T_dgettext($domain, $msgid) {
293	if (_check_locale()) return dgettext($domain, $msgid);
294	else return _dgettext($domain, $msgid);
295}
296function T_dngettext($domain, $single, $plural, $number) {
297	if (_check_locale()) return dngettext($domain, $single, $plural, $number);
298	else return _dngettext($domain, $single, $plural, $number);
299}
300function T_dcgettext($domain, $msgid, $category) {
301	if (_check_locale()) return dcgettext($domain, $msgid, $category);
302	else return _dcgettext($domain, $msgid, $category);
303}
304function T_dcngettext($domain, $single, $plural, $number, $category) {
305	if (_check_locale()) return dcngettext($domain, $single, $plural, $number, $category);
306	else return _dcngettext($domain, $single, $plural, $number, $category);
307}
308
309
310
311// Wrappers used as a drop in replacement for the standard gettext functions
312
313if (!function_exists('gettext')) {
314	function bindtextdomain($domain, $path) {
315		return _bindtextdomain($domain, $path);
316	}
317	function bind_textdomain_codeset($domain, $codeset) {
318		return _bind_textdomain_codeset($domain, $codeset);
319	}
320	function textdomain($domain) {
321		return _textdomain($domain);
322	}
323	function gettext($msgid) {
324		return _gettext($msgid);
325	}
326	function _($msgid) {
327		return __($msgid);
328	}
329	function ngettext($single, $plural, $number) {
330		return _ngettext($single, $plural, $number);
331	}
332	function dgettext($domain, $msgid) {
333		return _dgettext($domain, $msgid);
334	}
335	function dngettext($domain, $single, $plural, $number) {
336		return _dngettext($domain, $single, $plural, $number);
337	}
338	function dcgettext($domain, $msgid, $category) {
339		return _dcgettext($domain, $msgid, $category);
340	}
341	function dcngettext($domain, $single, $plural, $number, $category) {
342		return _dcngettext($domain, $single, $plural, $number, $category);
343	}
344}
345
346?>