00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 App::import('Core', 'l10n');
00031
00032
00033
00034
00035
00036
00037
00038
00039 class I18n extends Object {
00040
00041
00042
00043
00044
00045
00046 var $l10n = null;
00047
00048
00049
00050
00051
00052
00053 var $domain = null;
00054
00055
00056
00057
00058
00059
00060 var $category = 'LC_MESSAGES';
00061
00062
00063
00064
00065
00066
00067 var $__lang = null;
00068
00069
00070
00071
00072
00073
00074 var $__domains = array();
00075
00076
00077
00078
00079
00080
00081
00082 var $__noLocale = false;
00083
00084
00085
00086
00087
00088
00089 var $__cache = false;
00090
00091
00092
00093
00094
00095
00096
00097 var $__categories = array(
00098 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME', 'LC_MESSAGES'
00099 );
00100
00101
00102
00103
00104
00105
00106 function &getInstance() {
00107 static $instance = array();
00108 if (!$instance) {
00109 $instance[0] =& new I18n();
00110 $instance[0]->l10n =& new L10n();
00111 }
00112 return $instance[0];
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 function translate($singular, $plural = null, $domain = null, $category = 6, $count = null) {
00127 $_this =& I18n::getInstance();
00128
00129 if (strpos($singular, "\r\n") !== false) {
00130 $singular = str_replace("\r\n", "\n", $singular);
00131 }
00132 if ($plural !== null && strpos($plural, "\r\n") !== false) {
00133 $plural = str_replace("\r\n", "\n", $plural);
00134 }
00135
00136 if (is_numeric($category)) {
00137 $_this->category = $_this->__categories[$category];
00138 }
00139 $language = Configure::read('Config.language');
00140
00141 if (!empty($_SESSION['Config']['language'])) {
00142 $language = $_SESSION['Config']['language'];
00143 }
00144
00145 if (($_this->__lang && $_this->__lang !== $language) || !$_this->__lang) {
00146 $lang = $_this->l10n->get($language);
00147 $_this->__lang = $lang;
00148 }
00149
00150 if (is_null($domain)) {
00151 $domain = 'default';
00152 }
00153 $_this->domain = $domain . '_' . $_this->l10n->locale;
00154
00155 if (empty($_this->__domains)) {
00156 $_this->__domains = Cache::read($_this->domain, '_cake_core_');
00157 }
00158
00159 if (!isset($_this->__domains[$_this->category][$_this->__lang][$domain])) {
00160 $_this->__bindTextDomain($domain);
00161 $_this->__cache = true;
00162 }
00163
00164 if (!isset($count)) {
00165 $plurals = 0;
00166 } elseif (!empty($_this->__domains[$_this->category][$_this->__lang][$domain]["%plural-c"]) && $_this->__noLocale === false) {
00167 $header = $_this->__domains[$_this->category][$_this->__lang][$domain]["%plural-c"];
00168 $plurals = $_this->__pluralGuess($header, $count);
00169 } else {
00170 if ($count != 1) {
00171 $plurals = 1;
00172 } else {
00173 $plurals = 0;
00174 }
00175 }
00176
00177 if (!empty($_this->__domains[$_this->category][$_this->__lang][$domain][$singular])) {
00178 if (($trans = $_this->__domains[$_this->category][$_this->__lang][$domain][$singular]) || ($plurals) && ($trans = $_this->__domains[$_this->category][$_this->__lang][$domain][$plural])) {
00179 if (is_array($trans)) {
00180 if (isset($trans[$plurals])) {
00181 $trans = $trans[$plurals];
00182 }
00183 }
00184 if (strlen($trans)) {
00185 $singular = $trans;
00186 return $singular;
00187 }
00188 }
00189 }
00190
00191 if (!empty($plurals)) {
00192 return($plural);
00193 }
00194 return($singular);
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204 function __pluralGuess($header, $n) {
00205 if (!is_string($header) || $header === "nplurals=1;plural=0;" || !isset($header[0])) {
00206 return 0;
00207 }
00208
00209 if ($header === "nplurals=2;plural=n!=1;") {
00210 return $n != 1 ? 1 : 0;
00211 } elseif ($header === "nplurals=2;plural=n>1;") {
00212 return $n > 1 ? 1 : 0;
00213 }
00214
00215 if (strpos($header, "plurals=3")) {
00216 if (strpos($header, "100!=11")) {
00217 if (strpos($header, "10<=4")) {
00218 return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
00219 } elseif (strpos($header, "100<10")) {
00220 return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
00221 }
00222 return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n != 0 ? 1 : 2);
00223 } elseif (strpos($header, "n==2")) {
00224 return $n == 1 ? 0 : ($n == 2 ? 1 : 2);
00225 } elseif (strpos($header, "n==0")) {
00226 return $n == 1 ? 0 : ($n == 0 || ($n % 100 > 0 && $n % 100 < 20) ? 1 : 2);
00227 } elseif (strpos($header, "n>=2")) {
00228 return $n == 1 ? 0 : ($n >= 2 && $n <= 4 ? 1 : 2);
00229 } elseif (strpos($header, "10>=2")) {
00230 return $n == 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
00231 }
00232 return $n % 10 == 1 ? 0 : ($n % 10 == 2 ? 1 : 2);
00233 } elseif (strpos($header, "plurals=4")) {
00234 if (strpos($header, "100==2")) {
00235 return $n % 100 == 1 ? 0 : ($n % 100 == 2 ? 1 : ($n % 100 == 3 || $n % 100 == 4 ? 2 : 3));
00236 } elseif (strpos($header, "n>=3")) {
00237 return $n == 1 ? 0 : ($n == 2 ? 1 : ($n == 0 || ($n >= 3 && $n <= 10) ? 2 : 3));
00238 } elseif (strpos($header, "100>=1")) {
00239 return $n == 1 ? 0 : ($n == 0 || ($n % 100 >= 1 && $n % 100 <= 10) ? 1 : ($n % 100 >= 11 && $n % 100 <= 20 ? 2 : 3));
00240 }
00241 } elseif (strpos($header, "plurals=5")) {
00242 return $n == 1 ? 0 : ($n == 2 ? 1 : ($n >= 3 && $n <= 6 ? 2 : ($n >= 7 && $n <= 10 ? 3 : 4)));
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251
00252 function __bindTextDomain($domain) {
00253 $this->__noLocale = true;
00254 $core = true;
00255 $merge = array();
00256 $searchPaths = Configure::read('localePaths');
00257 $plugins = Configure::listObjects('plugin');
00258
00259 if (!empty($plugins)) {
00260 $pluginPaths = Configure::read('pluginPaths');
00261
00262 foreach ($plugins as $plugin) {
00263 $plugin = Inflector::underscore($plugin);
00264 if ($plugin === $domain) {
00265 foreach ($pluginPaths as $pluginPath) {
00266 $searchPaths[] = $pluginPath . DS . $plugin . DS . 'locale';
00267 }
00268 $searchPaths = array_reverse($searchPaths);
00269 break;
00270 }
00271 }
00272 }
00273
00274 foreach ($searchPaths as $directory) {
00275 foreach ($this->l10n->languagePath as $lang) {
00276 $file = $directory . DS . $lang . DS . $this->category . DS . $domain;
00277
00278 if ($core) {
00279 $app = $directory . DS . $lang . DS . $this->category . DS . 'core';
00280 if (file_exists($fn = "$app.mo")) {
00281 $this->__loadMo($fn, $domain);
00282 $this->__noLocale = false;
00283 $merge[$this->category][$this->__lang][$domain] = $this->__domains[$this->category][$this->__lang][$domain];
00284 $core = null;
00285 } elseif (file_exists($fn = "$app.po") && ($f = fopen($fn, "r"))) {
00286 $this->__loadPo($f, $domain);
00287 $this->__noLocale = false;
00288 $merge[$this->category][$this->__lang][$domain] = $this->__domains[$this->category][$this->__lang][$domain];
00289 $core = null;
00290 }
00291 }
00292
00293 if (file_exists($fn = "$file.mo")) {
00294 $this->__loadMo($fn, $domain);
00295 $this->__noLocale = false;
00296 break 2;
00297 } elseif (file_exists($fn = "$file.po") && ($f = fopen($fn, "r"))) {
00298 $this->__loadPo($f, $domain);
00299 $this->__noLocale = false;
00300 break 2;
00301 }
00302 }
00303 }
00304
00305 if (empty($this->__domains[$this->category][$this->__lang][$domain])) {
00306 $this->__domains[$this->category][$this->__lang][$domain] = array();
00307 return($domain);
00308 }
00309
00310 if ($head = $this->__domains[$this->category][$this->__lang][$domain][""]) {
00311 foreach (explode("\n", $head) as $line) {
00312 $header = strtok($line,":");
00313 $line = trim(strtok("\n"));
00314 $this->__domains[$this->category][$this->__lang][$domain]["%po-header"][strtolower($header)] = $line;
00315 }
00316
00317 if (isset($this->__domains[$this->category][$this->__lang][$domain]["%po-header"]["plural-forms"])) {
00318 $switch = preg_replace("/(?:[() {}\\[\\]^\\s*\\]]+)/", "", $this->__domains[$this->category][$this->__lang][$domain]["%po-header"]["plural-forms"]);
00319 $this->__domains[$this->category][$this->__lang][$domain]["%plural-c"] = $switch;
00320 unset($this->__domains[$this->category][$this->__lang][$domain]["%po-header"]);
00321 }
00322 $this->__domains = Set::pushDiff($this->__domains, $merge);
00323
00324 if (isset($this->__domains[$this->category][$this->__lang][$domain][null])) {
00325 unset($this->__domains[$this->category][$this->__lang][$domain][null]);
00326 }
00327 }
00328 return($domain);
00329 }
00330
00331
00332
00333
00334
00335
00336
00337 function __loadMo($file, $domain) {
00338 $data = file_get_contents($file);
00339
00340 if ($data) {
00341 $header = substr($data, 0, 20);
00342 $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
00343 extract($header);
00344
00345 if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && $version == 0) {
00346 for ($n = 0; $n < $count; $n++) {
00347 $r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
00348 $msgid = substr($data, $r["offs"], $r["len"]);
00349 unset($msgid_plural);
00350
00351 if (strpos($msgid, "\000")) {
00352 list($msgid, $msgid_plural) = explode("\000", $msgid);
00353 }
00354 $r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8));
00355 $msgstr = substr($data, $r["offs"], $r["len"]);
00356
00357 if (strpos($msgstr, "\000")) {
00358 $msgstr = explode("\000", $msgstr);
00359 }
00360 $this->__domains[$this->category][$this->__lang][$domain][$msgid] = $msgstr;
00361
00362 if (isset($msgid_plural)) {
00363 $this->__domains[$this->category][$this->__lang][$domain][$msgid_plural] =& $this->__domains[$this->category][$this->__lang][$domain][$msgid];
00364 }
00365 }
00366 }
00367 }
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377 function __loadPo($file, $domain) {
00378 $type = 0;
00379 $translations = array();
00380 $translationKey = "";
00381 $plural = 0;
00382 $header = "";
00383
00384 do {
00385 $line = trim(fgets($file, 1024));
00386 if ($line == "" || $line[0] == "#") {
00387 continue;
00388 }
00389 if (preg_match("/msgid[[:space:]]+\"(.+)\"$/i", $line, $regs)) {
00390 $type = 1;
00391 $translationKey = stripcslashes($regs[1]);
00392 } elseif (preg_match("/msgid[[:space:]]+\"\"$/i", $line, $regs)) {
00393 $type = 2;
00394 $translationKey = "";
00395 } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && ($type == 1 || $type == 2 || $type == 3)) {
00396 $type = 3;
00397 $translationKey .= stripcslashes($regs[1]);
00398 } elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
00399 $translations[$translationKey] = stripcslashes($regs[1]);
00400 $type = 4;
00401 } elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
00402 $type = 4;
00403 $translations[$translationKey] = "";
00404 } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 4 && $translationKey) {
00405 $translations[$translationKey] .= stripcslashes($regs[1]);
00406 } elseif (preg_match("/msgid_plural[[:space:]]+\".*\"$/i", $line, $regs)) {
00407 $type = 6;
00408 } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 6 && $translationKey) {
00409 $type = 6;
00410 } elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
00411 $plural = $regs[1];
00412 $translations[$translationKey][$plural] = stripcslashes($regs[2]);
00413 $type = 7;
00414 } elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
00415 $plural = $regs[1];
00416 $translations[$translationKey][$plural] = "";
00417 $type = 7;
00418 } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 7 && $translationKey) {
00419 $translations[$translationKey][$plural] .= stripcslashes($regs[1]);
00420 } elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && $type == 2 && !$translationKey) {
00421 $header .= stripcslashes($regs[1]);
00422 $type = 5;
00423 } elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && !$translationKey) {
00424 $header = "";
00425 $type = 5;
00426 } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 5) {
00427 $header .= stripcslashes($regs[1]);
00428 } else {
00429 unset($translations[$translationKey]);
00430 $type = 0;
00431 $translationKey = "";
00432 $plural = 0;
00433 }
00434 } while (!feof($file));
00435 fclose($file);
00436 $merge[""] = $header;
00437 return $this->__domains[$this->category][$this->__lang][$domain] = array_merge($merge ,$translations);
00438 }
00439
00440
00441
00442
00443
00444
00445 function __destruct() {
00446 if ($this->__cache) {
00447 Cache::write($this->domain, array_filter($this->__domains), '_cake_core_');
00448 }
00449 }
00450 }
00451 ?>