Source for file gettext.class.php

Documentation is available at gettext.class.php

  1. <?php
  2.  
  3. /**
  4.  * Copyright (c) 2003 Danilo Segan <[email protected]>.
  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.  * @copyright &copy; 2004-2006 The SquirrelMail Project Team
  23.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  24.  * @version $Id: gettext.class.php,v 1.5 2006/07/15 12:00:44 tokul Exp $
  25.  * @package squirrelmail
  26.  * @subpackage i18n
  27.  */
  28.  
  29. /**
  30.  * Class that uses parsed translation input objects
  31.  * @package squirrelmail
  32.  * @subpackage i18n
  33.  */
  34. class gettext_reader {
  35.     /**
  36.      * holds error code (0 if no error)
  37.      * @var integer 
  38.      * @access public
  39.      */
  40.     var $error = 0;
  41.     /**
  42.      * specifies the byte order: 0 low endian, 1 big endian
  43.      * @var integer 
  44.      * @access private
  45.      */
  46.     var $BYTEORDER 0;
  47.     /**
  48.      * input object data
  49.      * @var object 
  50.      * @access private
  51.      */
  52.     var $STREAM NULL;
  53.  
  54.     /**
  55.      *
  56.      */
  57.     function readint({
  58.         // Reads 4 byte value from $FD and puts it in int
  59.         // $BYTEORDER specifies the byte order: 0 low endian, 1 big endian
  60.         for ($i=0$i<4$i++{
  61.             $byte[$i]=ord($this->STREAM->read(1));
  62.         }
  63.         //print sprintf("pos: %d\n",$this->STREAM->currentpos());
  64.         if ($this->BYTEORDER == 0)
  65.             return (int)(($byte[0]($byte[1]<<8($byte[2]<<16($byte[3]<<24));
  66.         else
  67.             return (int)(($byte[3]($byte[2]<<8($byte[1]<<16($byte[0]<<24));
  68.     }
  69.  
  70.     /**
  71.      * constructor that requires StreamReader object
  72.      * @param object $Reader 
  73.      * @return boolean false, if some error with stream
  74.      */
  75.     function gettext_reader($Reader{
  76.         $MAGIC1 = (int) ((222(18<<8(4<<16(149<<24));
  77.         $MAGIC2 = (int) ((149(4<<8(18<<16(222<<24));
  78.  
  79.         $this->STREAM $Reader;
  80.         if ($this->STREAM->error>0{
  81.             $this->error=1;
  82.             return false;
  83.         }
  84.         $magic $this->readint();
  85.         if ($magic == $MAGIC1{
  86.             $this->BYTEORDER 0;
  87.         elseif ($magic == $MAGIC2{
  88.             $this->BYTEORDER 1;
  89.         else {
  90.             $this->error = 1// not MO file
  91.             return false;
  92.         }
  93.  
  94.         // FIXME: Do we care about revision? We should.
  95.         $revision $this->readint();
  96.  
  97.         $total $this->readint();
  98.         $originals $this->readint();
  99.         $translations $this->readint();
  100.  
  101.         $this->total $total;
  102.         $this->originals $originals;
  103.         $this->translations $translations;
  104.  
  105.         // Here we store already found translations
  106.         $this->_HASHED array();
  107.     }
  108.  
  109.     /**
  110.      * @param boolean $translations do translation have to be loaded
  111.      */
  112.     function load_tables($translations=false{
  113.         // if tables are loaded do not load them again
  114.         if (!isset($this->ORIGINALS)) {
  115.             $this->ORIGINALS array();
  116.             $this->STREAM->seekto($this->originals);
  117.             for ($i=0$i<$this->total$i++{
  118.                 $len $this->readint();
  119.                 $ofs $this->readint();
  120.                 $this->ORIGINALS[array($len,$ofs);
  121.             }
  122.         }
  123.  
  124.         // similar for translations
  125.         if ($translations and !isset($this->TRANSLATIONS)) {
  126.             $this->TRANSLATIONS array();
  127.             $this->STREAM->seekto($this->translations);
  128.             for ($i=0$i<$this->total$i++{
  129.                 $len $this->readint();
  130.                 $ofs $this->readint();
  131.                 $this->TRANSLATIONS[array($len,$ofs);
  132.             }
  133.         }
  134.     }
  135.  
  136.     /**
  137.      * get a string with particular number
  138.      * @param integer $num 
  139.      * @return string untranslated string
  140.      */
  141.     function get_string_number($num{
  142.         // TODO: Add simple hashing [check array, add if not already there]
  143.         $this->load_tables();
  144.         $meta $this->ORIGINALS[$num];
  145.         $length $meta[0];
  146.         $offset $meta[1];
  147.         $this->STREAM->seekto($offset);
  148.         $data $this->STREAM->read($length);
  149.         return (string)$data;
  150.     }
  151.  
  152.     /**
  153.      * get translated string with particular number
  154.      * @param integer $num 
  155.      * @return string translated string
  156.      */
  157.     function get_translation_number($num{
  158.         // get a string with particular number
  159.         // TODO: Add simple hashing [check array, add if not already there]
  160.         $this->load_tables(true);
  161.         $meta $this->TRANSLATIONS[$num];
  162.         $length $meta[0];
  163.         $offset $meta[1];
  164.         $this->STREAM->seekto($offset);
  165.         $data $this->STREAM->read($length);
  166.         return (string)$data;
  167.     }
  168.  
  169.     /**
  170.      * binary search for string
  171.      * @param string $string 
  172.      * @param integer $start 
  173.      * @param integer $end 
  174.      */
  175.     function find_string($string$start,$end{
  176.         //print "start: $start, end: $end\n";
  177.         // Simple hashing to improve speed
  178.         if (isset($this->_HASHED[$string])) return $this->_HASHED[$string];
  179.  
  180.         if (abs($start-$end)<=1{
  181.             // we're done, if it's not it, bye bye
  182.             $txt $this->get_string_number($start);
  183.             if ($string == $txt{
  184.                 $this->_HASHED[$string$start;
  185.                 return $start;
  186.             else
  187.                 return -1;
  188.         elseif ($start>$end{
  189.             return $this->find_string($string,$end,$start);
  190.         }  else {
  191.             $half = (int)(($start+$end)/2);
  192.             $tst $this->get_string_number($half);
  193.             $cmp strcmp($string,$tst);
  194.             if ($cmp == 0{
  195.                 $this->_HASHED[$string$half;
  196.                 return $half;
  197.             elseif ($cmp<0)
  198.                 return $this->find_string($string,$start,$half);
  199.             else
  200.                 return $this->find_string($string,$half,$end);
  201.         }
  202.     }
  203.  
  204.     /**
  205.      * translate string
  206.      * @param string $string English string
  207.      * @return string translated string
  208.      */
  209.     function translate($string{
  210.         if ($this->error > 0return $string;
  211.         $num $this->find_string($string0$this->total);
  212.         if ($num == -1)
  213.             return $string;
  214.         else
  215.             return $this->get_translation_number($num);
  216.     }
  217.  
  218.     /**
  219.      * extract plural forms header
  220.      * @return string plural-forms header string
  221.      */
  222.     function get_plural_forms({
  223.         // lets assume message number 0 is header
  224.         // this is true, right?
  225.  
  226.         // cache header field for plural forms
  227.         if (isset($this->pluralheader&& is_string($this->pluralheader))
  228.             return $this->pluralheader;
  229.         else {
  230.             $header $this->get_translation_number(0);
  231.  
  232.             if (eregi("plural-forms: (.*)\n",$header,$regs)) {
  233.                 $expr $regs[1];
  234.             else {
  235.                 $expr "nplurals=2; plural=n == 1 ? 0 : 1;";
  236.             }
  237.             $this->pluralheader $expr;
  238.             return $expr;
  239.         }
  240.     }
  241.  
  242.     /**
  243.      * find out the appropriate form number
  244.      * @param integer $n count
  245.      * @return integer 
  246.      */
  247.     function select_string($n{
  248.         $string $this->get_plural_forms();
  249.         $string str_replace('nplurals',"\$total",$string);
  250.         $string str_replace("n",$n,$string);
  251.         $string str_replace('plural',"\$plural",$string);
  252.  
  253.         $total 0;
  254.         $plural 0;
  255.  
  256.         eval("$string");
  257.         if ($plural>=$total$plural 0;
  258.         return $plural;
  259.     }
  260.  
  261.     /**
  262.      * translate string with singular/plural forms
  263.      * @param string $single English singural form of translation
  264.      * @param string $plural English plural form of translation
  265.      * @param string $number count
  266.      * @return string 
  267.      */
  268.     function ngettext($single$plural$number{
  269.         if ($this->error > 0{
  270.             $result=-1;
  271.         else {
  272.             // find out the appropriate form
  273.             $select $this->select_string($number);
  274.  
  275.             // this should contains all strings separated by NULLs
  276.             $result $this->find_string($single.chr(0).$plural,0,$this->total);
  277.         }
  278.         if ($result == -1{
  279.             if ($number != 1return $plural;
  280.             else return $single;
  281.         else {
  282.             $result $this->get_translation_number($result);
  283.  
  284.             // lets try to parse all the NUL staff
  285.             //$result = "proba0".chr(0)."proba1".chr(0)."proba2";
  286.             $list explode (chr(0)$result);
  287.             return $list[$select];
  288.         }
  289.     }
  290. }

Documentation generated on Sat, 07 Oct 2006 16:11:25 +0300 by phpDocumentor 1.3.0RC6