diff --git a/composer.json b/composer.json index 41b2458a3a..63e372b7d7 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "require": { "php": ">=5.5.0", "phpmyadmin/sql-parser": "~3.3", + "phpmyadmin/motranslator": "~0 || ~1.0", "tecnickcom/tcpdf": "~6.2", "phpseclib/phpseclib": "~2.0", "google/recaptcha": "~1.1" diff --git a/libraries/Language.php b/libraries/Language.php index 866c82b4c0..8dd53ed6be 100644 --- a/libraries/Language.php +++ b/libraries/Language.php @@ -171,9 +171,8 @@ class Language $GLOBALS['lang'] = $this->code; // Set locale - _setlocale(LC_MESSAGES, $this->code); + _setlocale(0, $this->code); _bindtextdomain('phpmyadmin', LOCALE_PATH); - _bind_textdomain_codeset('phpmyadmin', 'UTF-8'); _textdomain('phpmyadmin'); /* Text direction for language */ diff --git a/libraries/common.inc.php b/libraries/common.inc.php index d0009e9f40..edfff57b88 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -71,16 +71,16 @@ define('PHPMYADMIN', true); */ require_once './libraries/vendor_config.php'; -/** - * Load gettext functions. - */ -require_once GETTEXT_INC; - /** * Activate autoloader */ require_once './vendor/autoload.php'; +/** + * Load gettext functions. + */ +MoTranslator\Loader::load_functions(); + /** * initialize the error handler */ @@ -132,12 +132,6 @@ $variables_whitelist = array ( 'PMA_PHP_SELF', 'variables_whitelist', 'key', - # following are set by gettext.inc - 'text_domains', - 'default_domain', - 'LC_CATEGORIES', - 'EMULATEGETTEXT', - 'CURRENTLOCALE', ); foreach (get_defined_vars() as $key => $value) { diff --git a/libraries/php-gettext/gettext.inc b/libraries/php-gettext/gettext.inc deleted file mode 100644 index 908180d239..0000000000 --- a/libraries/php-gettext/gettext.inc +++ /dev/null @@ -1,539 +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 - -/** - * 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); - if ($source_encoding === false) { - $source_encoding = 'utf-8'; - } - $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 (DIRECTORY_SEPARATOR == '\\') { - 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/libraries/php-gettext/gettext.php b/libraries/php-gettext/gettext.php deleted file mode 100644 index d712deac1c..0000000000 --- a/libraries/php-gettext/gettext.php +++ /dev/null @@ -1,431 +0,0 @@ -. - Copyright (c) 2005 Nico Kaiser - - 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 - -*/ - -/** - * Provides a simple gettext replacement that works independently from - * the system's gettext abilities. - * It can read MO files and use them for translating strings. - * The files are passed to gettext_reader as a Stream (see streams.php) - * - * This version has the ability to cache all strings and translations to - * speed up the string lookup. - * While the cache is enabled by default, it can be switched off with the - * second parameter in the constructor (e.g. whenusing very large MO files - * that you don't want to keep in memory) - */ -class gettext_reader { - //public: - var $error = 0; // public variable that holds error code (0 if no error) - - //private: - var $BYTEORDER = 0; // 0: low endian, 1: big endian - var $STREAM = NULL; - var $short_circuit = false; - var $enable_cache = false; - var $originals = NULL; // offset of original table - var $translations = NULL; // offset of translation table - var $pluralheader = NULL; // cache header field for plural forms - var $total = 0; // total string count - var $table_originals = NULL; // table for original strings (offsets) - var $table_translations = NULL; // table for translated strings (offsets) - var $cache_translations = NULL; // original -> translation mapping - - - /* Methods */ - - - /** - * Reads a 32bit Integer from the Stream - * - * @access private - * @return Integer from the Stream - */ - function readint() { - if ($this->BYTEORDER == 0) { - // low endian - $input=unpack('V', $this->STREAM->read(4)); - return array_shift($input); - } else { - // big endian - $input=unpack('N', $this->STREAM->read(4)); - return array_shift($input); - } - } - - function read($bytes) { - return $this->STREAM->read($bytes); - } - - /** - * Reads an array of Integers from the Stream - * - * @param int count How many elements should be read - * @return Array of Integers - */ - function readintarray($count) { - if ($this->BYTEORDER == 0) { - // low endian - return unpack('V'.$count, $this->STREAM->read(4 * $count)); - } else { - // big endian - return unpack('N'.$count, $this->STREAM->read(4 * $count)); - } - } - - /** - * Constructor - * - * @param object Reader the StreamReader object - * @param boolean enable_cache Enable or disable caching of strings (default on) - */ - public function __construct($Reader, $enable_cache = true) { - // If there isn't a StreamReader, turn on short circuit mode. - if (! $Reader || isset($Reader->error) ) { - $this->short_circuit = true; - return; - } - - // Caching can be turned off - $this->enable_cache = $enable_cache; - - $MAGIC1 = "\x95\x04\x12\xde"; - $MAGIC2 = "\xde\x12\x04\x95"; - - $this->STREAM = $Reader; - $magic = $this->read(4); - if ($magic == $MAGIC1) { - $this->BYTEORDER = 1; - } elseif ($magic == $MAGIC2) { - $this->BYTEORDER = 0; - } else { - $this->error = 1; // not MO file - return false; - } - - // FIXME: Do we care about revision? We should. - $revision = $this->readint(); - - $this->total = $this->readint(); - $this->originals = $this->readint(); - $this->translations = $this->readint(); - } - - /** - * 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() { - if (is_array($this->cache_translations) && - is_array($this->table_originals) && - is_array($this->table_translations)) - return; - - /* get original and translations tables */ - 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 (); - /* read all strings in the cache */ - for ($i = 0; $i < $this->total; $i++) { - $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); - $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); - $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); - $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); - $this->cache_translations[$original] = $translation; - } - } - } - - /** - * Returns a string from the "originals" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_original_string($num) { - $length = $this->table_originals[$num * 2 + 1]; - $offset = $this->table_originals[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Returns a string from the "translations" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_translation_string($num) { - $length = $this->table_translations[$num * 2 + 1]; - $offset = $this->table_translations[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Binary search for string - * - * @access private - * @param string string - * @param int start (internally used in recursive function) - * @param int end (internally used in recursive function) - * @return int string number (offset in originals table) - */ - function find_string($string, $start = -1, $end = -1) { - if (($start == -1) or ($end == -1)) { - // find_string is called with only one parameter, set start end end - $start = 0; - $end = $this->total; - } - if (abs($start - $end) <= 1) { - // We're done, now we either found the string, or it doesn't exist - $txt = $this->get_original_string($start); - if ($string == $txt) - return $start; - else - return -1; - } else if ($start > $end) { - // start > end -> turn around and start over - return $this->find_string($string, $end, $start); - } else { - // Divide table in two parts - $half = (int)(($start + $end) / 2); - $cmp = strcmp($string, $this->get_original_string($half)); - if ($cmp == 0) - // string is exactly in the middle => return it - return $half; - else if ($cmp < 0) - // The string is in the upper half - return $this->find_string($string, $start, $half); - else - // The string is in the lower half - return $this->find_string($string, $half, $end); - } - } - - /** - * Translates a string - * - * @access public - * @param string string to be translated - * @return string translated string (or original, if not found) - */ - function translate($string) { - if ($this->short_circuit) - return $string; - $this->load_tables(); - - if ($this->enable_cache) { - // Caching enabled, get translated string from cache - if (array_key_exists($string, $this->cache_translations)) - return $this->cache_translations[$string]; - else - return $string; - } else { - // Caching not enabled, try to find string - $num = $this->find_string($string); - if ($num == -1) - return $string; - else - return $this->get_translation_string($num); - } - } - - /** - * Sanitize plural form expression for use in PHP eval call. - * - * @access private - * @return string sanitized plural form expression - */ - function sanitize_plural_expression($expr) { - // Get rid of disallowed characters. - $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); - - // Add parenthesis for tertiary '?' operator. - $expr .= ';'; - $res = ''; - $p = 0; - for ($i = 0; $i < strlen($expr); $i++) { - $ch = $expr[$i]; - switch ($ch) { - case '?': - $res .= ' ? ('; - $p++; - break; - case ':': - $res .= ') : ('; - break; - case ';': - $res .= str_repeat( ')', $p) . ';'; - $p = 0; - break; - default: - $res .= $ch; - } - } - 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 - * - * @access private - * @return string plural form header - */ - function get_plural_forms() { - // lets assume message number 0 is header - // this is true, right? - $this->load_tables(); - - // cache header field for plural forms - if (! is_string($this->pluralheader)) { - if ($this->enable_cache) { - $header = $this->cache_translations[""]; - } else { - $header = $this->get_translation_string(0); - } - $expr = $this->extract_plural_forms_header_from_po_header($header); - $this->pluralheader = $this->sanitize_plural_expression($expr); - } - return $this->pluralheader; - } - - /** - * Detects which plural form to take - * - * @access private - * @param n count - * @return int array index of the right plural form - */ - function select_string($n) { - $string = $this->get_plural_forms(); - $string = str_replace('nplurals',"\$total",$string); - $string = str_replace("n",$n,$string); - $string = str_replace('plural',"\$plural",$string); - - $total = 0; - $plural = 0; - - eval("$string"); - if ($plural >= $total) $plural = $total - 1; - return $plural; - } - - /** - * Plural version of gettext - * - * @access public - * @param string single - * @param string plural - * @param string number - * @return translated plural form - */ - function ngettext($single, $plural, $number) { - if ($this->short_circuit) { - if ($number != 1) - return $plural; - else - return $single; - } - - // find out the appropriate form - $select = $this->select_string($number); - - // this should contains all strings separated by NULLs - $key = $single . chr(0) . $plural; - - - if ($this->enable_cache) { - if (! array_key_exists($key, $this->cache_translations)) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->cache_translations[$key]; - $list = explode(chr(0), $result); - return $list[$select]; - } - } else { - $num = $this->find_string($key); - if ($num == -1) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->get_translation_string($num); - $list = explode(chr(0), $result); - return $list[$select]; - } - } - } - - 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/libraries/php-gettext/streams.php b/libraries/php-gettext/streams.php deleted file mode 100644 index 19cd9b2c1d..0000000000 --- a/libraries/php-gettext/streams.php +++ /dev/null @@ -1,166 +0,0 @@ -. - - 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 - -*/ - - - // Simple class to wrap file streams, string streams, etc. - // seek is essential, and it should be byte stream -class StreamReader { - // should return a string [FIXME: perhaps return array of bytes?] - function read($bytes) { - return false; - } - - // should return new position - function seekto($position) { - return false; - } - - // returns current position - function currentpos() { - return false; - } - - // returns length of entire stream (limit for seekto()s) - function length() { - return false; - } -}; - -class StringReader { - var $_pos; - var $_str; - - public function __construct($str='') { - $this->_str = $str; - $this->_pos = 0; - } - - function read($bytes) { - $data = substr($this->_str, $this->_pos, $bytes); - $this->_pos += $bytes; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - - return $data; - } - - function seekto($pos) { - $this->_pos = $pos; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return strlen($this->_str); - } - -}; - - -class FileReader { - var $_pos; - var $_fd; - var $_length; - - public function __construct($filename) { - if (file_exists($filename)) { - - $this->_length=filesize($filename); - $this->_pos = 0; - $this->_fd = fopen($filename,'rb'); - if (!$this->_fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - } else { - $this->error = 2; // File doesn't exist - return false; - } - } - - function read($bytes) { - if ($bytes) { - fseek($this->_fd, $this->_pos); - - // PHP 5.1.1 does not read more than 8192 bytes in one fread() - // the discussions at PHP Bugs suggest it's the intended behaviour - $data = ''; - while ($bytes > 0) { - $chunk = fread($this->_fd, $bytes); - $data .= $chunk; - $bytes -= strlen($chunk); - } - $this->_pos = ftell($this->_fd); - - return $data; - } else return ''; - } - - function seekto($pos) { - fseek($this->_fd, $pos); - $this->_pos = ftell($this->_fd); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return $this->_length; - } - - function close() { - fclose($this->_fd); - } - -}; - -// Preloads entire file in memory first, then creates a StringReader -// over it (it assumes knowledge of StringReader internals) -class CachedFileReader extends StringReader { - public function __construct($filename) { - if (file_exists($filename)) { - - $length=filesize($filename); - $fd = fopen($filename,'rb'); - - if (!$fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - $this->_str = fread($fd, $length); - fclose($fd); - - } else { - $this->error = 2; // File doesn't exist - return false; - } - } -}; - - diff --git a/libraries/vendor_config.php b/libraries/vendor_config.php index f194bac8b2..cafdc9bbc1 100644 --- a/libraries/vendor_config.php +++ b/libraries/vendor_config.php @@ -68,12 +68,6 @@ define('CUSTOM_FOOTER_FILE', CONFIG_DIR . 'config.footer.inc.php'); */ define('VERSION_CHECK_DEFAULT', true); -/** - * Path to gettext.inc file. Useful when you want php-gettext somewhere else, - * eg. /usr/share/php/gettext/gettext.inc. - */ -define('GETTEXT_INC', './libraries/php-gettext/gettext.inc'); - /** * Path to files with compiled locales (*.mo) */ diff --git a/test/bootstrap-dist.php b/test/bootstrap-dist.php index 3469ba2f89..28d9e6b469 100644 --- a/test/bootstrap-dist.php +++ b/test/bootstrap-dist.php @@ -50,9 +50,9 @@ foreach ($test_defaults as $varname => $defvalue) { } require_once 'libraries/vendor_config.php'; -require_once GETTEXT_INC; require_once 'vendor/autoload.php'; require_once 'libraries/core.lib.php'; +MoTranslator\Loader::load_functions(); $CFG = new PMA\libraries\Config(); // Initialize PMA_VERSION variable define('PMA_VERSION', $CFG->get('PMA_VERSION')); diff --git a/test/libraries/php-gettext/Locales_test.php b/test/libraries/php-gettext/Locales_test.php deleted file mode 100644 index 1817f83fdb..0000000000 --- a/test/libraries/php-gettext/Locales_test.php +++ /dev/null @@ -1,86 +0,0 @@ -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/test/libraries/php-gettext/PMA_FileReader_test.php b/test/libraries/php-gettext/PMA_FileReader_test.php deleted file mode 100644 index c083d3ab9d..0000000000 --- a/test/libraries/php-gettext/PMA_FileReader_test.php +++ /dev/null @@ -1,143 +0,0 @@ -object = new FileReader('./test/test_data/test.file'); - - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - * - * @access protected - * @return void - */ - protected function tearDown() - { - unset($this->object); - } - - /** - * Test for read - * - * @return void - */ - public function testRead() - { - $this->assertEquals( - $this->object->read(4), - 'TEST' - ); - - $this->assertEquals( - $this->object->read(false), - '' - ); - } - - /** - * Test for seekto - * - * @return void - */ - public function testSeekto() - { - $this->assertEquals( - $this->object->seekto(1), - 1 - ); - } - - /** - * Test for currentpos - * - * @return void - */ - public function testCurrentpos() - { - $this->assertEquals( - $this->object->currentpos(), - 0 - ); - } - - /** - * Test for length - * - * @return void - */ - public function testLength() - { - $this->assertEquals( - $this->object->length(), - 10 - ); - } - - /** - * Test for close - * - * @return void - */ - public function testClose() - { - $this->assertEquals( - $this->object->close(), - null - ); - } - - /** - * Test for non existing file - * - * @return void - */ - public function testForNonExistingFile() - { - $file = new FileReader('./path/for/no/file.txt'); - // looking at the return value of a constructor is curious - // but the constructor returns a value - $this->assertFalse( - $file->__construct('./path/for/no/file.txt') - ); - } - - public function testForCachedFileReader() - { - $reader = new CachedFileReader('./test/test_data/test.file'); - $this->assertEquals( - $reader->__construct('./test/test_data/test.file'), - null - ); - $this->assertFalse( - $reader->__construct('./path/for/no/file.txt') - ); - - } -} diff --git a/test/libraries/php-gettext/PMA_StreamReader_test.php b/test/libraries/php-gettext/PMA_StreamReader_test.php deleted file mode 100644 index db47ea4789..0000000000 --- a/test/libraries/php-gettext/PMA_StreamReader_test.php +++ /dev/null @@ -1,86 +0,0 @@ -object = new StreamReader(); - - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - * - * @access protected - * @return void - */ - protected function tearDown() - { - unset($this->object); - } - - /** - * Test for read - * - * @return void - */ - public function testRead() - { - $this->assertFalse($this->object->read(4)); - } - - /** - * Test for seekto - * - * @return void - */ - public function testSeekto() - { - $this->assertFalse($this->object->seekto(1)); - } - - /** - * Test for currentpos - * - * @return void - */ - public function testCurrentpos() - { - $this->assertFalse($this->object->currentpos()); - } - - /** - * Test for length - * - * @return void - */ - public function testLength() - { - $this->assertFalse($this->object->length()); - } - -} diff --git a/test/libraries/php-gettext/PMA_StringReader_test.php b/test/libraries/php-gettext/PMA_StringReader_test.php deleted file mode 100644 index f3c173c957..0000000000 --- a/test/libraries/php-gettext/PMA_StringReader_test.php +++ /dev/null @@ -1,125 +0,0 @@ -object = new StringReader('sample string'); - - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - * - * @access protected - * @return void - */ - protected function tearDown() - { - unset($this->object); - } - - /** - * Test for read - * - * @param int $bytes Number of bytes to read - * @param string $output Expected output - * - * @return void - * - * @dataProvider providerForTestRead - */ - public function testRead($bytes, $output) - { - $this->assertEquals( - $this->object->read($bytes), - $output - ); - } - - /** - * Provider for testRead - * - * @return array - */ - public function providerForTestRead() - { - return array( - array( - 4, - 'samp' - ), - array( - 6, - 'sample' - ), - array( - 9, - 'sample st' - ) - ); - } - - /** - * Test for seekto - * - * @return void - */ - public function testSeekto() - { - $this->assertEquals( - $this->object->seekto(3), - 3 - ); - } - - /** - * Test for currentpos - * - * @return void - */ - public function testCurrentpos() - { - $this->assertEquals( - $this->object->currentpos(), - 0 - ); - } - - /** - * Test for length - * - * @return void - */ - public function testLength() - { - $this->assertEquals( - $this->object->length(), - 13 - ); - } -} diff --git a/test/libraries/php-gettext/PMA_gettext_test.php b/test/libraries/php-gettext/PMA_gettext_test.php deleted file mode 100644 index 71029658e4..0000000000 --- a/test/libraries/php-gettext/PMA_gettext_test.php +++ /dev/null @@ -1,223 +0,0 @@ -object = new gettext_reader($reader); - - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - * - * @access protected - * @return void - */ - protected function tearDown() - { - unset($this->object); - } - - /** - * Test for readint - * - * @return void - */ - public function testReadint() - { - $this->assertEquals( - $this->object->readint(), - 1848603506 - ); - } - - /** - * Test for readintarray - * - * @return void - */ - public function testReadintarray() - { - $this->assertEquals( - $this->object->readintarray(1), - array( - 1 => 1848603506 - ) - ); - } - - /** - * Test for get_original_string - * - * @return void - */ - public function testGet_original_string() - { - $this->assertEquals( - $this->object->get_original_string(1), - '' - ); - } - - /** - * Test for get_translation_string - * - * @return void - */ - public function testGet_translation_string() - { - $this->assertEquals( - $this->object->get_translation_string(1), - '' - ); - } - - /** - * Test for find_string - * - * @param string $string string - * @param int $start start (internally used in recursive function) - * @param int $end end (internally used in recursive function) - * @param string $output Expected output - * - * @return void - * - * @dataProvider providerForTestFind_string - */ - public function testFind_string($string, $start, $end, $output) - { - $this->assertEquals( - $this->object->find_string($string, $start, $end), - $output - ); - } - - /** - * Data provider for testFind_string - * - * @return array - */ - public function providerForTestFind_string() - { - return array( - array( - 'sample_string/string', - 2, - 5, - -1 - ), - array( - 'sample_string/string', - -1, - -1, - -1 - ) - ); - } - - /** - * Test for translate - * - * @return void - */ - public function testTranslate() - { - $this->assertEquals( - $this->object->translate('transferable_string'), - 'transferable_string' - ); - } - - /** - * Test for sanitize_plural_expression - * - * @param string $expr Expression to sanitize - * @param string $output Expected output - * - * @return void - * - * @dataProvider providerForTestSanitize_plural_expression - */ - public function testSanitize_plural_expression($expr, $output) - { - $this->assertEquals( - $this->object->sanitize_plural_expression($expr), - $output - ); - } - - /** - * Data provider for testSanitize_plural_expression - * - * @return array - */ - public function providerForTestSanitize_plural_expression() - { - return array( - array( - 'employeeId = 1', - 'employeeId=1;' - ), - array( - 'id = 1 ? true : false', - 'id=1 ? (true) : (false);' - ) - ); - } - - /** - * Test for extract_plural_forms_header_from_po_header - * - * @return void - */ - public function testExtract_plural_forms_header_from_po_header() - { - $this->assertEquals( - $this->object->extract_plural_forms_header_from_po_header( - 'id = 1 ? true : false' - ), - 'nplurals=2; plural=n == 1 ? 0 : 1;' - ); - } - - /** - * Test for pgettext - * - * @return void - */ - public function testPgettext() - { - $this->assertEquals( - $this->object->pgettext('context', 'msgId'), - 'msgId' - ); - } - -} diff --git a/test/libraries/php-gettext/Parsing_test.php b/test/libraries/php-gettext/Parsing_test.php deleted file mode 100644 index 1e67174fdd..0000000000 --- a/test/libraries/php-gettext/Parsing_test.php +++ /dev/null @@ -1,91 +0,0 @@ -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" - ) - ); - } - - /** - * Test for npgettext - * - * @param int $number Number - * @param string $expected Expected output - * - * @return void - * - * @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); - } - - /** - * Data provider for test_npgettext - * - * @return array - */ - 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"), - ); - } - -} -