[ Index ]
 

Code source de WordPress 2.1.2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/wp-includes/ -> gettext.php (source)

   1  <?php
   2  /*
   3     Copyright (c) 2003 Danilo Segan <danilo@kvota.net>.
   4     Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
   5     
   6     This file is part of PHP-gettext.
   7  
   8     PHP-gettext is free software; you can redistribute it and/or modify
   9     it under the terms of the GNU General Public License as published by
  10     the Free Software Foundation; either version 2 of the License, or
  11     (at your option) any later version.
  12  
  13     PHP-gettext is distributed in the hope that it will be useful,
  14     but WITHOUT ANY WARRANTY; without even the implied warranty of
  15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16     GNU General Public License for more details.
  17  
  18     You should have received a copy of the GNU General Public License
  19     along with PHP-gettext; if not, write to the Free Software
  20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21  
  22  */
  23   
  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   */
  36  class gettext_reader {
  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
  42    var $STREAM = NULL;
  43    var $short_circuit = false;
  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     */
  63    function readint() {
  64        if ($this->BYTEORDER == 0) {
  65          // low endian
  66          $low_end = unpack('V', $this->STREAM->read(4));
  67          return array_shift($low_end);
  68        } else {
  69          // big endian
  70          $big_end = unpack('N', $this->STREAM->read(4));
  71          return array_shift($big_end);
  72        }
  73      }
  74  
  75    /**
  76     * Reads an array of Integers from the Stream
  77     * 
  78     * @param int count How many elements should be read
  79     * @return Array of Integers
  80     */
  81    function readintarray($count) {
  82      if ($this->BYTEORDER == 0) {
  83          // low endian
  84          return unpack('V'.$count, $this->STREAM->read(4 * $count));
  85        } else {
  86          // big endian
  87          return unpack('N'.$count, $this->STREAM->read(4 * $count));
  88        }
  89    }
  90    
  91    /**
  92     * Constructor
  93     * 
  94     * @param object Reader the StreamReader object
  95     * @param boolean enable_cache Enable or disable caching of strings (default on)
  96     */
  97    function gettext_reader($Reader, $enable_cache = true) {
  98      // If there isn't a StreamReader, turn on short circuit mode.
  99      if (! $Reader || isset($Reader->error) ) {
 100        $this->short_circuit = true;
 101        return;
 102      }
 103      
 104      // Caching can be turned off
 105      $this->enable_cache = $enable_cache;
 106  
 107      // $MAGIC1 = (int)0x950412de; //bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
 108      $MAGIC1 = (int) - 1794895138;
 109      // $MAGIC2 = (int)0xde120495; //bug
 110      $MAGIC2 = (int) - 569244523;
 111  
 112      $this->STREAM = $Reader;
 113      $magic = $this->readint();
 114      if ($magic == ($MAGIC1 & 0xFFFFFFFF)) { // to make sure it works for 64-bit platforms
 115        $this->BYTEORDER = 0;
 116      } elseif ($magic == ($MAGIC2 & 0xFFFFFFFF)) {
 117        $this->BYTEORDER = 1;
 118      } else {
 119        $this->error = 1; // not MO file
 120        return false;
 121      }
 122      
 123      // FIXME: Do we care about revision? We should.
 124      $revision = $this->readint();
 125      
 126      $this->total = $this->readint();
 127      $this->originals = $this->readint();
 128      $this->translations = $this->readint();
 129    }
 130    
 131    /**
 132     * Loads the translation tables from the MO file into the cache
 133     * If caching is enabled, also loads all strings into a cache
 134     * to speed up translation lookups
 135     * 
 136     * @access private
 137     */
 138    function load_tables() {
 139      if (is_array($this->cache_translations) &&
 140        is_array($this->table_originals) &&
 141        is_array($this->table_translations))
 142        return;
 143      
 144      /* get original and translations tables */
 145      $this->STREAM->seekto($this->originals);
 146      $this->table_originals = $this->readintarray($this->total * 2);
 147      $this->STREAM->seekto($this->translations);
 148      $this->table_translations = $this->readintarray($this->total * 2);
 149      
 150      if ($this->enable_cache) {
 151        $this->cache_translations = array ();
 152        /* read all strings in the cache */
 153        for ($i = 0; $i < $this->total; $i++) {
 154          $this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
 155          $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
 156          $this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
 157          $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
 158          $this->cache_translations[$original] = $translation;
 159        }
 160      }
 161    }
 162    
 163    /**
 164     * Returns a string from the "originals" table
 165     * 
 166     * @access private
 167     * @param int num Offset number of original string
 168     * @return string Requested string if found, otherwise ''
 169     */
 170    function get_original_string($num) {
 171      $length = $this->table_originals[$num * 2 + 1];
 172      $offset = $this->table_originals[$num * 2 + 2];
 173      if (! $length)
 174        return '';
 175      $this->STREAM->seekto($offset);
 176      $data = $this->STREAM->read($length);
 177      return (string)$data;
 178    }
 179    
 180    /**
 181     * Returns a string from the "translations" table
 182     * 
 183     * @access private
 184     * @param int num Offset number of original string
 185     * @return string Requested string if found, otherwise ''
 186     */
 187    function get_translation_string($num) {
 188      $length = $this->table_translations[$num * 2 + 1];
 189      $offset = $this->table_translations[$num * 2 + 2];
 190      if (! $length)
 191        return '';
 192      $this->STREAM->seekto($offset);
 193      $data = $this->STREAM->read($length);
 194      return (string)$data;
 195    }
 196    
 197    /**
 198     * Binary search for string
 199     * 
 200     * @access private
 201     * @param string string
 202     * @param int start (internally used in recursive function)
 203     * @param int end (internally used in recursive function)
 204     * @return int string number (offset in originals table)
 205     */
 206    function find_string($string, $start = -1, $end = -1) {
 207      if (($start == -1) or ($end == -1)) {
 208        // find_string is called with only one parameter, set start end end
 209        $start = 0;
 210        $end = $this->total;
 211      }
 212      if (abs($start - $end) <= 1) {
 213        // We're done, now we either found the string, or it doesn't exist
 214        $txt = $this->get_original_string($start);
 215        if ($string == $txt)
 216          return $start;
 217        else
 218          return -1;
 219      } else if ($start > $end) {
 220        // start > end -> turn around and start over
 221        return $this->find_string($string, $end, $start);
 222      } else {
 223        // Divide table in two parts
 224        $half = (int)(($start + $end) / 2);
 225        $cmp = strcmp($string, $this->get_original_string($half));
 226        if ($cmp == 0)
 227          // string is exactly in the middle => return it
 228          return $half;
 229        else if ($cmp < 0)
 230          // The string is in the upper half
 231          return $this->find_string($string, $start, $half);
 232        else
 233          // The string is in the lower half
 234          return $this->find_string($string, $half, $end);
 235      }
 236    }
 237    
 238    /**
 239     * Translates a string
 240     * 
 241     * @access public
 242     * @param string string to be translated
 243     * @return string translated string (or original, if not found)
 244     */
 245    function translate($string) {
 246      if ($this->short_circuit)
 247        return $string;
 248      $this->load_tables();     
 249      
 250      if ($this->enable_cache) {
 251        // Caching enabled, get translated string from cache
 252        if (array_key_exists($string, $this->cache_translations))
 253          return $this->cache_translations[$string];
 254        else
 255          return $string;
 256      } else {
 257        // Caching not enabled, try to find string
 258        $num = $this->find_string($string);
 259        if ($num == -1)
 260          return $string;
 261        else
 262          return $this->get_translation_string($num);
 263      }
 264    }
 265  
 266    /**
 267     * Get possible plural forms from MO header
 268     * 
 269     * @access private
 270     * @return string plural form header
 271     */
 272    function get_plural_forms() {
 273      // lets assume message number 0 is header  
 274      // this is true, right?
 275      $this->load_tables();
 276      
 277      // cache header field for plural forms
 278      if (! is_string($this->pluralheader)) {
 279        if ($this->enable_cache) {
 280          $header = $this->cache_translations[""];
 281        } else {
 282          $header = $this->get_translation_string(0);
 283        }
 284        if (eregi("plural-forms: ([^\n]*)\n", $header, $regs))
 285          $expr = $regs[1];
 286        else
 287          $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
 288        $this->pluralheader = $expr;
 289      }
 290      return $this->pluralheader;
 291    }
 292  
 293    /**
 294     * Detects which plural form to take
 295     * 
 296     * @access private
 297     * @param n count
 298     * @return int array index of the right plural form
 299     */
 300    function select_string($n) {
 301      $string = $this->get_plural_forms();
 302      $string = str_replace('nplurals',"\$total",$string);
 303      $string = str_replace("n",$n,$string);
 304      $string = str_replace('plural',"\$plural",$string);
 305  
 306      # poEdit doesn't put any semicolons, which
 307      # results in parse error in eval
 308      $string .= ';';
 309      
 310      $total = 0;
 311      $plural = 0;
 312  
 313      eval("$string");
 314      if ($plural >= $total) $plural = $total - 1;
 315      return $plural;
 316    }
 317  
 318    /**
 319     * Plural version of gettext
 320     * 
 321     * @access public
 322     * @param string single
 323     * @param string plural
 324     * @param string number
 325     * @return translated plural form
 326     */
 327    function ngettext($single, $plural, $number) {
 328      if ($this->short_circuit) {
 329        if ($number != 1)
 330          return $plural;
 331        else
 332          return $single;
 333      }
 334  
 335      // find out the appropriate form
 336      $select = $this->select_string($number); 
 337      
 338      // this should contains all strings separated by NULLs
 339      $key = $single.chr(0).$plural;
 340      
 341      
 342      if ($this->enable_cache) {
 343        if (! array_key_exists($key, $this->cache_translations)) {
 344          return ($number != 1) ? $plural : $single;
 345        } else {
 346          $result = $this->cache_translations[$key];
 347          $list = explode(chr(0), $result);
 348          return $list[$select];
 349        }
 350      } else {
 351        $num = $this->find_string($key);
 352        if ($num == -1) {
 353          return ($number != 1) ? $plural : $single;
 354        } else {
 355          $result = $this->get_translation_string($num);
 356          $list = explode(chr(0), $result);
 357          return $list[$select];
 358        }
 359      }
 360    }
 361  
 362  }
 363  
 364  ?>


Généré le : Fri Mar 30 19:41:27 2007 par Balluche grâce à PHPXref 0.7