Changeset 2394

Show
Ignore:
Timestamp:
02/28/05 16:31:01 (3 years ago)
Author:
ryan
Message:

Bump php-gettext to version 1.0.3. http://mosquito.wordpress.org/view.php?id=1001 Mad props to Nico Kaiser.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/wp-includes/gettext.php

    r1817 r2394  
    22/* 
    33   Copyright (c) 2003 Danilo Segan <danilo@kvota.net>. 
    4  
     4   Copyright (c) 2005 Nico Kaiser <nico@siriux.net> 
     5    
    56   This file is part of PHP-gettext. 
    67 
     
    2122*/ 
    2223  
    23  
    24  
    25   // For start, we only want to read the MO files 
    26  
     24/** 
     25 * Provides a simple gettext replacement that works independently from 
     26 * the system's gettext abilities. 
     27 * It can read MO files and use them for translating strings. 
     28 * The files are passed to gettext_reader as a Stream (see streams.php) 
     29 *  
     30 * This version has the ability to cache all strings and translations to 
     31 * speed up the string lookup. 
     32 * While the cache is enabled by default, it can be switched off with the 
     33 * second parameter in the constructor (e.g. whenusing very large MO files 
     34 * that you don't want to keep in memory) 
     35 */ 
    2736class gettext_reader { 
    28 //public: 
    29   var $error = 0; // public variable that holds error code (0 if no error) 
    30 //private: 
    31   var $BYTEORDER = 0; 
     37  //public: 
     38   var $error = 0; // public variable that holds error code (0 if no error) 
     39    
     40   //private: 
     41  var $BYTEORDER = 0;        // 0: low endian, 1: big endian 
    3242  var $STREAM = NULL; 
    3343  var $short_circuit = false; 
    34  
     44  var $enable_cache = false; 
     45  var $originals = NULL;      // offset of original table 
     46  var $translations = NULL;    // offset of translation table 
     47  var $pluralheader = NULL;    // cache header field for plural forms 
     48  var $total = 0;          // total string count 
     49  var $table_originals = NULL;  // table for original strings (offsets) 
     50  var $table_translations = NULL;  // table for translated strings (offsets) 
     51  var $cache_translations = NULL;  // original -> translation mapping 
     52 
     53 
     54  /* Methods */ 
     55   
     56     
     57  /** 
     58   * Reads a 32bit Integer from the Stream 
     59   *  
     60   * @access private 
     61   * @return Integer from the Stream 
     62   */ 
    3563  function readint() { 
    36     // Reads 4 byte value from $FD and puts it in int 
    37     // $BYTEORDER specifies the byte order: 0 low endian, 1 big endian 
    38     for ($i=0; $i<4; $i++) { 
    39       $byte[$i]=ord($this->STREAM->read(1)); 
    40     } 
    41     //print sprintf("pos: %d\n",$this->STREAM->currentpos()); 
    42     if ($this->BYTEORDER == 0)  
    43       return (int)(($byte[0]) | ($byte[1]<<8) | ($byte[2]<<16) | ($byte[3]<<24)); 
    44     else  
    45       return (int)(($byte[3]) | ($byte[2]<<8) | ($byte[1]<<16) | ($byte[0]<<24)); 
    46   } 
    47  
    48   // constructor that requires StreamReader object 
    49   function gettext_reader($Reader) { 
     64      if ($this->BYTEORDER == 0) { 
     65        // low endian 
     66        return array_shift(unpack('V', $this->STREAM->read(4))); 
     67      } else { 
     68        // big endian 
     69        return array_shift(unpack('N', $this->STREAM->read(4))); 
     70      } 
     71    } 
     72 
     73  /** 
     74   * Reads an array of Integers from the Stream 
     75   *  
     76   * @param int count How many elements should be read 
     77   * @return Array of Integers 
     78   */ 
     79  function readintarray($count) { 
     80    if ($this->BYTEORDER == 0) { 
     81        // low endian 
     82        return unpack('V'.$count, $this->STREAM->read(4 * $count)); 
     83      } else { 
     84        // big endian 
     85        return unpack('N'.$count, $this->STREAM->read(4 * $count)); 
     86      } 
     87  } 
     88   
     89  /** 
     90   * Constructor 
     91   *  
     92   * @param object Reader the StreamReader object 
     93   * @param boolean enable_cache Enable or disable caching of strings (default on) 
     94   */ 
     95  function gettext_reader($Reader, $enable_cache = true) { 
    5096    // If there isn't a StreamReader, turn on short circuit mode. 
    5197    if (! $Reader) { 
    52         $this->short_circuit = true; 
    53         return; 
    54     } 
    55  
    56     // $MAGIC1 = (int)0x950412de; //bug in PHP 5 
    57     $MAGIC1 = (int) - 1794895138; 
    58     // $MAGIC2 = (int)0xde120495; //bug 
    59     $MAGIC2 = (int) - 569244523; 
    60  
     98      $this->short_circuit = true; 
     99      return; 
     100    } 
     101     
     102    // Caching can be turned off 
     103    $this->enable_cache = $enable_cache; 
     104 
     105    // $MAGIC1 = (int)0x950412de; //bug in PHP 5 
     106    $MAGIC1 = (int) - 1794895138; 
     107    // $MAGIC2 = (int)0xde120495; //bug 
     108    $MAGIC2 = (int) - 569244523; 
    61109 
    62110    $this->STREAM = $Reader; 
     
    70118      return false; 
    71119    } 
    72  
     120     
    73121    // FIXME: Do we care about revision? We should. 
    74122    $revision = $this->readint(); 
    75  
    76     $total = $this->readint(); 
    77     $originals = $this->readint(); 
    78     $translations = $this->readint(); 
    79  
    80     $this->total = $total; 
    81     $this->originals = $originals; 
    82     $this->translations = $translations; 
    83  
    84   } 
    85  
    86   function load_tables($translations=false) { 
    87     // if tables are loaded do not load them again 
    88     if (!is_array($this->ORIGINALS)) { 
    89       $this->ORIGINALS = array(); 
    90       $this->STREAM->seekto($this->originals); 
    91       for ($i=0; $i<$this->total; $i++) { 
    92     $len = $this->readint(); 
    93     $ofs = $this->readint(); 
    94     $this->ORIGINALS[] = array($len,$ofs); 
    95       } 
    96     } 
    97  
    98     // similar for translations 
    99     if ($translations and !is_array($this->TRANSLATIONS)) { 
    100       $this->TRANSLATIONS = array(); 
    101       $this->STREAM->seekto($this->translations); 
    102       for ($i=0; $i<$this->total; $i++) { 
    103     $len = $this->readint(); 
    104     $ofs = $this->readint(); 
    105     $this->TRANSLATIONS[] = array($len,$ofs); 
    106       } 
    107     } 
    108  
    109   } 
    110  
    111   function get_string_number($num) { 
    112     // get a string with particular number 
    113     // TODO: Add simple hashing [check array, add if not already there] 
    114     $this->load_tables(); 
    115     $meta = $this->ORIGINALS[$num]; 
    116     $length = $meta[0]; 
    117     $offset = $meta[1]; 
    118         if (! $length) { 
    119             return ''; 
    120         } 
     123     
     124    $this->total = $this->readint(); 
     125    $this->originals = $this->readint(); 
     126    $this->translations = $this->readint(); 
     127  } 
     128   
     129  /** 
     130   * Loads the translation tables from the MO file into the cache 
     131   * If caching is enabled, also loads all strings into a cache 
     132   * to speed up translation lookups 
     133   *  
     134   * @access private 
     135   */ 
     136  function load_tables() { 
     137    if (is_array($this->cache_translations) && 
     138      is_array($this->table_originals) && 
     139      is_array($this->table_translations)) 
     140      return; 
     141     
     142    /* get original and translations tables */ 
     143    $this->STREAM->seekto($this->originals); 
     144    $this->table_originals = $this->readintarray($this->total * 2); 
     145    $this->STREAM->seekto($this->translations); 
     146    $this->table_translations = $this->readintarray($this->total * 2); 
     147     
     148    if ($this->enable_cache) { 
     149      $this->cache_translations = array (); 
     150      /* read all strings in the cache */ 
     151      for ($i = 0; $i < $this->total; $i++) { 
     152        $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); 
     153        $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); 
     154        $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); 
     155        $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); 
     156        $this->cache_translations[$original] = $translation; 
     157      } 
     158    } 
     159  } 
     160   
     161  /** 
     162   * Returns a string from the "originals" table 
     163   *  
     164   * @access private 
     165   * @param int num Offset number of original string 
     166   * @return string Requested string if found, otherwise '' 
     167   */ 
     168  function get_original_string($num) { 
     169    $length = $this->table_originals[$num * 2 + 1]; 
     170    $offset = $this->table_originals[$num * 2 + 2]; 
     171    if (! $length) 
     172      return ''; 
    121173    $this->STREAM->seekto($offset); 
    122174    $data = $this->STREAM->read($length); 
    123175    return (string)$data; 
    124176  } 
    125  
    126   function get_translation_number($num) { 
    127     // get a string with particular number 
    128     // TODO: Add simple hashing [check array, add if not already there] 
    129     $this->load_tables(true); 
    130     $meta = $this->TRANSLATIONS[$num]; 
    131     $length = $meta[0]; 
    132     $offset = $meta[1]; 
     177   
     178  /** 
     179   * Returns a string from the "translations" table 
     180   *  
     181   * @access private 
     182   * @param int num Offset number of original string 
     183   * @return string Requested string if found, otherwise '' 
     184   */ 
     185  function get_translation_string($num) { 
     186    $length = $this->table_translations[$num * 2 + 1]; 
     187    $offset = $this->table_translations[$num * 2 + 2]; 
     188    if (! $length) 
     189      return ''; 
    133190    $this->STREAM->seekto($offset); 
    134191    $data = $this->STREAM->read($length); 
     
    136193  } 
    137194   
    138   // binary search for string 
    139   function find_string($string, $start,$end) { 
    140     //print "start: $start, end: $end\n"; 
    141     if (abs($start-$end)<=1) { 
    142       // we're done, if it's not it, bye bye 
    143       $txt = $this->get_string_number($start); 
     195  /** 
     196   * Binary search for string 
     197   *  
     198   * @access private 
     199   * @param string string 
     200   * @param int start (internally used in recursive function) 
     201   * @param int end (internally used in recursive function) 
     202   * @return int string number (offset in originals table) 
     203   */ 
     204  function find_string($string, $start = -1, $end = -1) { 
     205    if (($start == -1) or ($end == -1)) { 
     206      // find_string is called with only one parameter, set start end end 
     207      $start = 0; 
     208      $end = $this->total; 
     209    } 
     210    if (abs($start - $end) <= 1) { 
     211      // We're done, now we either found the string, or it doesn't exist 
     212      $txt = $this->get_original_string($start); 
    144213      if ($string == $txt) 
    145     return $start; 
    146       else 
    147     return -1; 
    148     } elseif ($start>$end) { 
    149       return $this->find_string($string,$end,$start); 
    150     }  else { 
    151       $half = (int)(($start+$end)/2); 
    152       $tst = $this->get_string_number($half); 
    153       $cmp = strcmp($string,$tst); 
    154       if ($cmp == 0)  
    155     return $half; 
    156       elseif ($cmp<0)  
    157     return $this->find_string($string,$start,$half); 
    158       else 
    159     return $this->find_string($string,$half,$end); 
    160     } 
    161   } 
    162  
     214        return $start; 
     215      else 
     216        return -1; 
     217    } else if ($start > $end) { 
     218      // start > end -> turn around and start over 
     219      return $this->find_string($string, $end, $start); 
     220    } else { 
     221      // Divide table in two parts 
     222      $half = (int)(($start + $end) / 2); 
     223      $cmp = strcmp($string, $this->get_original_string($half)); 
     224      if ($cmp == 0) 
     225        // string is exactly in the middle => return it 
     226        return $half; 
     227      else if ($cmp < 0) 
     228        // The string is in the upper half 
     229        return $this->find_string($string, $start, $half); 
     230      else 
     231        // The string is in the lower half 
     232        return $this->find_string($string, $half, $end); 
     233    } 
     234  } 
     235   
     236  /** 
     237   * Translates a string 
     238   *  
     239   * @access public 
     240   * @param string string to be translated 
     241   * @return string translated string (or original, if not found) 
     242   */ 
    163243  function translate($string) { 
    164     if ($this->short_circuit) { 
     244    if ($this->short_circuit) 
     245      return $string; 
     246    $this->load_tables();      
     247     
     248    if ($this->enable_cache) { 
     249      // Caching enabled, get translated string from cache 
     250      if (array_key_exists($string, $this->cache_translations)) 
     251        return $this->cache_translations[$string]; 
     252      else 
    165253        return $string; 
    166     } 
    167  
    168     $num = $this->find_string($string, 0, $this->total); 
    169     if ($num == -1) 
    170       return $string; 
    171     else  
    172       return $this->get_translation_number($num); 
    173   } 
    174  
     254    } else { 
     255      // Caching not enabled, try to find string 
     256      $num = $this->find_string($string); 
     257      if ($num == -1) 
     258        return $string; 
     259      else 
     260        return $this->get_translation_string($num); 
     261    } 
     262  } 
     263 
     264  /** 
     265   * Get possible plural forms from MO header 
     266   *  
     267   * @access private 
     268   * @return string plural form header 
     269   */ 
    175270  function get_plural_forms() { 
    176     // lets assume message number 0 is header 
     271    // lets assume message number 0 is header   
    177272    // this is true, right? 
    178  
     273    $this->load_tables(); 
     274     
    179275    // cache header field for plural forms 
    180     if (is_string($this->pluralheader))  
    181       return $this->pluralheader; 
    182     else { 
    183       $header = $this->get_translation_number(0); 
    184  
    185       if (eregi("plural-forms: (.*)\n",$header,$regs)) { 
    186     $expr = $regs[1]; 
    187       } else { 
    188     $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; 
    189       } 
     276    if (! is_string($this->pluralheader)) { 
     277      if ($this->enable_cache) { 
     278        $header = $this->cache_translations[""]; 
     279      } else { 
     280        $header = $this->get_translation_string(0); 
     281      } 
     282      if (eregi("plural-forms: (.*)\n", $header, $regs)) 
     283        $expr = $regs[1]; 
     284      else 
     285        $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; 
    190286      $this->pluralheader = $expr; 
    191       return $expr; 
    192     } 
    193   } 
    194  
     287    } 
     288    return $this->pluralheader; 
     289  } 
     290 
     291  /** 
     292   * Detects which plural form to take 
     293   *  
     294   * @access private 
     295   * @param n count 
     296   * @return int array index of the right plural form 
     297   */ 
    195298  function select_string($n) { 
    196299    $string = $this->get_plural_forms(); 
     
    198301    $string = str_replace("n",$n,$string); 
    199302    $string = str_replace('plural',"\$plural",$string); 
    200  
     303     
    201304    $total = 0; 
    202305    $plural = 0; 
    203306 
    204307    eval("$string"); 
    205     if ($plural>=$total) $plural = 0; 
     308    if ($plural >= $total) $plural = 0; 
    206309    return $plural; 
    207310  } 
    208311 
     312  /** 
     313   * Plural version of gettext 
     314   *  
     315   * @access public 
     316   * @param string single 
     317   * @param string plural 
     318   * @param string number 
     319   * @return translated plural form 
     320   */ 
    209321  function ngettext($single, $plural, $number) { 
    210322    if ($this->short_circuit) { 
    211       if ($number != 1) return $plural; 
    212       else return $single; 
     323      if ($number != 1) 
     324        return $plural; 
     325      else 
     326        return $single; 
    213327    } 
    214328 
     
    216330    $select = $this->select_string($number);  
    217331     
    218  
    219332    // this should contains all strings separated by NULLs 
    220     $result = $this->find_string($single.chr(0).$plural,0,$this->total); 
    221     if ($result == -1) { 
    222       if ($number != 1) return $plural; 
    223       else return $single; 
     333    $key = $single.chr(0).$plural; 
     334     
     335     
     336    if ($this->enable_cache) { 
     337      if (! array_key_exists($key, $this->cache_translations)) { 
     338        return ($number != 1) ? $plural : $single; 
     339      } else { 
     340        $result = $this->cache_translations[$key]; 
     341        $list = explode(chr(0), $result); 
     342        return $list[$select]; 
     343      } 
    224344    } else { 
    225       $result = $this->get_translation_number($result); 
    226      
    227       // lets try to parse all the NUL staff 
    228       //$result = "proba0".chr(0)."proba1".chr(0)."proba2"; 
    229       $list = explode (chr(0), $result); 
    230       return $list[$select]; 
     345      $num = $this->find_string($key); 
     346      if ($num == -1) { 
     347        return ($number != 1) ? $plural : $single; 
     348      } else { 
     349        $result = $this->get_translation_string($num); 
     350        $list = explode(chr(0), $result); 
     351        return $list[$select]; 
     352      } 
    231353    } 
    232354  } 
     
    234356} 
    235357 
    236  
    237358?> 
  • trunk/wp-includes/streams.php

    r1080 r2394  
    11<?php 
    22/* 
    3    Copyright (c) 2003 Danilo Segan <danilo@kvota.net>. 
     3   Copyright (c) 2003, 2005 Danilo Segan <danilo@kvota.net>. 
    44 
    55   This file is part of PHP-gettext. 
     
    104104 
    105105  function read($bytes) { 
    106     fseek($this->_fd, $this->_pos); 
    107     $data = fread($this->_fd, $bytes); 
    108     $this->_pos = ftell($this->_fd); 
    109  
    110     return $data; 
     106    if ($bytes) { 
     107      fseek($this->_fd, $this->_pos); 
     108      $data = fread($this->_fd, $bytes); 
     109      $this->_pos = ftell($this->_fd); 
     110       
     111      return $data; 
     112    } else return ''; 
    111113  } 
    112114 
     
    131133} 
    132134 
     135// Preloads entire file in memory first, then creates a StringReader  
     136// over it (it assumes knowledge of StringReader internals) 
     137class CachedFileReader extends StringReader { 
     138  function CachedFileReader($filename) { 
     139    if (file_exists($filename)) { 
     140 
     141      $length=filesize($filename); 
     142      $fd = fopen($filename,'rb'); 
     143 
     144      if (!$fd) { 
     145    $this->error = 3; // Cannot read file, probably permissions 
     146    return false; 
     147      } 
     148      $this->_str = fread($fd, $length); 
     149      fclose($fd); 
     150 
     151    } else { 
     152      $this->error = 2; // File doesn't exist 
     153      return false; 
     154    } 
     155  } 
     156} 
     157 
     158 
    133159?> 
  • trunk/wp-includes/wp-l10n.php

    r2238 r2394  
    6767 
    6868    if ( is_readable($mofile)) { 
    69     $input = new FileReader($mofile); 
     69    $input = new CachedFileReader($mofile); 
    7070    }   else { 
    7171        return;