Make WordPress Core

source: trunk/wp-includes/gettext.php @ 1608

Last change on this file since 1608 was 1080, checked in by rboren, 21 years ago

gettext l10n.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 6.3 KB
Line 
1<?php
2/*
3   Copyright (c) 2003 Danilo Segan <[email protected]>.
4
5   This file is part of PHP-gettext.
6
7   PHP-gettext is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   PHP-gettext is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with PHP-gettext; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21*/
22 
23
24
25  // For start, we only want to read the MO files
26
27class gettext_reader {
28//public:
29  var $error = 0; // public variable that holds error code (0 if no error)
30//private:
31  var $BYTEORDER = 0;
32  var $STREAM = NULL;
33  var $short_circuit = false;
34
35  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) {
50    // If there isn't a StreamReader, turn on short circuit mode.
51    if (! $Reader) {
52        $this->short_circuit = true;
53        return;
54    }
55
56    $MAGIC1 = (int)0x950412de;
57    $MAGIC2 = (int)0xde120495;
58
59
60    $this->STREAM = $Reader;
61    $magic = $this->readint();
62    if ($magic == $MAGIC1) {
63      $this->BYTEORDER = 0;
64    } elseif ($magic == $MAGIC2) {
65      $this->BYTEORDER = 1;
66    } else {
67      $this->error = 1; // not MO file
68      return false;
69    }
70
71    // FIXME: Do we care about revision? We should.
72    $revision = $this->readint();
73
74    $total = $this->readint();
75    $originals = $this->readint();
76    $translations = $this->readint();
77
78    $this->total = $total;
79    $this->originals = $originals;
80    $this->translations = $translations;
81
82  }
83
84  function load_tables($translations=false) {
85    // if tables are loaded do not load them again
86    if (!is_array($this->ORIGINALS)) {
87      $this->ORIGINALS = array();
88      $this->STREAM->seekto($this->originals);
89      for ($i=0; $i<$this->total; $i++) {
90        $len = $this->readint();
91        $ofs = $this->readint();
92        $this->ORIGINALS[] = array($len,$ofs);
93      }
94    }
95
96    // similar for translations
97    if ($translations and !is_array($this->TRANSLATIONS)) {
98      $this->TRANSLATIONS = array();
99      $this->STREAM->seekto($this->translations);
100      for ($i=0; $i<$this->total; $i++) {
101        $len = $this->readint();
102        $ofs = $this->readint();
103        $this->TRANSLATIONS[] = array($len,$ofs);
104      }
105    }
106
107  }
108
109  function get_string_number($num) {
110    // get a string with particular number
111    // TODO: Add simple hashing [check array, add if not already there]
112    $this->load_tables();
113    $meta = $this->ORIGINALS[$num];
114    $length = $meta[0];
115    $offset = $meta[1];
116    $this->STREAM->seekto($offset);
117    $data = $this->STREAM->read($length);
118    return (string)$data;
119  }
120
121  function get_translation_number($num) {
122    // get a string with particular number
123    // TODO: Add simple hashing [check array, add if not already there]
124    $this->load_tables(true);
125    $meta = $this->TRANSLATIONS[$num];
126    $length = $meta[0];
127    $offset = $meta[1];
128    $this->STREAM->seekto($offset);
129    $data = $this->STREAM->read($length);
130    return (string)$data;
131  }
132 
133  // binary search for string
134  function find_string($string, $start,$end) {
135    //print "start: $start, end: $end\n";
136    if (abs($start-$end)<=1) {
137      // we're done, if it's not it, bye bye
138      $txt = $this->get_string_number($start);
139      if ($string == $txt)
140        return $start;
141      else
142        return -1;
143    } elseif ($start>$end) {
144      return $this->find_string($string,$end,$start);
145    }  else {
146      $half = (int)(($start+$end)/2);
147      $tst = $this->get_string_number($half);
148      $cmp = strcmp($string,$tst);
149      if ($cmp == 0) 
150        return $half;
151      elseif ($cmp<0) 
152        return $this->find_string($string,$start,$half);
153      else
154        return $this->find_string($string,$half,$end);
155    }
156  }
157
158  function translate($string) {
159    if ($this->short_circuit) {
160        return $string;
161    }
162
163    $num = $this->find_string($string, 0, $this->total);
164    if ($num == -1)
165      return $string;
166    else 
167      return $this->get_translation_number($num);
168  }
169
170  function get_plural_forms() {
171    // lets assume message number 0 is header
172    // this is true, right?
173
174    // cache header field for plural forms
175    if (is_string($this->pluralheader)) 
176      return $this->pluralheader;
177    else {
178      $header = $this->get_translation_number(0);
179
180      if (eregi("plural-forms: (.*)\n",$header,$regs)) {
181        $expr = $regs[1];
182      } else {
183        $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
184      }
185      $this->pluralheader = $expr;
186      return $expr;
187    }
188  }
189
190  function select_string($n) {
191    $string = $this->get_plural_forms();
192    $string = str_replace('nplurals',"\$total",$string);
193    $string = str_replace("n",$n,$string);
194    $string = str_replace('plural',"\$plural",$string);
195
196    $total = 0;
197    $plural = 0;
198
199    eval("$string");
200    if ($plural>=$total) $plural = 0;
201    return $plural;
202  }
203
204  function ngettext($single, $plural, $number) {
205    if ($this->short_circuit) {
206      if ($number != 1) return $plural;
207      else return $single;
208    }
209
210    // find out the appropriate form
211    $select = $this->select_string($number); 
212   
213
214    // this should contains all strings separated by NULLs
215    $result = $this->find_string($single.chr(0).$plural,0,$this->total);
216    if ($result == -1) {
217      if ($number != 1) return $plural;
218      else return $single;
219    } else {
220      $result = $this->get_translation_number($result);
221   
222      // lets try to parse all the NUL staff
223      //$result = "proba0".chr(0)."proba1".chr(0)."proba2";
224      $list = explode (chr(0), $result);
225      return $list[$select];
226    }
227  }
228
229}
230
231
232?>
Note: See TracBrowser for help on using the repository browser.