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?>