[ Index ] |
|
Code source de WordPress 2.1.2 |
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 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 30 19:41:27 2007 | par Balluche grâce à PHPXref 0.7 |