diff --git a/include/php-gettext-1.0.9/AUTHORS b/include/php-gettext-1.0.11/AUTHORS similarity index 100% rename from include/php-gettext-1.0.9/AUTHORS rename to include/php-gettext-1.0.11/AUTHORS diff --git a/include/php-gettext-1.0.9/COPYING b/include/php-gettext-1.0.11/COPYING similarity index 100% rename from include/php-gettext-1.0.9/COPYING rename to include/php-gettext-1.0.11/COPYING diff --git a/include/php-gettext-1.0.9/Makefile b/include/php-gettext-1.0.11/Makefile similarity index 84% rename from include/php-gettext-1.0.9/Makefile rename to include/php-gettext-1.0.11/Makefile index f0b5bf99..f389de51 100644 --- a/include/php-gettext-1.0.9/Makefile +++ b/include/php-gettext-1.0.11/Makefile @@ -1,5 +1,5 @@ PACKAGE = php-gettext-$(VERSION) -VERSION = 1.0.9 +VERSION = 1.0.11 DIST_FILES = \ gettext.php \ @@ -16,9 +16,14 @@ DIST_FILES = \ examples/locale/sr_CS/LC_MESSAGES/messages.mo \ examples/locale/de_CH/LC_MESSAGES/messages.po \ examples/locale/de_CH/LC_MESSAGES/messages.mo \ - examples/update + examples/update \ + tests/LocalesTest.php \ + tests/ParsingTest.php -dist: +check: + phpunit --verbose tests + +dist: check if [ -d $(PACKAGE) ]; then \ rm -rf $(PACKAGE); \ fi; \ diff --git a/include/php-gettext-1.0.9/README b/include/php-gettext-1.0.11/README similarity index 100% rename from include/php-gettext-1.0.9/README rename to include/php-gettext-1.0.11/README diff --git a/include/php-gettext-1.0.9/examples/index.php b/include/php-gettext-1.0.11/examples/index.php similarity index 100% rename from include/php-gettext-1.0.9/examples/index.php rename to include/php-gettext-1.0.11/examples/index.php diff --git a/include/php-gettext-1.0.9/examples/locale/de_CH/LC_MESSAGES/messages.mo b/include/php-gettext-1.0.11/examples/locale/de_CH/LC_MESSAGES/messages.mo similarity index 100% rename from include/php-gettext-1.0.9/examples/locale/de_CH/LC_MESSAGES/messages.mo rename to include/php-gettext-1.0.11/examples/locale/de_CH/LC_MESSAGES/messages.mo diff --git a/include/php-gettext-1.0.9/examples/locale/de_CH/LC_MESSAGES/messages.po b/include/php-gettext-1.0.11/examples/locale/de_CH/LC_MESSAGES/messages.po similarity index 100% rename from include/php-gettext-1.0.9/examples/locale/de_CH/LC_MESSAGES/messages.po rename to include/php-gettext-1.0.11/examples/locale/de_CH/LC_MESSAGES/messages.po diff --git a/include/php-gettext-1.0.9/examples/locale/sr_CS/LC_MESSAGES/messages.mo b/include/php-gettext-1.0.11/examples/locale/sr_CS/LC_MESSAGES/messages.mo similarity index 100% rename from include/php-gettext-1.0.9/examples/locale/sr_CS/LC_MESSAGES/messages.mo rename to include/php-gettext-1.0.11/examples/locale/sr_CS/LC_MESSAGES/messages.mo diff --git a/include/php-gettext-1.0.9/examples/locale/sr_CS/LC_MESSAGES/messages.po b/include/php-gettext-1.0.11/examples/locale/sr_CS/LC_MESSAGES/messages.po similarity index 100% rename from include/php-gettext-1.0.9/examples/locale/sr_CS/LC_MESSAGES/messages.po rename to include/php-gettext-1.0.11/examples/locale/sr_CS/LC_MESSAGES/messages.po diff --git a/include/php-gettext-1.0.9/examples/pigs_dropin.php b/include/php-gettext-1.0.11/examples/pigs_dropin.php similarity index 98% rename from include/php-gettext-1.0.9/examples/pigs_dropin.php rename to include/php-gettext-1.0.11/examples/pigs_dropin.php index 320a2a58..94fd8507 100644 --- a/include/php-gettext-1.0.9/examples/pigs_dropin.php +++ b/include/php-gettext-1.0.11/examples/pigs_dropin.php @@ -21,7 +21,7 @@ */ -error_reporting(E_STRICT); +error_reporting(E_ALL | E_STRICT); // define constants define('PROJECT_DIR', realpath('./')); diff --git a/include/php-gettext-1.0.9/examples/pigs_fallback.php b/include/php-gettext-1.0.11/examples/pigs_fallback.php similarity index 98% rename from include/php-gettext-1.0.9/examples/pigs_fallback.php rename to include/php-gettext-1.0.11/examples/pigs_fallback.php index 5d154b6c..353190da 100644 --- a/include/php-gettext-1.0.9/examples/pigs_fallback.php +++ b/include/php-gettext-1.0.11/examples/pigs_fallback.php @@ -21,7 +21,7 @@ */ -error_reporting(E_STRICT); +error_reporting(E_ALL | E_STRICT); // define constants define('PROJECT_DIR', realpath('./')); diff --git a/include/php-gettext-1.0.9/examples/update b/include/php-gettext-1.0.11/examples/update similarity index 100% rename from include/php-gettext-1.0.9/examples/update rename to include/php-gettext-1.0.11/examples/update diff --git a/include/php-gettext-1.0.11/gettext.inc b/include/php-gettext-1.0.11/gettext.inc new file mode 100644 index 00000000..00b96669 --- /dev/null +++ b/include/php-gettext-1.0.11/gettext.inc @@ -0,0 +1,536 @@ + + 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 + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* +LC_CTYPE 0 +LC_NUMERIC 1 +LC_TIME 2 +LC_COLLATE 3 +LC_MONETARY 4 +LC_MESSAGES 5 +LC_ALL 6 +*/ + +// 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 + +global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE; +$text_domains = array(); +$default_domain = 'messages'; +$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL'); +$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); + $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; +} + +/** + * Returns whether we are using our emulated gettext API or PHP built-in one. + */ +function locale_emulation() { + global $EMULATEGETTEXT; + return $EMULATEGETTEXT; +} + +/** + * Checks if the current locale is supported on this system. + */ +function _check_locale_and_function($function=false) { + global $EMULATEGETTEXT; + if ($function and !function_exists($function)) + return false; + return !$EMULATEGETTEXT; +} + +/** + * 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'); +} + +/** + * 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; + } +} + + +// 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 != '') + return $CURRENTLOCALE; + 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 { + 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 { + // 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; + if (array_key_exists($default_domain, $text_domains)) { + unset($text_domains[$default_domain]->l10n); + } + return $CURRENTLOCALE; + } +} + +/** + * Sets the path for a domain. + */ +function _bindtextdomain($domain, $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; +} + +/** + * Sets the default domain. + */ +function _textdomain($domain) { + global $default_domain; + $default_domain = $domain; +} + +/** + * Lookup a message in the current domain. + */ +function _gettext($msgid) { + $l10n = _get_reader(); + return _encode($l10n->translate($msgid)); +} + +/** + * Alias for gettext. + */ +function __($msgid) { + return _gettext($msgid); +} + +/** + * Plural version of gettext. + */ +function _ngettext($singular, $plural, $number) { + $l10n = _get_reader(); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Override the current domain. + */ +function _dgettext($domain, $msgid) { + $l10n = _get_reader($domain); + return _encode($l10n->translate($msgid)); +} + +/** + * Plural version of dgettext. + */ +function _dngettext($domain, $singular, $plural, $number) { + $l10n = _get_reader($domain); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Overrides the domain and category for a single lookup. + */ +function _dcgettext($domain, $msgid, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->translate($msgid)); +} +/** + * Plural version of dcgettext. + */ +function _dcngettext($domain, $singular, $plural, $number, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->ngettext($singular, $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)); +} + +/** + * 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_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('bind_textdomain_codeset')) + return bind_textdomain_codeset($domain, $codeset); + else return _bind_textdomain_codeset($domain, $codeset); +} +function T_textdomain($domain) { + if (_check_locale_and_function()) return textdomain($domain); + else return _textdomain($domain); +} +function T_gettext($msgid) { + if (_check_locale_and_function()) return gettext($msgid); + else return _gettext($msgid); +} +function T_($msgid) { + if (_check_locale_and_function()) return _($msgid); + return __($msgid); +} +function T_ngettext($singular, $plural, $number) { + if (_check_locale_and_function()) + return ngettext($singular, $plural, $number); + else return _ngettext($singular, $plural, $number); +} +function T_dgettext($domain, $msgid) { + if (_check_locale_and_function()) return dgettext($domain, $msgid); + else return _dgettext($domain, $msgid); +} +function T_dngettext($domain, $singular, $plural, $number) { + if (_check_locale_and_function()) + return dngettext($domain, $singular, $plural, $number); + else return _dngettext($domain, $singular, $plural, $number); +} +function T_dcgettext($domain, $msgid, $category) { + if (_check_locale_and_function()) + return dcgettext($domain, $msgid, $category); + else return _dcgettext($domain, $msgid, $category); +} +function T_dcngettext($domain, $singular, $plural, $number, $category) { + if (_check_locale_and_function()) + return dcngettext($domain, $singular, $plural, $number, $category); + else return _dcngettext($domain, $singular, $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, $number) { + if (_check_locale_and_function('npgettext')) + return npgettext($context, $singular, $plural, $number); + else + return _npgettext($context, $singular, $plural, $number); +} + +function T_dnpgettext($domain, $context, $singular, $plural, $number) { + if (_check_locale_and_function('dnpgettext')) + return dnpgettext($domain, $context, $singular, $plural, $number); + else + return _dnpgettext($domain, $context, $singular, $plural, $number); +} + +function T_dcnpgettext($domain, $context, $singular, $plural, + $number, $category) { + if (_check_locale_and_function('dcnpgettext')) + return dcnpgettext($domain, $context, $singular, + $plural, $number, $category); + else + return _dcnpgettext($domain, $context, $singular, + $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($singular, $plural, $number) { + return _ngettext($singular, $plural, $number); + } + function dgettext($domain, $msgid) { + return _dgettext($domain, $msgid); + } + function dngettext($domain, $singular, $plural, $number) { + return _dngettext($domain, $singular, $plural, $number); + } + function dcgettext($domain, $msgid, $category) { + return _dcgettext($domain, $msgid, $category); + } + function dcngettext($domain, $singular, $plural, $number, $category) { + return _dcngettext($domain, $singular, $plural, $number, $category); + } + function pgettext($context, $msgid) { + return _pgettext($context, $msgid); + } + function npgettext($context, $singular, $plural, $number) { + return _npgettext($context, $singular, $plural, $number); + } + function dpgettext($domain, $context, $msgid) { + return _dpgettext($domain, $context, $msgid); + } + function dnpgettext($domain, $context, $singular, $plural, $number) { + return _dnpgettext($domain, $context, $singular, $plural, $number); + } + function dcpgettext($domain, $context, $msgid, $category) { + return _dcpgettext($domain, $context, $msgid, $category); + } + function dcnpgettext($domain, $context, $singular, $plural, + $number, $category) { + return _dcnpgettext($domain, $context, $singular, $plural, + $number, $category); + } +} + +?> diff --git a/include/php-gettext-1.0.9/gettext.php b/include/php-gettext-1.0.11/gettext.php similarity index 89% rename from include/php-gettext-1.0.9/gettext.php rename to include/php-gettext-1.0.11/gettext.php index 8865d781..5064047c 100755 --- a/include/php-gettext-1.0.9/gettext.php +++ b/include/php-gettext-1.0.11/gettext.php @@ -134,7 +134,7 @@ class gettext_reader { * Loads the translation tables from the MO file into the cache * If caching is enabled, also loads all strings into a cache * to speed up translation lookups - * + * * @access private */ function load_tables() { @@ -144,10 +144,14 @@ class gettext_reader { return; /* get original and translations tables */ - $this->STREAM->seekto($this->originals); - $this->table_originals = $this->readintarray($this->total * 2); - $this->STREAM->seekto($this->translations); - $this->table_translations = $this->readintarray($this->total * 2); + if (!is_array($this->table_originals)) { + $this->STREAM->seekto($this->originals); + $this->table_originals = $this->readintarray($this->total * 2); + } + if (!is_array($this->table_translations)) { + $this->STREAM->seekto($this->translations); + $this->table_translations = $this->readintarray($this->total * 2); + } if ($this->enable_cache) { $this->cache_translations = array (); @@ -300,6 +304,20 @@ class gettext_reader { return $res; } + /** + * Parse full PO header and extract only plural forms line. + * + * @access private + * @return string verbatim plural form header field + */ + function extract_plural_forms_header_from_po_header($header) { + if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) + $expr = $regs[2]; + else + $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; + return $expr; + } + /** * Get possible plural forms from MO header * @@ -318,11 +336,7 @@ class gettext_reader { } else { $header = $this->get_translation_string(0); } - if (eregi("plural-forms: ([^\n]*)\n", $header, $regs)) - $expr = $regs[1]; - else - $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; - + $expr = $this->extract_plural_forms_header_from_po_header($header); $this->pluralheader = $this->sanitize_plural_expression($expr); } return $this->pluralheader; @@ -370,7 +384,7 @@ class gettext_reader { $select = $this->select_string($number); // this should contains all strings separated by NULLs - $key = $single.chr(0).$plural; + $key = $single . chr(0) . $plural; if ($this->enable_cache) { @@ -393,6 +407,26 @@ class gettext_reader { } } + function pgettext($context, $msgid) { + $key = $context . chr(4) . $msgid; + $ret = $this->translate($key); + if (strpos($ret, "\004") !== FALSE) { + return $msgid; + } else { + return $ret; + } + } + + function npgettext($context, $singular, $plural, $number) { + $key = $context . chr(4) . $singular; + $ret = $this->ngettext($key, $plural, $number); + if (strpos($ret, "\004") !== FALSE) { + return $singular; + } else { + return $ret; + } + + } } ?> diff --git a/include/php-gettext-1.0.9/streams.php b/include/php-gettext-1.0.11/streams.php old mode 100755 new mode 100644 similarity index 100% rename from include/php-gettext-1.0.9/streams.php rename to include/php-gettext-1.0.11/streams.php diff --git a/include/php-gettext-1.0.11/tests/LocalesTest.php b/include/php-gettext-1.0.11/tests/LocalesTest.php new file mode 100644 index 00000000..fab21f86 --- /dev/null +++ b/include/php-gettext-1.0.11/tests/LocalesTest.php @@ -0,0 +1,75 @@ +assertEquals('sr_RS', _setlocale(LC_MESSAGES, 0)); + } + + public function test_setlocale_system() + { + putenv("LC_ALL="); + // For an existing locale, it never needs emulation. + putenv("LANG=C"); + _setlocale(LC_MESSAGES, ""); + $this->assertEquals(0, locale_emulation()); + } + + public function test_setlocale_emulation() + { + putenv("LC_ALL="); + // If we set it to a non-existent locale, it still works, but uses + // emulation. + _setlocale(LC_MESSAGES, "xxx_XXX"); + $this->assertEquals('xxx_XXX', _setlocale(LC_MESSAGES, 0)); + $this->assertEquals(1, locale_emulation()); + } + + public function test_get_list_of_locales() + { + // For a locale containing country code, we prefer + // full locale name, but if that's not found, fall back + // to the language only locale name. + $this->assertEquals(array("sr_RS", "sr"), + get_list_of_locales("sr_RS")); + + // If language code is used, it's the only thing returned. + $this->assertEquals(array("sr"), + get_list_of_locales("sr")); + + // There is support for language and charset only. + $this->assertEquals(array("sr.UTF-8", "sr"), + get_list_of_locales("sr.UTF-8")); + + // It can also split out character set from the full locale name. + $this->assertEquals(array("sr_RS.UTF-8", "sr_RS", "sr"), + get_list_of_locales("sr_RS.UTF-8")); + + // There is support for @modifier in locale names as well. + $this->assertEquals(array("sr_RS.UTF-8@latin", "sr_RS@latin", "sr@latin", + "sr_RS.UTF-8", "sr_RS", "sr"), + get_list_of_locales("sr_RS.UTF-8@latin")); + + // We can pass in only language and modifier. + $this->assertEquals(array("sr@latin", "sr"), + get_list_of_locales("sr@latin")); + + + // If locale name is not following the regular POSIX pattern, + // it's used verbatim. + $this->assertEquals(array("something"), + get_list_of_locales("something")); + + // Passing in an empty string returns an empty array. + $this->assertEquals(array(), + get_list_of_locales("")); + } +} + +?> diff --git a/include/php-gettext-1.0.11/tests/ParsingTest.php b/include/php-gettext-1.0.11/tests/ParsingTest.php new file mode 100644 index 00000000..ff561989 --- /dev/null +++ b/include/php-gettext-1.0.11/tests/ParsingTest.php @@ -0,0 +1,60 @@ +assertEquals( + 'nplurals=2; plural=n == 1 ? 0 : 1;', + $parser->extract_plural_forms_header_from_po_header("")); + + // Extracting it from the middle of the header works. + $this->assertEquals( + 'nplurals=1; plural=0;', + $parser->extract_plural_forms_header_from_po_header( + "Content-type: text/html; charset=UTF-8\n" + ."Plural-Forms: nplurals=1; plural=0;\n" + ."Last-Translator: nobody\n" + )); + + // It's also case-insensitive. + $this->assertEquals( + 'nplurals=1; plural=0;', + $parser->extract_plural_forms_header_from_po_header( + "PLURAL-forms: nplurals=1; plural=0;\n" + )); + + // It falls back to default if it's not on a separate line. + $this->assertEquals( + 'nplurals=2; plural=n == 1 ? 0 : 1;', + $parser->extract_plural_forms_header_from_po_header( + "Content-type: text/html; charset=UTF-8" // note the missing \n here + ."Plural-Forms: nplurals=1; plural=0;\n" + ."Last-Translator: nobody\n" + )); + } + + /** + * @dataProvider data_provider_test_npgettext + */ + public function test_npgettext($number, $expected) { + $parser = new gettext_reader(NULL); + $result = $parser->npgettext("context", + "%d pig went to the market\n", + "%d pigs went to the market\n", + $number); + $this->assertSame($expected, $result); + } + public static function data_provider_test_npgettext() { + return array( + array(1, "%d pig went to the market\n"), + array(2, "%d pigs went to the market\n"), + ); + } + +} +?> diff --git a/include/php-gettext-1.0.9/gettext.inc b/include/php-gettext-1.0.9/gettext.inc deleted file mode 100644 index 5d7390e2..00000000 --- a/include/php-gettext-1.0.9/gettext.inc +++ /dev/null @@ -1,374 +0,0 @@ - - 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 - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ -/* -LC_CTYPE 0 -LC_NUMERIC 1 -LC_TIME 2 -LC_COLLATE 3 -LC_MONETARY 4 -LC_MESSAGES 5 -LC_ALL 6 -*/ - - -// 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 - -global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE; -$text_domains = array(); -$default_domain = 'messages'; -$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL'); -$EMULATEGETTEXT = 0; -$CURRENTLOCALE = ''; - -/* Class to hold a single domain included in $text_domains. */ -class domain { - var $l10n; - var $path; - var $codeset; -} - -// Utility functions - -/** - * 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); - $bound_path = isset($text_domains[$domain]->path) ? - $text_domains[$domain]->path : './'; - $subpath = $LC_CATEGORIES[$category] ."/$domain.mo"; - /* 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(); - if (preg_match("/([a-z]{2,3})" // language code - ."(_([A-Z]{2}))?" // country code - ."(\.([-A-Za-z0-9_]))?" // charset - ."(@([-A-Za-z0-9_]+))?/", // @ modifier - $locale, $matches)) { - @list(,$lang,,$country,,$charset,,$modifier) = $matches; - if ($modifier) { - $locale_names = array("${lang}_$country.$charset@$modifier", - "${lang}_$country@$modifier", - "$lang@$modifier"); - } - array_push($locale_names, - "${lang}_$country.$charset", "${lang}_$country", "$lang"); - } - array_push($locale_names, $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; -} - -/** - * Returns whether we are using our emulated gettext API or PHP built-in one. - */ -function locale_emulation() { - global $EMULATEGETTEXT; - return $EMULATEGETTEXT; -} - -/** - * Checks if the current locale is supported on this system. - */ -function _check_locale() { - global $EMULATEGETTEXT; - return !$EMULATEGETTEXT; -} - -/** - * 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'); -} - -/** - * 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; - } -} - - - - -// Custom implementation of the standard gettext related functions - -/** - * 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 != '') - return $CURRENTLOCALE; - 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; - $CURRENTLOCALE = $ret; - } else { - if ($locale == '') // emulate variable support - $CURRENTLOCALE = getenv('LANG'); - else - $CURRENTLOCALE = $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; - } -} - -/** - * Sets the path for a domain. - */ -function _bindtextdomain($domain, $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; -} - -/** - * Sets the default domain. - */ -function _textdomain($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)); -} -/** - * Alias for gettext. - */ -function __($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)); -} - -/** - * Override the current domain. - */ -function _dgettext($domain, $msgid) { - $l10n = _get_reader($domain); - //return $l10n->translate($msgid); - 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)); -} - -/** - * 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)); -} -/** - * 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)); -} - - - -// 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); -} -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); -} -function T_textdomain($domain) { - if (_check_locale()) return textdomain($domain); - else return _textdomain($domain); -} -function T_gettext($msgid) { - if (_check_locale()) return gettext($msgid); - else return _gettext($msgid); -} -function T_($msgid) { - if (_check_locale()) return _($msgid); - return __($msgid); -} -function T_ngettext($single, $plural, $number) { - if (_check_locale()) 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); -} -function T_dngettext($domain, $single, $plural, $number) { - if (_check_locale()) 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); -} -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); -} - - - -// 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); - } -} - -?> diff --git a/lang.inc.php b/lang.inc.php index c504a3e1..da95fab8 100644 --- a/lang.inc.php +++ b/lang.inc.php @@ -32,7 +32,7 @@ /** * The phpgettext package */ -require_once(dirname(__FILE__).'/include/php-gettext-1.0.9/gettext.inc'); +require_once(dirname(__FILE__).'/include/php-gettext-1.0.11/gettext.inc'); /** * Translate the given elements of the array