Make WordPress Core

Changeset 11626


Ignore:
Timestamp:
06/23/2009 04:32:52 PM (17 years ago)
Author:
ryan
Message:

Merge latest pomo. Works around mbstring.func_overload. Props nbachiyski. fixes #10236 for trunk

Location:
trunk/wp-includes/pomo
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/pomo/entry.php

    r10584 r11626  
    33 * Contains Translation_Entry class
    44 *
    5  * @version $Id: entry.php 13 2008-04-21 12:03:37Z nbachiyski $
     5 * @version $Id: entry.php 115 2009-05-11 18:56:15Z nbachiyski $
    66 * @package pomo
    77 * @subpackage entry
     
    4949                $object_varnames = array_keys(get_object_vars($this));
    5050                foreach ($args as $varname => $value) {
    51                         if (in_array($varname, $object_varnames)) {
    52                                 $this->$varname = $value;
    53                         }
     51                        $this->$varname = $value;
    5452                }
    5553                if (isset($args['plural'])) $this->is_plural = true;
  • trunk/wp-includes/pomo/mo.php

    r10810 r11626  
    33 * Class for working with MO files
    44 *
    5  * @version $Id: mo.php 33 2009-02-16 09:33:39Z nbachiyski $
     5 * @version $Id: mo.php 106 2009-04-23 19:48:22Z nbachiyski $
    66 * @package pomo
    77 * @subpackage mo
     
    1111require_once dirname(__FILE__) . '/streams.php';
    1212
    13 class MO extends Translations {
     13class MO extends Gettext_Translations {
    1414
    1515        var $_nplurals = 2;
    16 
    17         function set_header($header, $value) {
    18                 parent::set_header($header, $value);
    19                 if ('Plural-Forms' == $header)
    20                         $this->_gettext_select_plural_form = $this->_make_gettext_select_plural_form($value);
    21         }
    2216
    2317        /**
     
    3327                return $this->import_from_reader($reader);
    3428        }
     29       
     30        function export_to_file($filename) {
     31                $fh = fopen($filename, 'wb');
     32                if ( !$fh ) return false;
     33                $entries = array_filter($this->entries, create_function('$e', 'return !empty($e->translations);'));
     34                ksort($entries);
     35                $magic = 0x950412de;
     36                $revision = 0;
     37                $total = count($entries) + 1; // all the headers are one entry
     38                $originals_lenghts_addr = 28;
     39                $translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
     40                $size_of_hash = 0;
     41                $hash_addr = $translations_lenghts_addr + 8 * $total;
     42                $current_addr = $hash_addr;
     43                fwrite($fh, pack('V*', $magic, $revision, $total, $originals_lenghts_addr,
     44                        $translations_lenghts_addr, $size_of_hash, $hash_addr));
     45                fseek($fh, $originals_lenghts_addr);
     46               
     47                // headers' msgid is an empty string
     48                fwrite($fh, pack('VV', 0, $current_addr));
     49                $current_addr++;
     50                $originals_table = chr(0);
     51
     52                foreach($entries as $entry) {
     53                        $originals_table .= $this->export_original($entry) . chr(0);
     54                        $length = strlen($this->export_original($entry));
     55                        fwrite($fh, pack('VV', $length, $current_addr));
     56                        $current_addr += $length + 1; // account for the NULL byte after
     57                }
     58               
     59                $exported_headers = $this->export_headers();
     60                fwrite($fh, pack('VV', strlen($exported_headers), $current_addr));
     61                $current_addr += strlen($exported_headers) + 1;
     62                $translations_table = $exported_headers . chr(0);
     63               
     64                foreach($entries as $entry) {
     65                        $translations_table .= $this->export_translations($entry) . chr(0);
     66                        $length = strlen($this->export_translations($entry));
     67                        fwrite($fh, pack('VV', $length, $current_addr));
     68                        $current_addr += $length + 1;
     69                }
     70               
     71                fwrite($fh, $originals_table);
     72                fwrite($fh, $translations_table);
     73                fclose($fh);
     74        }
     75       
     76        function export_original($entry) {
     77                //TODO: warnings for control characters
     78                $exported = $entry->singular;
     79                if ($entry->is_plural) $exported .= chr(0).$entry->plural;
     80                if (!is_null($entry->context)) $exported = $entry->context . chr(4) . $exported;
     81                return $exported;
     82        }
     83       
     84        function export_translations($entry) {
     85                //TODO: warnings for control characters
     86                return implode(chr(0), $entry->translations);
     87        }
     88       
     89        function export_headers() {
     90                $exported = '';
     91                foreach($this->headers as $header => $value) {
     92                        $exported.= "$header: $value\n";
     93                }
     94                return $exported;
     95        }
    3596
    3697        function get_byteorder($magic) {
     
    43104                // 0xde120495
    44105                $magic_big = ((int) - 569244523) && 0xFFFFFFFF;
    45 
     106               
    46107                if ($magic_little == $magic || $magic_little_64 == $magic) {
    47108                        return 'little';
     
    64125                $total = $reader->readint32();
    65126                // get addresses of array of lenghts and offsets for original string and translations
    66                 $originals_lo_addr = $reader->readint32();
    67                 $translations_lo_addr = $reader->readint32();
     127                $originals_lenghts_addr = $reader->readint32();
     128                $translations_lenghts_addr = $reader->readint32();
    68129
    69                 $reader->seekto($originals_lo_addr);
    70                 $originals_lo = $reader->readint32array($total * 2); // each of
    71                 $reader->seekto($translations_lo_addr);
    72                 $translations_lo = $reader->readint32array($total * 2);
     130                $reader->seekto($originals_lenghts_addr);
     131                $originals_lenghts = $reader->readint32array($total * 2); // each of
     132                $reader->seekto($translations_lenghts_addr);
     133                $translations_lenghts = $reader->readint32array($total * 2);
    73134
    74135                $length = create_function('$i', 'return $i * 2 + 1;');
     
    76137
    77138                for ($i = 0; $i < $total; ++$i) {
    78                         $reader->seekto($originals_lo[$offset($i)]);
    79                         $original = $reader->read($originals_lo[$length($i)]);
    80                         $reader->seekto($translations_lo[$offset($i)]);
    81                         $translation = $reader->read($translations_lo[$length($i)]);
     139                        $reader->seekto($originals_lenghts[$offset($i)]);
     140                        $original = $reader->read($originals_lenghts[$length($i)]);
     141                        $reader->seekto($translations_lenghts[$offset($i)]);
     142                        $translation = $reader->read($translations_lenghts[$length($i)]);
    82143                        if ('' == $original) {
    83144                                $this->set_headers($this->make_headers($translation));
     
    87148                }
    88149                return true;
    89         }
    90 
    91         function make_headers($translation) {
    92                 $headers = array();
    93                 $lines = explode("\n", $translation);
    94                 foreach($lines as $line) {
    95                         $parts = explode(':', $line, 2);
    96                         if (!isset($parts[1])) continue;
    97                         $headers[trim($parts[0])] = trim($parts[1]);
    98                 }
    99                 return $headers;
    100150        }
    101151
  • trunk/wp-includes/pomo/po.php

    r10810 r11626  
    33 * Class for working with PO files
    44 *
    5  * @version $Id: po.php 33 2009-02-16 09:33:39Z nbachiyski $
     5 * @version $Id: po.php 123 2009-05-13 19:35:43Z nbachiyski $
    66 * @package pomo
    77 * @subpackage po
     
    1717 * Routines for working with PO files
    1818 */
    19 class PO extends Translations {
    20 
     19class PO extends Gettext_Translations {
     20       
    2121
    2222        /**
     
    7676        }
    7777
    78 
    7978        /**
    8079         * Formats a string in PO-style
     
    8887                $slash = '\\';
    8988                $newline = "\n";
    90                 $tab = "\t";
    9189
    9290                $replaces = array(
    9391                        "$slash"        => "$slash$slash",
    94                         "$tab"          => '\t',
    9592                        "$quote"        => "$slash$quote",
     93                        "\t"            => '\t',
    9694                );
     95
    9796                $string = str_replace(array_keys($replaces), array_values($replaces), $string);
    9897
    99                 $po = array();
    100                 foreach (explode($newline, $string) as $line) {
    101                         $po[] = wordwrap($line, PO_MAX_LINE_LEN - 2, " $quote$newline$quote");
    102                 }
    103                 $po = $quote.implode("${slash}n$quote$newline$quote", $po).$quote;
     98                $po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
    10499                // add empty string on first line for readbility
    105                 if (false !== strpos($po, $newline)) {
     100                if (false !== strpos($string, $newline) &&
     101                                (substr_count($string, $newline) > 1 || !($newline === substr($string, -strlen($newline))))) {
    106102                        $po = "$quote$quote$newline$po";
    107103                }
     
    110106                return $po;
    111107        }
    112 
    113         /**
    114          * Inserts $with in the beginning of every new line of $string and
     108       
     109        /**
     110         * Gives back the original string from a PO-formatted string
     111         *
     112         * @static
     113         * @param string $string PO-formatted string
     114         * @return string enascaped string
     115         */
     116        function unpoify($string) {
     117                $escapes = array('t' => "\t", 'n' => "\n", '\\' => '\\');
     118                $lines = array_map('trim', explode("\n", $string));
     119                $lines = array_map(array('PO', 'trim_quotes'), $lines);
     120                $unpoified = '';
     121                $previous_is_backslash = false;
     122                foreach($lines as $line) {
     123                        preg_match_all('/./u', $line, $chars);
     124                        $chars = $chars[0];
     125                        foreach($chars as $char) {
     126                                if (!$previous_is_backslash) {
     127                                        if ('\\' == $char)
     128                                                $previous_is_backslash = true;
     129                                        else
     130                                                $unpoified .= $char;
     131                                } else {
     132                                        $previous_is_backslash = false;
     133                                        $unpoified .= isset($escapes[$char])? $escapes[$char] : $char;
     134                                }
     135                        }
     136                }
     137                return $unpoified;
     138        }
     139
     140        /**
     141         * Inserts $with in the beginning of every new line of $string and
    115142         * returns the modified string
    116143         *
     
    158185                if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.');
    159186                if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':');
    160                 if (!empty($entry->flags)) $po[] = PO::comment_block(implode("\n", $entry->flags), ',');
     187                if (!empty($entry->flags)) $po[] = PO::comment_block(implode(", ", $entry->flags), ',');
    161188                if (!is_null($entry->context)) $po[] = 'msgctxt '.PO::poify($entry->context);
    162189                $po[] = 'msgid '.PO::poify($entry->singular);
     
    174201        }
    175202
     203        function import_from_file($filename) {
     204                $f = fopen($filename, 'r');
     205                if (!$f) return false;
     206                $lineno = 0;
     207                while (true) {
     208                        $res = $this->read_entry($f, $lineno);
     209                        if (!$res) break;
     210                        if ($res['entry']->singular == '') {
     211                                $this->set_headers($this->make_headers($res['entry']->translations[0]));
     212                        } else {
     213                                $this->add_entry($res['entry']);
     214                        }
     215                }
     216                PO::read_line($f, 'clear');
     217                return $res !== false;
     218        }
     219       
     220        function read_entry($f, $lineno = 0) {
     221                $entry = new Translation_Entry();
     222                // where were we in the last step
     223                // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
     224                $context = '';
     225                $msgstr_index = 0;
     226                $is_final = create_function('$context', 'return $context == "msgstr" || $context == "msgstr_plural";');
     227                while (true) {
     228                        $lineno++;
     229                        $line = PO::read_line($f);
     230                        if (!$line)  {
     231                                if (feof($f)) {
     232                                        if ($is_final($context))
     233                                                break;
     234                                        elseif (!$context) // we haven't read a line and eof came
     235                                                return null;
     236                                        else
     237                                                return false;
     238                                } else {
     239                                        return false;
     240                                }
     241                        }
     242                        if ($line == "\n") continue;
     243                        $line = trim($line);
     244                        if (preg_match('/^#/', $line, $m)) {
     245                                // the comment is the start of a new entry
     246                                if ($is_final($context)) {
     247                                        PO::read_line($f, 'put-back');
     248                                        $lineno--;
     249                                        break;
     250                                }
     251                                // comments have to be at the beginning
     252                                if ($context && $context != 'comment') {
     253                                        return false;
     254                                }
     255                                // add comment
     256                                $this->add_comment_to_entry($entry, $line);;
     257                        } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
     258                                if ($is_final($context)) {
     259                                        PO::read_line($f, 'put-back');
     260                                        $lineno--;
     261                                        break;
     262                                }
     263                                if ($context && $context != 'comment') {
     264                                        return false;
     265                                }
     266                                $context = 'msgctxt';
     267                                $entry->context .= PO::unpoify($m[1]);
     268                        } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
     269                                if ($is_final($context)) {
     270                                        PO::read_line($f, 'put-back');
     271                                        $lineno--;
     272                                        break;
     273                                }
     274                                if ($context && $context != 'msgctxt' && $context != 'comment') {
     275                                        return false;
     276                                }
     277                                $context = 'msgid';
     278                                $entry->singular .= PO::unpoify($m[1]);
     279                        } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
     280                                if ($context != 'msgid') {
     281                                        return false;
     282                                }
     283                                $context = 'msgid_plural';
     284                                $entry->is_plural = true;
     285                                $entry->plural .= PO::unpoify($m[1]);
     286                        } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
     287                                if ($context != 'msgid') {
     288                                        return false;
     289                                }
     290                                $context = 'msgstr';
     291                                $entry->translations = array(PO::unpoify($m[1]));
     292                        } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
     293                                if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
     294                                        return false;
     295                                }
     296                                $context = 'msgstr_plural';
     297                                $msgstr_index = $m[1];
     298                                $entry->translations[$m[1]] = PO::unpoify($m[2]);
     299                        } elseif (preg_match('/^".*"$/', $line)) {
     300                                $unpoified = PO::unpoify($line);
     301                                switch ($context) {
     302                                        case 'msgid':
     303                                                $entry->singular .= $unpoified; break;
     304                                        case 'msgctxt':
     305                                                $entry->context .= $unpoified; break;
     306                                        case 'msgid_plural':
     307                                                $entry->plural .= $unpoified; break;
     308                                        case 'msgstr':
     309                                                $entry->translations[0] .= $unpoified; break;
     310                                        case 'msgstr_plural':
     311                                                $entry->translations[$msgstr_index] .= $unpoified; break;
     312                                        default:
     313                                                return false;
     314                                }
     315                        } else {
     316                                return false;
     317                        }
     318                }
     319                if (array() == array_filter($entry->translations)) $entry->translations = array();
     320                return array('entry' => $entry, 'lineno' => $lineno);
     321        }
     322       
     323        function read_line($f, $action = 'read') {
     324                static $last_line = '';
     325                static $use_last_line = false;
     326                if ('clear' == $action) {
     327                        $last_line = '';
     328                        return true;
     329                }
     330                if ('put-back' == $action) {
     331                        $use_last_line = true;
     332                        return true;
     333                }
     334                $line = $use_last_line? $last_line : fgets($f);
     335                $last_line = $line;
     336                $use_last_line = false;
     337                return $line;
     338        }
     339       
     340        function add_comment_to_entry(&$entry, $po_comment_line) {
     341                $first_two = substr($po_comment_line, 0, 2);
     342                $comment = trim(substr($po_comment_line, 2));
     343                if ('#:' == $first_two) {
     344                        $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
     345                } elseif ('#.' == $first_two) {
     346                        $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
     347                } elseif ('#,' == $first_two) {
     348                        $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
     349                } else {
     350                        $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
     351                }
     352        }
     353       
     354        function trim_quotes($s) {
     355                if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
     356                if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
     357                return $s;
     358        }
    176359}
    177360?>
  • trunk/wp-includes/pomo/streams.php

    r10584 r11626  
    44 * Based on the classes from Danilo Segan <danilo@kvota.net>
    55 *
    6  * @version $Id: streams.php 33 2009-02-16 09:33:39Z nbachiyski $
     6 * @version $Id: streams.php 138 2009-06-23 13:22:09Z nbachiyski $
    77 * @package pomo
    88 * @subpackage streams
     
    1818  var $_str;
    1919
    20   function POMO_StringReader($str = '') {
    21     $this->_str = $str;
    22     $this->_pos = 0;
    23   }
     20        function POMO_StringReader($str = '') {
     21                $this->_str = $str;
     22                $this->_pos = 0;
     23                $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
     24        }
    2425
    25   function read($bytes) {
    26     $data = substr($this->_str, $this->_pos, $bytes);
    27     $this->_pos += $bytes;
    28     if (strlen($this->_str)<$this->_pos)
    29       $this->_pos = strlen($this->_str);
     26        function _substr($string, $start, $length) {
     27                if ($this->is_overloaded) {
     28                        return mb_substr($string,$start,$length,'ascii');
     29                } else {
     30                        return substr($string,$start,$length);
     31                }
     32        }
     33       
     34        function _strlen($string) {
     35                if ($this->is_overloaded) {
     36                        return mb_strlen($string,'ascii');
     37                } else {
     38                        return strlen($string);
     39                }
     40        }
    3041
    31     return $data;
    32   }
     42        function read($bytes) {
     43                $data = $this->_substr($this->_str, $this->_pos, $bytes);
     44                $this->_pos += $bytes;
     45                if ($this->_strlen($this->_str) < $this->_pos) $this->_pos = $this->_strlen($this->_str);
     46                return $data;
     47        }
    3348
    34   function seekto($pos) {
    35     $this->_pos = $pos;
    36     if (strlen($this->_str)<$this->_pos)
    37       $this->_pos = strlen($this->_str);
    38     return $this->_pos;
    39   }
     49        function seekto($pos) {
     50                $this->_pos = $pos;
     51                if ($this->_strlen($this->_str) < $this->_pos) $this->_pos = $this->_strlen($this->_str);
     52                return $this->_pos;
     53        }
    4054
    41   function pos() {
    42     return $this->_pos;
    43   }
     55        function pos() {
     56                return $this->_pos;
     57        }
    4458
    45   function length() {
    46     return strlen($this->_str);
    47   }
     59        function length() {
     60                return $this->_strlen($this->_str);
     61        }
    4862
    4963}
     
    5468class POMO_CachedFileReader extends POMO_StringReader {
    5569        function POMO_CachedFileReader($filename) {
     70                parent::POMO_StringReader();
    5671                $this->_str = file_get_contents($filename);
    5772                if (false === $this->_str)
    5873                        return false;
    59                 $this->pos = 0;
     74                $this->_pos = 0;
    6075        }
    6176}
     
    97112        function readint32() {
    98113                $bytes = $this->read(4);
    99                 if (4 != strlen($bytes))
     114                if (4 != $this->_strlen($bytes))
    100115                        return false;
    101116                $endian_letter = ('big' == $this->endian)? 'N' : 'V';
     
    113128        function readint32array($count) {
    114129                $bytes = $this->read(4 * $count);
    115                 if (4*$count != strlen($bytes))
     130                if (4*$count != $this->_strlen($bytes))
    116131                        return false;
    117132                $endian_letter = ('big' == $this->endian)? 'N' : 'V';
  • trunk/wp-includes/pomo/translations.php

    r10810 r11626  
    33 * Class for a set of entries for translation and their associated headers
    44 *
    5  * @version $Id: translations.php 35 2009-02-16 12:54:57Z nbachiyski $
     5 * @version $Id: translations.php 114 2009-05-11 17:30:38Z nbachiyski $
    66 * @package pomo
    77 * @subpackage translations
     
    2020         * @return bool true on success, false if the entry doesn't have a key
    2121         */
    22         function add_entry(&$entry) {
     22        function add_entry($entry) {
     23                if (is_array($entry)) {
     24                        $entry = new Translation_Entry($entry);
     25                }
    2326                $key = $entry->key();
    2427                if (false === $key) return false;
    25                 $this->entries[$key] = &$entry;
     28                $this->entries[$key] = $entry;
    2629                return true;
    2730        }
     
    8891                if ($translated && 0 <= $index && $index < $total_plural_forms &&
    8992                                is_array($translated->translations) &&
    90                                 count($translated->translations) == $total_plural_forms)
     93                                isset($translated->translations[$index]))
    9194                        return $translated->translations[$index];
    9295                else
     
    9497        }
    9598
     99        /**
     100         * Merge $other in the current object.
     101         *
     102         * @param Object &$other Another Translation object, whose translations will be merged in this one
     103         * @return void
     104         **/
     105        function merge_with(&$other) {
     106                $this->entries = array_merge($this->entries, $other->entries);
     107        }
     108}
     109
     110class Gettext_Translations extends Translations {
    96111        /**
    97112         * The gettext implmentation of select_plural_form.
     
    131146         * Adds parantheses to the inner parts of ternary operators in
    132147         * plural expressions, because PHP evaluates ternary oerators from left to right
    133          *
     148         * 
    134149         * @param string $expression the expression without parentheses
    135150         * @return string the expression with parentheses added
     
    159174                return rtrim($res, ';');
    160175        }
     176       
     177        function make_headers($translation) {
     178                $headers = array();
     179                // sometimes \ns are used instead of real new lines
     180                $translation = str_replace('\n', "\n", $translation);
     181                $lines = explode("\n", $translation);
     182                foreach($lines as $line) {
     183                        $parts = explode(':', $line, 2);
     184                        if (!isset($parts[1])) continue;
     185                        $headers[trim($parts[0])] = trim($parts[1]);
     186                }
     187                return $headers;
     188        }
    161189
    162         /**
    163          * Merge $other in the current object.
    164          *
    165          * @param Object &$other Another Translation object, whose translations will be merged in this one
    166          * @return void
    167          **/
    168         function merge_with(&$other) {
    169                 $this->entries = array_merge($this->entries, $other->entries);
     190        function set_header($header, $value) {
     191                parent::set_header($header, $value);
     192                if ('Plural-Forms' == $header)
     193                        $this->_gettext_select_plural_form = $this->_make_gettext_select_plural_form($value);
    170194        }
     195
     196       
    171197}
    172198
Note: See TracChangeset for help on using the changeset viewer.