X-Git-Url: https://projects.mako.cc/source/scuttle/blobdiff_plain/e3d34a49246237c9dbcb56db37d4f5807f87b01c..7e8b3ec9903f52ae787c67f27761ed3a7baf6d11:/includes/php-gettext/gettext.inc diff --git a/includes/php-gettext/gettext.inc b/includes/php-gettext/gettext.inc index 21a41cc..399a0f2 100644 --- a/includes/php-gettext/gettext.inc +++ b/includes/php-gettext/gettext.inc @@ -1,9 +1,10 @@ - + Copyright (c) 2009 Danilo Segan + Drop in replacement for native gettext. - + This file is part of PHP-gettext. PHP-gettext is free software; you can redistribute it and/or modify @@ -22,17 +23,25 @@ */ /* -LC_CTYPE 0 -LC_NUMERIC 1 -LC_TIME 2 -LC_COLLATE 3 -LC_MONETARY 4 -LC_MESSAGES 5 -LC_ALL 6 +LC_CTYPE 0 +LC_NUMERIC 1 +LC_TIME 2 +LC_COLLATE 3 +LC_MONETARY 4 +LC_MESSAGES 5 +LC_ALL 6 */ -require(dirname(__FILE__) .'/streams.php'); -require(dirname(__FILE__) .'/gettext.php'); + +// LC_MESSAGES is not available if php-gettext is not loaded +// while the other constants are already available from session extension. +if (!defined('LC_MESSAGES')) { + define('LC_MESSAGES', 5); +} + +require('streams.php'); +require('gettext.php'); + // Variables @@ -43,29 +52,96 @@ $LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MO $EMULATEGETTEXT = 0; $CURRENTLOCALE = ''; +/* Class to hold a single domain included in $text_domains. */ +class domain { + var $l10n; + var $path; + var $codeset; +} // Utility functions +/** + * Return a list of locales to try for any POSIX-style locale specification. + */ +function get_list_of_locales($locale) { + /* Figure out all possible locale names and start with the most + * specific ones. I.e. for sr_CS.UTF-8@latin, look through all of + * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr. + */ + $locale_names = array(); + $lang = NULL; + $country = NULL; + $charset = NULL; + $modifier = NULL; + if ($locale) { + if (preg_match("/^(?P[a-z]{2,3})" // language code + ."(?:_(?P[A-Z]{2}))?" // country code + ."(?:\.(?P[-A-Za-z0-9_]+))?" // charset + ."(?:@(?P[-A-Za-z0-9_]+))?$/", // @ modifier + $locale, $matches)) { + + if (isset($matches["lang"])) $lang = $matches["lang"]; + if (isset($matches["country"])) $country = $matches["country"]; + if (isset($matches["charset"])) $charset = $matches["charset"]; + if (isset($matches["modifier"])) $modifier = $matches["modifier"]; + + if ($modifier) { + if ($country) { + if ($charset) + array_push($locale_names, "${lang}_$country.$charset@$modifier"); + array_push($locale_names, "${lang}_$country@$modifier"); + } elseif ($charset) + array_push($locale_names, "${lang}.$charset@$modifier"); + array_push($locale_names, "$lang@$modifier"); + } + if ($country) { + if ($charset) + array_push($locale_names, "${lang}_$country.$charset"); + array_push($locale_names, "${lang}_$country"); + } elseif ($charset) + array_push($locale_names, "${lang}.$charset"); + array_push($locale_names, $lang); + } + + // If the locale name doesn't match POSIX style, just include it as-is. + if (!in_array($locale, $locale_names)) + array_push($locale_names, $locale); + } + return $locale_names; +} + /** * Utility function to get a StreamReader for the given text domain. */ function _get_reader($domain=null, $category=5, $enable_cache=true) { - global $text_domains, $default_domain, $LC_CATEGORIES; - if (!isset($domain)) $domain = $default_domain; - if (!isset($text_domains[$domain]->l10n)) { - // get the current locale - $locale = _setlocale(LC_MESSAGES, 0); - $p = isset($text_domains[$domain]->path) ? $text_domains[$domain]->path : './'; - $path = $p . "$locale/". $LC_CATEGORIES[$category] ."/$domain.mo"; - if (file_exists($path)) { - $input = new FileReader($path); - } - else { - $input = null; - } - $text_domains[$domain]->l10n = new gettext_reader($input, $enable_cache); - } - return $text_domains[$domain]->l10n; + global $text_domains, $default_domain, $LC_CATEGORIES; + if (!isset($domain)) $domain = $default_domain; + if (!isset($text_domains[$domain]->l10n)) { + // get the current locale + $locale = _setlocale(LC_MESSAGES, 0); + $bound_path = isset($text_domains[$domain]->path) ? + $text_domains[$domain]->path : './'; + $subpath = $LC_CATEGORIES[$category] ."/$domain.mo"; + + $locale_names = get_list_of_locales($locale); + $input = null; + foreach ($locale_names as $locale) { + $full_path = $bound_path . $locale . "/" . $subpath; + if (file_exists($full_path)) { + $input = new FileReader($full_path); + break; + } + } + + if (!array_key_exists($domain, $text_domains)) { + // Initialize an empty domain object. + $text_domains[$domain] = new domain(); + } + $text_domains[$domain]->l10n = new gettext_reader($input, + $enable_cache); + } + return $text_domains[$domain]->l10n; } /** @@ -79,8 +155,10 @@ function locale_emulation() { /** * Checks if the current locale is supported on this system. */ -function _check_locale() { +function _check_locale_and_function($function=false) { global $EMULATEGETTEXT; + if ($function and !function_exists($function)) + return false; return !$EMULATEGETTEXT; } @@ -88,56 +166,70 @@ function _check_locale() { * Get the codeset for the given domain. */ function _get_codeset($domain=null) { - global $text_domains, $default_domain, $LC_CATEGORIES; - if (!isset($domain)) $domain = $default_domain; - return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding'); + global $text_domains, $default_domain, $LC_CATEGORIES; + if (!isset($domain)) $domain = $default_domain; + return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding'); } /** * Convert the given string to the encoding set by bind_textdomain_codeset. */ function _encode($text) { - $source_encoding = mb_detect_encoding($text); - $target_encoding = _get_codeset(); - if ($source_encoding != $target_encoding) { - return mb_convert_encoding($text, $target_encoding, $source_encoding); - } - else { - return $text; - } + $source_encoding = mb_detect_encoding($text); + $target_encoding = _get_codeset(); + if ($source_encoding != $target_encoding) { + return mb_convert_encoding($text, $target_encoding, $source_encoding); + } + else { + return $text; + } } - - // Custom implementation of the standard gettext related functions +/** + * Returns passed in $locale, or environment variable $LANG if $locale == ''. + */ +function _get_default_locale($locale) { + if ($locale == '') // emulate variable support + return getenv('LANG'); + else + return $locale; +} + /** * Sets a requested locale, if needed emulates it. */ function _setlocale($category, $locale) { global $CURRENTLOCALE, $EMULATEGETTEXT; if ($locale === 0) { // use === to differentiate between string "0" - if ($CURRENTLOCALE != '') + if ($CURRENTLOCALE != '') return $CURRENTLOCALE; - else + else // obey LANG variable, maybe extend to support all of LC_* vars // even if we tried to read locale without setting it first return _setlocale($category, $CURRENTLOCALE); } else { - $ret = 0; - if (function_exists('setlocale')) // I don't know if this ever happens ;) - $ret = setlocale($category, $locale); - if (($ret and $locale == '') or ($ret == $locale)) { - $EMULATEGETTEXT = 0; + if (function_exists('setlocale')) { + $ret = setlocale($category, $locale); + if (($locale == '' and !$ret) or // failed setting it by env + ($locale != '' and $ret != $locale)) { // failed setting it + // Failed setting it according to environment. + $CURRENTLOCALE = _get_default_locale($locale); + $EMULATEGETTEXT = 1; + } else { $CURRENTLOCALE = $ret; + $EMULATEGETTEXT = 0; + } } else { - if ($locale == '') // emulate variable support - $CURRENTLOCALE = getenv('LANG'); - else - $CURRENTLOCALE = $locale; - $EMULATEGETTEXT = 1; + // No function setlocale(), emulate it all. + $CURRENTLOCALE = _get_default_locale($locale); + $EMULATEGETTEXT = 1; } + // Allow locale to be changed on the go for one translation domain. + global $text_domains, $default_domain; + unset($text_domains[$default_domain]->l10n); return $CURRENTLOCALE; } } @@ -146,135 +238,240 @@ function _setlocale($category, $locale) { * Sets the path for a domain. */ function _bindtextdomain($domain, $path) { - global $text_domains; - // ensure $path ends with a slash - if ($path[strlen($path) - 1] != '/') $path .= '/'; - elseif ($path[strlen($path) - 1] != '\\') $path .= '\\'; - $text_domains[$domain]->path = $path; + global $text_domains; + // ensure $path ends with a slash ('/' should work for both, but lets still play nice) + if (substr(php_uname(), 0, 7) == "Windows") { + if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/') + $path .= '\\'; + } else { + if ($path[strlen($path)-1] != '/') + $path .= '/'; + } + if (!array_key_exists($domain, $text_domains)) { + // Initialize an empty domain object. + $text_domains[$domain] = new domain(); + } + $text_domains[$domain]->path = $path; } /** * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned. */ function _bind_textdomain_codeset($domain, $codeset) { - global $text_domains; - $text_domains[$domain]->codeset = $codeset; + global $text_domains; + $text_domains[$domain]->codeset = $codeset; } /** * Sets the default domain. */ function _textdomain($domain) { - global $default_domain; - $default_domain = $domain; + global $default_domain; + $default_domain = $domain; } /** * Lookup a message in the current domain. */ function _gettext($msgid) { - $l10n = _get_reader(); - //return $l10n->translate($msgid); - return _encode($l10n->translate($msgid)); + $l10n = _get_reader(); + return _encode($l10n->translate($msgid)); } + /** * Alias for gettext. */ function __($msgid) { - return _gettext($msgid); + return _gettext($msgid); } + /** * Plural version of gettext. */ function _ngettext($single, $plural, $number) { - $l10n = _get_reader(); - //return $l10n->ngettext($single, $plural, $number); - return _encode($l10n->ngettext($single, $plural, $number)); + $l10n = _get_reader(); + return _encode($l10n->ngettext($single, $plural, $number)); } /** * Override the current domain. */ function _dgettext($domain, $msgid) { - $l10n = _get_reader($domain); - //return $l10n->translate($msgid); - return _encode($l10n->translate($msgid)); + $l10n = _get_reader($domain); + return _encode($l10n->translate($msgid)); } + /** * Plural version of dgettext. */ function _dngettext($domain, $single, $plural, $number) { - $l10n = _get_reader($domain); - //return $l10n->ngettext($single, $plural, $number); - return _encode($l10n->ngettext($single, $plural, $number)); + $l10n = _get_reader($domain); + return _encode($l10n->ngettext($single, $plural, $number)); } /** * Overrides the domain and category for a single lookup. */ function _dcgettext($domain, $msgid, $category) { - $l10n = _get_reader($domain, $category); - //return $l10n->translate($msgid); - return _encode($l10n->translate($msgid)); + $l10n = _get_reader($domain, $category); + return _encode($l10n->translate($msgid)); } /** * Plural version of dcgettext. */ function _dcngettext($domain, $single, $plural, $number, $category) { - $l10n = _get_reader($domain, $category); - //return $l10n->ngettext($single, $plural, $number); - return _encode($l10n->ngettext($single, $plural, $number)); + $l10n = _get_reader($domain, $category); + return _encode($l10n->ngettext($single, $plural, $number)); } +/** + * Context version of gettext. + */ +function _pgettext($context, $msgid) { + $l10n = _get_reader(); + return _encode($l10n->pgettext($context, $msgid)); +} +/** + * Override the current domain in a context gettext call. + */ +function _dpgettext($domain, $context, $msgid) { + $l10n = _get_reader($domain); + return _encode($l10n->pgettext($context, $msgid)); +} -// Wrappers to use if the standard gettext functions are available, but the current locale is not supported by the system. -// Use the standard impl if the current locale is supported, use the custom impl otherwise. +/** + * Overrides the domain and category for a single context-based lookup. + */ +function _dcpgettext($domain, $context, $msgid, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Context version of ngettext. + */ +function _npgettext($context, $singular, $plural) { + $l10n = _get_reader(); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + +/** + * Override the current domain in a context ngettext call. + */ +function _dnpgettext($domain, $context, $singular, $plural) { + $l10n = _get_reader($domain); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + +/** + * Overrides the domain and category for a plural context-based lookup. + */ +function _dcnpgettext($domain, $context, $singular, $plural, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + + + +// Wrappers to use if the standard gettext functions are available, +// but the current locale is not supported by the system. +// Use the standard impl if the current locale is supported, use the +// custom impl otherwise. function T_setlocale($category, $locale) { return _setlocale($category, $locale); } function T_bindtextdomain($domain, $path) { - if (_check_locale()) return bindtextdomain($domain, $path); - else return _bindtextdomain($domain, $path); + if (_check_locale_and_function()) return bindtextdomain($domain, $path); + else return _bindtextdomain($domain, $path); } function T_bind_textdomain_codeset($domain, $codeset) { // bind_textdomain_codeset is available only in PHP 4.2.0+ - if (_check_locale() and function_exists('bind_textdomain_codeset')) return bind_textdomain_codeset($domain, $codeset); - else return _bind_textdomain_codeset($domain, $codeset); + if (_check_locale_and_function('bind_textdomain_codeset')) + return bind_textdomain_codeset($domain, $codeset); + else return _bind_textdomain_codeset($domain, $codeset); } function T_textdomain($domain) { - if (_check_locale()) return textdomain($domain); - else return _textdomain($domain); + if (_check_locale_and_function()) return textdomain($domain); + else return _textdomain($domain); } function T_gettext($msgid) { - if (_check_locale()) return gettext($msgid); - else return _gettext($msgid); + if (_check_locale_and_function()) return gettext($msgid); + else return _gettext($msgid); } function T_($msgid) { - if (_check_locale()) return _($msgid); - return __($msgid); + if (_check_locale_and_function()) return _($msgid); + return __($msgid); } function T_ngettext($single, $plural, $number) { - if (_check_locale()) return ngettext($single, $plural, $number); - else return _ngettext($single, $plural, $number); + if (_check_locale_and_function()) + return ngettext($single, $plural, $number); + else return _ngettext($single, $plural, $number); } function T_dgettext($domain, $msgid) { - if (_check_locale()) return dgettext($domain, $msgid); - else return _dgettext($domain, $msgid); + if (_check_locale_and_function()) return dgettext($domain, $msgid); + else return _dgettext($domain, $msgid); } function T_dngettext($domain, $single, $plural, $number) { - if (_check_locale()) return dngettext($domain, $single, $plural, $number); - else return _dngettext($domain, $single, $plural, $number); + if (_check_locale_and_function()) + return dngettext($domain, $single, $plural, $number); + else return _dngettext($domain, $single, $plural, $number); } function T_dcgettext($domain, $msgid, $category) { - if (_check_locale()) return dcgettext($domain, $msgid, $category); - else return _dcgettext($domain, $msgid, $category); + if (_check_locale_and_function()) + return dcgettext($domain, $msgid, $category); + else return _dcgettext($domain, $msgid, $category); } function T_dcngettext($domain, $single, $plural, $number, $category) { - if (_check_locale()) return dcngettext($domain, $single, $plural, $number, $category); - else return _dcngettext($domain, $single, $plural, $number, $category); + if (_check_locale_and_function()) + return dcngettext($domain, $single, $plural, $number, $category); + else return _dcngettext($domain, $single, $plural, $number, $category); +} + +function T_pgettext($context, $msgid) { + if (_check_locale_and_function('pgettext')) + return pgettext($context, $msgid); + else + return _pgettext($context, $msgid); +} + +function T_dpgettext($domain, $context, $msgid) { + if (_check_locale_and_function('dpgettext')) + return dpgettext($domain, $context, $msgid); + else + return _dpgettext($domain, $context, $msgid); +} + +function T_dcpgettext($domain, $context, $msgid, $category) { + if (_check_locale_and_function('dcpgettext')) + return dcpgettext($domain, $context, $msgid, $category); + else + return _dcpgettext($domain, $context, $msgid, $category); +} + +function T_npgettext($context, $singular, $plural) { + if (_check_locale_and_function('npgettext')) + return npgettext($context, $single, $plural, $number); + else + return _npgettext($context, $single, $plural, $number); +} + +function T_dnpgettext($domain, $context, $singular, $plural) { + if (_check_locale_and_function('dnpgettext')) + return dnpgettext($domain, $context, $single, $plural, $number); + else + return _dnpgettext($domain, $context, $single, $plural, $number); +} + +function T_dcnpgettext($domain, $context, $singular, $plural, $category) { + if (_check_locale_and_function('dcnpgettext')) + return dcnpgettext($domain, $context, $single, + $plural, $number, $category); + else + return _dcnpgettext($domain, $context, $single, + $plural, $number, $category); } @@ -282,36 +479,56 @@ function T_dcngettext($domain, $single, $plural, $number, $category) { // Wrappers used as a drop in replacement for the standard gettext functions if (!function_exists('gettext')) { - function bindtextdomain($domain, $path) { - return _bindtextdomain($domain, $path); - } - function bind_textdomain_codeset($domain, $codeset) { - return _bind_textdomain_codeset($domain, $codeset); - } - function textdomain($domain) { - return _textdomain($domain); - } - function gettext($msgid) { - return _gettext($msgid); - } - function _($msgid) { - return __($msgid); - } - function ngettext($single, $plural, $number) { - return _ngettext($single, $plural, $number); - } - function dgettext($domain, $msgid) { - return _dgettext($domain, $msgid); - } - function dngettext($domain, $single, $plural, $number) { - return _dngettext($domain, $single, $plural, $number); - } - function dcgettext($domain, $msgid, $category) { - return _dcgettext($domain, $msgid, $category); - } - function dcngettext($domain, $single, $plural, $number, $category) { - return _dcngettext($domain, $single, $plural, $number, $category); - } -} - -?> \ No newline at end of file + function bindtextdomain($domain, $path) { + return _bindtextdomain($domain, $path); + } + function bind_textdomain_codeset($domain, $codeset) { + return _bind_textdomain_codeset($domain, $codeset); + } + function textdomain($domain) { + return _textdomain($domain); + } + function gettext($msgid) { + return _gettext($msgid); + } + function _($msgid) { + return __($msgid); + } + function ngettext($single, $plural, $number) { + return _ngettext($single, $plural, $number); + } + function dgettext($domain, $msgid) { + return _dgettext($domain, $msgid); + } + function dngettext($domain, $single, $plural, $number) { + return _dngettext($domain, $single, $plural, $number); + } + function dcgettext($domain, $msgid, $category) { + return _dcgettext($domain, $msgid, $category); + } + function dcngettext($domain, $single, $plural, $number, $category) { + return _dcngettext($domain, $single, $plural, $number, $category); + } + function pgettext($context, $msgid) { + return _pgettext($context, $msgid); + } + function npgettext($context, $single, $plural, $number) { + return _npgettext($context, $single, $plural, $number); + } + function dpgettext($domain, $context, $msgid) { + return _dpgettext($domain, $context, $msgid); + } + function dnpgettext($domain, $context, $single, $plural, $number) { + return _dnpgettext($domain, $context, $single, $plural, $number); + } + function dcpgettext($domain, $context, $msgid, $category) { + return _dcpgettext($domain, $context, $msgid, $category); + } + function dcnpgettext($domain, $context, $single, $plural, + $number, $category) { + return _dcnpgettext($domain, $context, $single, $plural, + $number, $category); + } +} + +?>