From 5dfddd7b181d2707f3e0d1c2f979ff2e09313a10 Mon Sep 17 00:00:00 2001 From: ryan Date: Tue, 17 Feb 2009 05:03:29 +0000 Subject: [PATCH] Switch to pomo lib. Support gettext contexts. Deprecate long form functions. Props nbachiyski. fixes #9112 #9111 git-svn-id: http://svn.automattic.com/wordpress/trunk@10584 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/l10n.php | 158 +++++++++++++------------- wp-includes/pomo/entry.php | 72 ++++++++++++ wp-includes/pomo/mo.php | 135 +++++++++++++++++++++++ wp-includes/pomo/po.php | 177 ++++++++++++++++++++++++++++++ wp-includes/pomo/streams.php | 122 ++++++++++++++++++++ wp-includes/pomo/translations.php | 173 +++++++++++++++++++++++++++++ wp-settings.php | 3 +- 7 files changed, 759 insertions(+), 81 deletions(-) create mode 100644 wp-includes/pomo/entry.php create mode 100644 wp-includes/pomo/mo.php create mode 100644 wp-includes/pomo/po.php create mode 100644 wp-includes/pomo/streams.php create mode 100644 wp-includes/pomo/translations.php diff --git a/wp-includes/l10n.php b/wp-includes/l10n.php index ed03835b66..3237655214 100644 --- a/wp-includes/l10n.php +++ b/wp-includes/l10n.php @@ -44,16 +44,11 @@ function get_locale() { } /** - * Retrieve the translated text. - * - * If the domain is set in the $l10n global, then the text is run through the - * domain's translate method. After it is passed to the 'gettext' filter hook, - * along with the untranslated text as the second parameter. - * - * If the domain is not set, the $text is just returned. + * Retrieves the translation of $text. If there is no translation, or + * the domain isn't loaded the original text is returned. * + * @see __() Don't use translate() directly, use __() * @since 2.2.0 - * @uses $l10n Gets list of domain translated string (gettext_reader) objects. * @uses apply_filters() Calls 'gettext' on domain translated text * with the untranslated text as second parameter. * @@ -61,13 +56,9 @@ function get_locale() { * @param string $domain Domain to retrieve the translated text. * @return string Translated text */ -function translate($text, $domain = 'default') { - global $l10n; - - if (isset($l10n[$domain])) - return apply_filters('gettext', $l10n[$domain]->translate($text), $text, $domain); - else - return apply_filters('gettext', $text, $text, $domain); +function translate( $text, $domain = 'default' ) { + $translations = &get_translations_for_domain( $domain ); + return apply_filters('gettext', $translations->translate($text), $text, $domain); } function before_last_bar( $string ) { @@ -79,13 +70,8 @@ function before_last_bar( $string ) { } /** - * Retrieve the translated text and strip context. - * - * If the domain is set in the $l10n global, then the text is run through the - * domain's translate method. After it is passed to the 'gettext' filter hook, - * along with the untranslated text as the second parameter. - * - * If the domain is not set, the $text is just returned. + * Translate $text like translate(), but assumes that the text + * contains a context after its last vertical bar. * * @since 2.5 * @uses translate() @@ -99,8 +85,14 @@ function translate_with_context( $text, $domain = 'default' ) { } +function translate_with_gettext_context( $text, $context, $domain = 'default' ) { + $translations = &get_translations_for_domain( $domain ); + return apply_filters( 'gettext_with_context', $translations->translate( $text, $context ), $text, $context, $domain); +} + /** - * Retrieves the translated string from the translate(). + * Retrieves the translation of $text. If there is no translation, or + * the domain isn't loaded the original text is returned. * * @see translate() An alias of translate() * @since 2.1.0 @@ -109,8 +101,8 @@ function translate_with_context( $text, $domain = 'default' ) { * @param string $domain Optional. Domain to retrieve the translated text * @return string Translated text */ -function __($text, $domain = 'default') { - return translate($text, $domain); +function __( $text, $domain = 'default' ) { + return translate( $text, $domain ); } /** @@ -122,12 +114,12 @@ function __($text, $domain = 'default') { * @param string $text Text to translate * @param string $domain Optional. Domain to retrieve the translated text */ -function _e($text, $domain = 'default') { - echo translate($text, $domain); +function _e( $text, $domain = 'default' ) { + echo translate( $text, $domain ); } /** - * Retrieve context translated string. + * Retrieve translated string with vertical bar context * * Quite a few times, there will be collisions with similar translatable text * found in more than two places but with different translated context. @@ -149,6 +141,16 @@ function _c($text, $domain = 'default') { return translate_with_context($text, $domain); } +function _x( $single, $context, $domain = 'default' ) { + return translate_with_gettext_context( $single, $context, $domain ); +} + +function __ngettext() { + _deprecated_function( __FUNCTION__, '2.8', '_n()' ); + $args = func_get_args(); + return call_user_func_array('_n', $args); +} + /** * Retrieve the plural or single form based on the amount. * @@ -171,26 +173,10 @@ function _c($text, $domain = 'default') { * @param string $domain Optional. The domain identifier the text should be retrieved in * @return string Either $single or $plural translated text */ -function __ngettext($single, $plural, $number, $domain = 'default') { - global $l10n; - - if (isset($l10n[$domain])) { - return apply_filters('ngettext', $l10n[$domain]->ngettext($single, $plural, $number), $single, $plural, $number); - } else { - if ($number != 1) - return $plural; - else - return $single; - } -} - -/** - * @see __ngettext() An alias of __ngettext - * - */ -function _n() { - $args = func_get_args(); - return call_user_func_array('__ngettext', $args); +function _n($single, $plural, $number, $domain = 'default') { + $translations = &get_translations_for_domain( $domain ); + $translation = $translations->translate_plural( $single, $plural, $number ); + return apply_filters( 'ngettext', $translation, $single, $plural, $number ); } /** @@ -199,7 +185,23 @@ function _n() { * */ function _nc( $single, $plural, $number, $domain = 'default' ) { - return before_last_bar( __ngettext( $single, $plural, $number, $domain ) ); + return before_last_bar( _n( $single, $plural, $number, $domain ) ); +} + +function _nx($single, $plural, $number, $context, $domain = 'default') { + $translations = &get_translations_for_domain( $domain ); + $translation = $translations->translate_plural( $single, $plural, $number, $context ); + return apply_filters( 'ngettext_with_context ', $translation, $single, $plural, $number, $context ); +} + +/** + * @deprecated Use _n_noop() + */ +function __ngettext_noop() { + _deprecated_function( __FUNCTION__, '2.8', '_n_noop()' ); + $args = func_get_args(); + return call_user_func_array('_n_noop', $args); + } /** @@ -210,31 +212,22 @@ function _nc( $single, $plural, $number, $domain = 'default' ) { * * Example: * $messages = array( - * 'post' => ngettext_noop('%s post', '%s posts'), - * 'page' => ngettext_noop('%s pages', '%s pages') + * 'post' => _n_noop('%s post', '%s posts'), + * 'page' => _n_noop('%s pages', '%s pages') * ); * ... * $message = $messages[$type]; - * $usable_text = sprintf(__ngettext($message[0], $message[1], $count), $count); + * $usable_text = sprintf(_n($message[0], $message[1], $count), $count); * * @since 2.5 * @param $single Single form to be i18ned * @param $plural Plural form to be i18ned - * @param $number Not used, here for compatibility with __ngettext, optional - * @param $domain Not used, here for compatibility with __ngettext, optional + * @param $number Not used, here for compatibility with _n, optional + * @param $domain Not used, here for compatibility with _n, optional * @return array array($single, $plural) */ -function __ngettext_noop($single, $plural, $number=1, $domain = 'default') { - return array($single, $plural); -} - -/** - * @see __ngettext_noop() An alias of __ngettext_noop() - * - */ -function _n_noop() { - $args = func_get_args(); - return call_user_func_array('__ngettext_noop', $args); +function _n_noop( $single, $plural, $number = 1, $domain = 'default' ) { + return array( $single, $plural ); } /** @@ -258,21 +251,15 @@ function _n_noop() { function load_textdomain($domain, $mofile) { global $l10n; - if ( is_readable($mofile)) - $input = new CachedFileReader($mofile); - else - return; + if ( !is_readable($mofile)) return; + + $mo = new MO(); + $mo->import_from_file( $mofile ); - $gettext = new gettext_reader($input); - - if (isset($l10n[$domain])) { - $l10n[$domain]->load_tables(); - $gettext->load_tables(); - $l10n[$domain]->cache_translations = array_merge($gettext->cache_translations, $l10n[$domain]->cache_translations); - } else - $l10n[$domain] = $gettext; - - unset($input, $gettext); + if (isset($l10n[$domain])) + $mo->merge_with( $l10n[$domain] ); + + $l10n[$domain] = &$mo; } /** @@ -340,4 +327,17 @@ function load_theme_textdomain($domain, $path = false) { load_textdomain($domain, $mofile); } +/** + * Returns the Translations instance for a domain. If there isn't one, + * returns empty Translations instance. + * + * @param string $domain + * @return object A Translation instance + */ +function get_translations_for_domain( $domain ) { + global $l10n; + $empty = &new Translations; + return isset($l10n[$domain])? $l10n[$domain] : $empty; +} + ?> diff --git a/wp-includes/pomo/entry.php b/wp-includes/pomo/entry.php new file mode 100644 index 0000000000..bb146a7d3e --- /dev/null +++ b/wp-includes/pomo/entry.php @@ -0,0 +1,72 @@ + $value) { + if (in_array($varname, $object_varnames)) { + $this->$varname = $value; + } + } + if (isset($args['plural'])) $this->is_plural = true; + if (!is_array($this->translations)) $this->translations = array(); + if (!is_array($this->references)) $this->references = array(); + if (!is_array($this->flags)) $this->flags = array(); + } + + /** + * Generates a unique key for this entry + * + * @return string|bool the key or false if the entry is empty + */ + function key() { + if (is_null($this->singular)) return false; + // prepend context and EOT, like in MO files + return is_null($this->context)? $this->singular : $this->context.chr(4).$this->singular; + } +} +?> diff --git a/wp-includes/pomo/mo.php b/wp-includes/pomo/mo.php new file mode 100644 index 0000000000..3ee38c2946 --- /dev/null +++ b/wp-includes/pomo/mo.php @@ -0,0 +1,135 @@ +_gettext_select_plural_form = $this->_make_gettext_select_plural_form($value); + } + + /** + * Fills up with the entries from MO file $filename + * + * @param string $filename MO file to load + */ + function import_from_file($filename) { + $reader = new POMO_CachedIntFileReader($filename); + if (isset($reader->error)) { + return false; + } + return $this->import_from_reader($reader); + } + + function get_byteorder($magic) { + + // The magic is 0x950412de + + // bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565 + $magic_little = (int) - 1794895138; + $magic_little_64 = (int) 2500072158; + // 0xde120495 + $magic_big = ((int) - 569244523) && 0xFFFFFFFF; + + if ($magic_little == $magic || $magic_little_64 == $magic) { + return 'little'; + } else if ($magic_big == $magic) { + return 'big'; + } else { + return false; + } + } + + function import_from_reader($reader) { + $reader->setEndian('little'); + $endian = MO::get_byteorder($reader->readint32()); + if (false === $endian) { + return false; + } + $reader->setEndian($endian); + + $revision = $reader->readint32(); + $total = $reader->readint32(); + // get addresses of array of lenghts and offsets for original string and translations + $originals_lo_addr = $reader->readint32(); + $translations_lo_addr = $reader->readint32(); + + $reader->seekto($originals_lo_addr); + $originals_lo = $reader->readint32array($total * 2); // each of + $reader->seekto($translations_lo_addr); + $translations_lo = $reader->readint32array($total * 2); + + $length = create_function('$i', 'return $i * 2 + 1;'); + $offset = create_function('$i', 'return $i * 2 + 2;'); + + for ($i = 0; $i < $total; ++$i) { + $reader->seekto($originals_lo[$offset($i)]); + $original = $reader->read($originals_lo[$length($i)]); + $reader->seekto($translations_lo[$offset($i)]); + $translation = $reader->read($translations_lo[$length($i)]); + if ('' == $original) { + $this->set_headers($this->make_headers($translation)); + } else { + $this->add_entry($this->make_entry($original, $translation)); + } + } + return true; + } + + function make_headers($translation) { + $headers = array(); + $lines = explode("\n", $translation); + foreach($lines as $line) { + $parts = explode(':', $line, 2); + if (!isset($parts[1])) continue; + $headers[trim($parts[0])] = trim($parts[1]); + } + return $headers; + } + + /** + * @static + */ + function &make_entry($original, $translation) { + $args = array(); + // look for context + $parts = explode(chr(4), $original); + if (isset($parts[1])) { + $original = $parts[1]; + $args['context'] = $parts[0]; + } + // look for plural original + $parts = explode(chr(0), $original); + $args['singular'] = $parts[0]; + if (isset($parts[1])) { + $args['plural'] = $parts[1]; + } + // plural translations are also separated by \0 + $args['translations'] = explode(chr(0), $translation); + $entry = & new Translation_Entry($args); + return $entry; + } + + function select_plural_form($count) { + return $this->gettext_select_plural_form($count); + } + + function get_plural_forms_count() { + return $this->_nplurals; + } + + +} +?> diff --git a/wp-includes/pomo/po.php b/wp-includes/pomo/po.php new file mode 100644 index 0000000000..b998671fb8 --- /dev/null +++ b/wp-includes/pomo/po.php @@ -0,0 +1,177 @@ +headers as $header => $value) { + $header_string.= "$header: $value\n"; + } + $poified = PO::poify($header_string); + return rtrim("msgid \"\"\nmsgstr $poified"); + } + + /** + * Exports all entries to PO format + * + * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end + */ + function export_entries() { + //TODO sorting + return implode("\n\n", array_map(array('PO', 'export_entry'), $this->entries)); + } + + /** + * Exports the whole PO file as a string + * + * @param bool $include_headers whether to include the headers in the export + * @return string ready for inclusion in PO file string for headers and all the enrtries + */ + function export($include_headers = true) { + $res = ''; + if ($include_headers) { + $res .= $this->export_headers(); + $res .= "\n\n"; + } + $res .= $this->export_entries(); + return $res; + } + + /** + * Same as {@link export}, but writes the result to a file + * + * @param string $filename where to write the PO string + * @param bool $include_headers whether to include tje headers in the export + * @return bool true on success, false on error + */ + function export_to_file($filename, $include_headers = true) { + $fh = fopen($filename, 'w'); + if (false === $fh) return false; + $export = $this->export($include_headers); + $res = fwrite($fh, $export); + if (false === $res) return false; + return fclose($fh); + } + + + /** + * Formats a string in PO-style + * + * @static + * @param string $string the string to format + * @return string the poified string + */ + function poify($string) { + $quote = '"'; + $slash = '\\'; + $newline = "\n"; + $tab = "\t"; + + $replaces = array( + "$slash" => "$slash$slash", + "$tab" => '\t', + "$quote" => "$slash$quote", + ); + $string = str_replace(array_keys($replaces), array_values($replaces), $string); + + $po = array(); + foreach (explode($newline, $string) as $line) { + $po[] = wordwrap($line, PO_MAX_LINE_LEN - 2, " $quote$newline$quote"); + } + $po = $quote.implode("${slash}n$quote$newline$quote", $po).$quote; + // add empty string on first line for readbility + if (false !== strpos($po, $newline)) { + $po = "$quote$quote$newline$po"; + } + // remove empty strings + $po = str_replace("$newline$quote$quote", '', $po); + return $po; + } + + /** + * Inserts $with in the beginning of every new line of $string and + * returns the modified string + * + * @static + * @param string $string prepend lines in this string + * @param string $with prepend lines with this string + */ + function prepend_each_line($string, $with) { + $php_with = var_export($with, true); + $lines = explode("\n", $string); + // do not prepend the string on the last empty line, artefact by explode + if ("\n" == substr($string, -1)) unset($lines[count($lines) - 1]); + $res = implode("\n", array_map(create_function('$x', "return $php_with.\$x;"), $lines)); + // give back the empty line, we ignored above + if ("\n" == substr($string, -1)) $res .= "\n"; + return $res; + } + + /** + * Prepare a text as a comment -- wraps the lines and prepends # + * and a special character to each line + * + * @access private + * @param string $text the comment text + * @param string $char character to denote a special PO comment, + * like :, default is a space + */ + function comment_block($text, $char=' ') { + $text = wordwrap($text, PO_MAX_LINE_LEN - 3); + return PO::prepend_each_line($text, "#$char "); + } + + /** + * Builds a string from the entry for inclusion in PO file + * + * @static + * @param object &$entry the entry to convert to po string + * @return string|bool PO-style formatted string for the entry or + * false if the entry is empty + */ + function export_entry(&$entry) { + if (is_null($entry->singular)) return false; + $po = array(); + if (!empty($entry->translator_comments)) $po[] = PO::comment_block($entry->translator_comments); + if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.'); + if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':'); + if (!empty($entry->flags)) $po[] = PO::comment_block(implode("\n", $entry->flags), ','); + if (!is_null($entry->context)) $po[] = 'msgctxt '.PO::poify($entry->context); + $po[] = 'msgid '.PO::poify($entry->singular); + if (!$entry->is_plural) { + $translation = empty($entry->translations)? '' : $entry->translations[0]; + $po[] = 'msgstr '.PO::poify($translation); + } else { + $po[] = 'msgid_plural '.PO::poify($entry->plural); + $translations = empty($entry->translations)? array('', '') : $entry->translations; + foreach($translations as $i => $translation) { + $po[] = "msgstr[$i] ".PO::poify($translation); + } + } + return implode("\n", $po); + } + +} +?> diff --git a/wp-includes/pomo/streams.php b/wp-includes/pomo/streams.php new file mode 100644 index 0000000000..3b0241af4c --- /dev/null +++ b/wp-includes/pomo/streams.php @@ -0,0 +1,122 @@ + + * + * @version $Id: streams.php 33 2009-02-16 09:33:39Z nbachiyski $ + * @package pomo + * @subpackage streams + */ + + +/** + * Provides file-like methods for manipulating a string instead + * of a physical file. + */ +class POMO_StringReader { + var $_pos; + var $_str; + + function POMO_StringReader($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 pos() { + return $this->_pos; + } + + function length() { + return strlen($this->_str); + } + +} + +/** + * Reads the contents of the file in the beginning. + */ +class POMO_CachedFileReader extends POMO_StringReader { + function POMO_CachedFileReader($filename) { + $this->_str = file_get_contents($filename); + if (false === $this->_str) + return false; + $this->pos = 0; + } +} + +/** + * Allows reading integers from a file. + */ +class POMO_CachedIntFileReader extends POMO_CachedFileReader { + + var $endian = 'little'; + + /** + * Opens a file and caches it. + * + * @param $filename string name of the file to be opened + * @param $endian string endianness of the words in the file, allowed + * values are 'little' or 'big'. Default value is 'little' + */ + function POMO_CachedIntFileReader($filename, $endian = 'little') { + $this->endian = $endian; + parent::POMO_CachedFileReader($filename); + } + + /** + * Sets the endianness of the file. + * + * @param $endian string 'big' or 'little' + */ + function setEndian($endian) { + $this->endian = $endian; + } + + /** + * Reads a 32bit Integer from the Stream + * + * @return mixed The integer, corresponding to the next 32 bits from + * the stream of false if there are not enough bytes or on error + */ + function readint32() { + $bytes = $this->read(4); + if (4 != strlen($bytes)) + return false; + $endian_letter = ('big' == $this->endian)? 'N' : 'V'; + $int = unpack($endian_letter, $bytes); + return array_shift($int); + } + + /** + * Reads an array of 32-bit Integers from the Stream + * + * @param integer count How many elements should be read + * @return mixed Array of integers or false if there isn't + * enough data or on error + */ + function readint32array($count) { + $bytes = $this->read(4 * $count); + if (4*$count != strlen($bytes)) + return false; + $endian_letter = ('big' == $this->endian)? 'N' : 'V'; + return unpack($endian_letter.$count, $bytes); + } +} + +?> diff --git a/wp-includes/pomo/translations.php b/wp-includes/pomo/translations.php new file mode 100644 index 0000000000..2932238d22 --- /dev/null +++ b/wp-includes/pomo/translations.php @@ -0,0 +1,173 @@ +key(); + if (false === $key) return false; + $this->entries[$key] = &$entry; + return true; + } + + /** + * Sets $header PO header to $value + * + * If the header already exists, it will be overwritten + * + * TODO: this should be out of this class, it is gettext specific + * + * @param string $header header name, without trailing : + * @param string $value header value, without trailing \n + */ + function set_header($header, $value) { + $this->headers[$header] = $value; + } + + function set_headers(&$headers) { + foreach($headers as $header => $value) { + $this->set_header($header, $value); + } + } + + function get_header($header) { + return isset($this->headers[$header])? $this->headers[$header] : false; + } + + function translate_entry(&$entry) { + $key = $entry->key(); + return isset($this->entries[$key])? $this->entries[$key] : false; + } + + function translate($singular, $context=null) { + $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context)); + $translated = $this->translate_entry($entry); + return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular; + } + + /** + * Given the number of items, returns the 0-based index of the plural form to use + * + * Here, in the base Translations class, the commong logic for English is implmented: + * 0 if there is one element, 1 otherwise + * + * This function should be overrided by the sub-classes. For example MO/PO can derive the logic + * from their headers. + * + * @param integer $count number of items + */ + function select_plural_form($count) { + return 1 == $count? 0 : 1; + } + + function get_plural_forms_count() { + return 2; + } + + function translate_plural($singular, $plural, $count, $context = null) { + $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context)); + $translated = $this->translate_entry($entry); + $index = $this->select_plural_form($count); + $total_plural_forms = $this->get_plural_forms_count(); + if ($translated && 0 <= $index && $index < $total_plural_forms && + is_array($translated->translations) && + count($translated->translations) == $total_plural_forms) + return $translated->translations[$index]; + else + return 1 == $count? $singular : $plural; + } + + /** + * The gettext implmentation of select_plural_form. + * + * It lives in this class, because there are more than one descendand, which will use it and + * they can't share it effectively. + * + */ + function gettext_select_plural_form($count) { + if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) { + $plural_header = $this->get_header('Plural-Forms'); + $this->_gettext_select_plural_form = $this->_make_gettext_select_plural_form($plural_header); + } + return call_user_func($this->_gettext_select_plural_form, $count); + } + + /** + * Makes a function, which will return the right translation index, according to the + * plural forms header + */ + function _make_gettext_select_plural_form($plural_header) { + $res = create_function('$count', 'return 1 == $count? 0 : 1;'); + if ($plural_header && (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $plural_header, $matches))) { + $nplurals = (int)$matches[1]; + $this->_nplurals = $nplurals; + $plural_expr = trim($this->_parenthesize_plural_exression($matches[2])); + $plural_expr = str_replace('n', '$n', $plural_expr); + $func_body = " + \$index = (int)($plural_expr); + return (\$index < $nplurals)? \$index : $nplurals - 1;"; + $res = create_function('$n', $func_body); + } + return $res; + } + + /** + * Adds parantheses to the inner parts of ternary operators in + * plural expressions, because PHP evaluates ternary oerators from left to right + * + * @param string $expression the expression without parentheses + * @return string the expression with parentheses added + */ + function _parenthesize_plural_exression($expression) { + $expression .= ';'; + $res = ''; + $depth = 0; + for ($i = 0; $i < strlen($expression); ++$i) { + $char = $expression[$i]; + switch ($char) { + case '?': + $res .= ' ? ('; + $depth++; + break; + case ':': + $res .= ') : ('; + break; + case ';': + $res .= str_repeat(')', $depth) . ';'; + $depth= 0; + break; + default: + $res .= $char; + } + } + return rtrim($res, ';'); + } + + /** + * Merge $other in the current object. + * + * @param Object &$other Another Translation object, whose translations will be merged in this one + * @return void + **/ + function merge_with(&$other) { + $this->entries = array_merge($this->entries, $other->entries); + } +} + +?> diff --git a/wp-settings.php b/wp-settings.php index 4a35fb8761..b0437be9b7 100644 --- a/wp-settings.php +++ b/wp-settings.php @@ -273,8 +273,7 @@ if ( function_exists('wp_cache_add_global_groups') ) { require (ABSPATH . WPINC . '/plugin.php'); require (ABSPATH . WPINC . '/default-filters.php'); -include_once(ABSPATH . WPINC . '/streams.php'); -include_once(ABSPATH . WPINC . '/gettext.php'); +include_once(ABSPATH . WPINC . '/pomo/mo.php'); require_once (ABSPATH . WPINC . '/l10n.php'); if ( !is_blog_installed() && (strpos($_SERVER['PHP_SELF'], 'install.php') === false && !defined('WP_INSTALLING')) ) {