1<?php 2if(!defined("LCE_FUNCTIONS")) 3{ 4 define("LCE_FUNCTIONS", 1); 5 include("base.php"); 6 include("lce_config.php"); 7 8 // Unknown line class 9 define("LCE_UNKNOWN", 0); 10 // pure whitespace 11 define("LCE_WS", 1); 12 // a unqualified comment 13 define("LCE_COMMENT", 2); 14 // a user/translator comment 15 define("LCE_COMMENT_USER", 3); 16 // a tool-generated comment 17 define("LCE_COMMENT_TOOL", 4); 18 // A line containing a MSGID 19 define("LCE_MSGID", 5); 20 // A line containing a MSGSTR 21 define("LCE_MSGSTR", 6); 22 // A quoted text string 23 define("LCE_TEXT", 7); 24 25 define("STATE_ABORT", 0); 26 define("STATE_OK", 1); 27 define("STATE_LOOP", 2); 28 29 class POEntryAD extends AD 30 { 31 function validate($value) 32 { 33 // print '"<pre>' . $value . '"<br></pre>'; 34 $result = AD::validate(trim($value)); 35 //return $result; 36 if($result[0]) 37 { 38 $lines = explode("\n", ereg_replace("\r", "", $result[1])); 39 //$lines = explode("\n", $result[1]); 40 /* print "<pre>"; 41 print_r($lines); 42 print "</pre>";*/ 43 $res = array(); 44 for($i = 0; $i < count($lines); $i++) 45 { 46 if(trim($lines[$i]) != "") 47 $res[] = $lines[$i]; 48 } 49 $result[1] = join("\n", $res); 50 /* print "<pre>"; 51 print_r($result[1]); 52 print "</pre>";*/ 53 54 $result[0] = $this->checkQuotation($result[1]); 55 } 56 return $result; 57 } 58 59 function checkQuotation($str) 60 { 61 $rex = "\\\\n|\\\\t|\\\\r|\\\\\""; 62 $str = ereg_replace($rex, "", $str); 63 $str = ereg_replace("\\\\\\\\", "", $str); 64 return !(strstr($str, "\"") 65 || strstr($str, "\\")); 66 } 67 } 68 69 70 class CommentAD extends AD 71 { 72 var $prefix; 73 function CommentAD( 74 $name, // the name of the variable 75 $not_null = 0, 76 $type = "", // as returned by gettype 77 $prefix = "# ") 78 { 79 $this->prefix = $prefix; 80 AD::AD($name, $not_null, $type); 81 } 82 83 function validate($value) 84 { 85 $res = AD::validate($value); 86 return $res; 87 if($res[0] && $res[1] != "") 88 { 89 $mod_lines = array(); 90 $lines = explode("\n", $res[1]); 91 92 for($i = 0; $i < count($lines); $i++) 93 { 94 $line = $lines[$i]; 95 if(substr($line, 0, 1) != "#") 96 $line = $this->prefix . $line; 97 $mod_lines[] = $line; 98 } 99 $res[1] = join("\n", $mod_lines); 100 } 101 return $res; 102 } 103 } 104 105 class POEntry extends HtmlValidator 106 { 107 var $msgid; 108 var $msgstr; 109 var $user_comment; 110 var $sys_comment; 111 var $unk_comment; 112 113 var $msgid_lc = 0; 114 var $msgstr_lc = 0; 115 var $user_comment_lc = 0; 116 var $sys_comment_lc = 0; 117 var $unk_comment_lc = 0; 118 119 function POEntry() 120 { 121 $this->atts = array( 122 new AD("msgid"), 123 new POEntryAD("msgstr", REQUIRED_ATTRIBUTE), 124 new CommentAD("user_comment"), 125 new POEntryAD("sys_comment"), 126 new POEntryAD("unk_comment"), 127 new AD("msgid_lc", NOT_REQUIRED_ATTRIBUTE, 0), 128 new AD("msgstr_lc", NOT_REQUIRED_ATTRIBUTE, 0), 129 new AD("user_comment_lc", NOT_REQUIRED_ATTRIBUTE, 0), 130 new AD("sys_comment_lc", NOT_REQUIRED_ATTRIBUTE, 0), 131 new AD("unk_comment_lc", NOT_REQUIRED_ATTRIBUTE, 0) 132 ); 133 } 134 135 function lineCount($entry) 136 { 137 $lc = count(explode("\n", $entry)); 138 return $lc; 139 } 140 141 function serializeToVars($prefix) 142 { 143 $this->user_comment_lc = $this->lineCount($this->user_comment); 144 $this->unk_comment_lc = $this->lineCount($this->sys_comment); 145 $this->sys_comment_lc = $this->lineCount($this->unk_comment); 146 $this->msgid_lc = $this->lineCount($this->msgid); 147 $this->msgstr_lc = $this->lineCount($this->msgstr); 148 return HtmlValidator::serializeToVars($prefix); 149 } 150 151 function write() 152 { 153 $content = ""; 154 $content .= $this->user_comment . "\n"; 155 $content .= $this->unk_comment . "\n"; 156 $content .= $this->sys_comment . "\n"; 157 $content .= "msgid \"" . $this->msgid . "\"\n"; 158 $content .= 'msgstr "' . join("\"\n\"", explode("\n", $this->msgstr)) . "\"" . "\n\n"; 159 return $content; 160 } 161 } 162 163 class POReader extends HTMLValidator 164 { 165 var $msgid; 166 var $msgstr; 167 var $user_comment; 168 var $sys_comment; 169 var $unk_comment; 170 var $state; 171 var $ignore_ws; 172 var $po_entries; 173 var $poe_num; 174 var $filename; 175 var $domain; 176 177 function gettext($msgid) 178 { 179 if(isset($this->po_entries[$msgid])) 180 { 181 $po = $this->po_entries[$msgid]; 182 return StripCSlashes(join("", explode("\n", $po->msgstr))); 183 //return $po->msgstr; 184 } 185 return $msgid; 186 } 187 188 189 function parseFromVars($prefix) 190 { 191 $res = HtmlValidator::parseFromVars($prefix); 192 if($res[0]) 193 { 194 $poe_res = true; 195 $this->po_entries = array(); 196 for($i = 0; $i < $this->poe_num; $i++) 197 { 198 $poe = new POEntry; 199 $res = $poe->parseFromVars($prefix . "_POE$i"); 200 if($res[0]) 201 { 202 $msgid = $prefix . "_POE" . $i . "_MSGID"; 203 $msgid = $$msgid; 204 $this->po_entries[$prefix . "_POE" . $i . "_MSGID"] = $res[1]; 205 } 206 else 207 $poe_res = false; 208 } 209 } 210 if(!$poe_res) 211 $GLOBALS[$prefix . "_ERR"] = 1; 212 return array($poe_res, $this); 213 } 214 215 function serializeToVars($prefix) 216 { 217 HtmlValidator::serializeToVars($prefix); 218 reset($this->po_entries); 219 $i = 0; 220 while($poe = each($this->po_entries)) 221 { 222 $poe = $poe[1]; 223 $poe->serializeToVars($prefix . "_POE$i"); 224 $i++; 225 } 226 } 227 228 229 function POReader($domain, $filename) 230 { 231 $this->domain = $domain; 232 $this->filename = $filename; 233 $this->ignore_ws = true; 234 $this->po_entries = array(); 235 $this->atts = array( 236 new AD("domain", REQUIRED_ATTRIBUTE), 237 new AD("filename", REQUIRED_ATTRIBUTE), 238 new AD("poe_num", REQUIRED_ATTRIBUTE, 0) 239 ); 240 } 241 242 243 function read() 244 { 245 if($fh = fopen($this->filename, "r")) 246 { 247 $this->lines = array(); 248 while (!feof ($fh)) 249 { 250 $line = fgets($fh, 4096); 251 $this->lines[] = $line; 252 } 253 fclose($fh); 254 } 255 $this->createPOEntries(); 256 $this->poe_num = count($this->po_entries); 257 } 258 259 function write($save="yes") 260 { 261 reset($this->po_entries); 262 $content = ""; 263 while($poe = each($this->po_entries)) 264 { 265 $poe = $poe[1]; 266 $content .= $poe->write(); 267 } 268 269 if(($fh = fopen($this->filename, "w")) 270 && $save == "yes") 271 { 272 fwrite($fh, $content); 273 } 274 return $content; 275 } 276 277 function isComment($class) 278 { 279 if($class == LCE_COMMENT || $class == LCE_COMMENT_USER || $class == LCE_COMMENT_TOOL) 280 return true; 281 return false; 282 } 283 284 function comment($line, $class) 285 { 286 if($this->isComment($class)) 287 { 288 if($class == LCE_COMMENT_USER) 289 $this->user_comment .= $line; 290 else if($class == LCE_COMMENT_TOOL) 291 $this->sys_comment .= $line; 292 else 293 $this->unk_comment .= $line; 294 return STATE_OK; 295 } 296 if($class == LCE_MSGID) 297 { 298 $this->state = "msgid"; 299 return STATE_LOOP; 300 } 301 return STATE_ABORT; 302 } 303 304 function msgid($line, $class) 305 { 306 if($class == LCE_MSGID || $class == LCE_TEXT) 307 { 308 $line = $this->stripLine($line, LCE_MSGID); 309 $this->msgid .= $line; 310 return STATE_OK; 311 } 312 if($class == LCE_MSGSTR) 313 { 314 $this->state = "msgstr"; 315 return STATE_LOOP; 316 } 317 return STATE_ABORT; 318 } 319 320 function msgstr($line, $class) 321 { 322 if($class == LCE_MSGSTR || $class == LCE_TEXT) 323 { 324 $line = $this->stripLine($line, $class); 325 $this->msgstr .= $line; 326 return STATE_OK; 327 } 328 // We have a different state, so we have to create a POEntry 329 $poe = new POEntry; 330 $poe->user_comment = trim($this->user_comment); 331 $poe->sys_comment = trim($this->sys_comment); 332 $poe->unk_comment = trim($this->unk_comment); 333 $poe->msgid = trim($this->msgid); 334 $poe->msgstr = trim($this->msgstr); 335 $this->po_entries[trim($this->msgid)] = $poe; 336 $this->state = "start"; 337 return STATE_LOOP; 338 } 339 340 function start($line, $class) 341 { 342 $this->user_comment = ""; 343 $this->sys_comment = ""; 344 $this->unk_comment = ""; 345 $this->msgid = ""; 346 $this->msgstr = ""; 347 if($this->isComment($class)) 348 { 349 $this->state = "comment"; 350 return STATE_LOOP; 351 } 352 if($class == LCE_MSGID) 353 { 354 $this->state = "msgid"; 355 return STATE_LOOP; 356 } 357 return STATE_OK; 358 } 359 360 function createPOEntries() 361 { 362 $this->msgid = ""; 363 $this->msgstr = ""; 364 $this->user_comment = ""; 365 $this->sys_comment = ""; 366 $this->state = "start"; 367 368 reset($this->lines); 369 for($i = 0; $i < count($this->lines); $i++) 370 { 371 $line = $this->lines[$i]; 372 $class = $this->classifyLine($line); 373 if($class != LCE_WS || !$this->ignore_ws) 374 { 375 $state_ret = STATE_LOOP; 376 while($state_ret == STATE_LOOP) 377 { 378 $state = $this->state; 379 //print "$this->state $class:$line <br>"; 380 $state_ret = $this->$state($line, $class); 381 } 382 //print "state_ret = $state_ret <br>"; 383 } 384 if($state_ret == STATE_ABORT) 385 break; 386 } 387 // Get the last entry 388 if($state_ret != STATE_ABORT) 389 { 390 $this->msgstr("", LCE_UNKNOWN); 391 } 392 } 393 394 function stripLine($line, $class) 395 { 396 switch($class) 397 { 398 case LCE_TEXT: 399 ereg('^"(.*)"', $line, $regs); 400 $line = $regs[1] . "\n"; 401 break; 402 case LCE_MSGID: 403 if(substr($line, strlen("msgid")) == "msgid") 404 { 405 $line = substr($line, strlen("msgid") + 1); 406 } 407 ereg('"(.*)"', $line, $regs); 408 $line = $regs[1]; 409 break; 410 case LCE_MSGSTR: 411 // TODO: Check if ^ can be removed 412 $line = substr($line, strlen("msgstr") + 1); 413 ereg('^"(.*)"', $line, $regs); 414 $line = $regs[1] . "\n"; 415 break; 416 417 } 418 return $line; 419 } 420 421 function printClassification() 422 { 423 reset($this->lines); 424 for($i = 0; $i < count($this->lines); $i++) 425 { 426 $line = $this->lines[$i]; 427 $class = $this->classifyLine($line); 428 print "#$i: $class $line<br>"; 429 } 430 } 431 432 function classifyLine($line) 433 { 434 if(ereg("^[ \n\r\t]*$", $line)) 435 return LCE_WS; 436 if(ereg("^#.*\$", $line)) 437 { 438 if(ereg("^[,:-~].*", substr($line, 1))) 439 { 440 return LCE_COMMENT_TOOL; 441 } 442 if(ereg("^[ \n\r\t].*", substr($line, 1))) 443 { 444 return LCE_COMMENT_USER; 445 } 446 return LCE_COMMENT; 447 } 448 if(ereg("^msgid (.*)\$", $line, $regs)) 449 { 450 $line = $regs[1]; 451 if($this->classifyLine($line) == LCE_TEXT) 452 return LCE_MSGID; 453 } 454 if(ereg("^msgstr (.*)\$", $line, $regs)) 455 { 456 $line = $regs[1]; 457 if($this->classifyLine($line) == LCE_TEXT) 458 return LCE_MSGSTR; 459 } 460 if(ereg('^".*"', $line)) 461 { 462 // TODO: Check correct escapes 463 return LCE_TEXT; 464 } 465 466 return LCE_UNKNOWN; 467 } 468 } 469 470 471 function getTextDomains($lines) 472 { 473 $default_domain = ""; 474 $domains = array(); 475 while($gl = each($GLOBALS)) 476 { 477 $gname = $gl[0]; 478 global $$gname; 479 } 480 for($i = 0; $i < count($lines); $i++) 481 { 482 if(ereg("bindtextdomain\(([^,]+),([^\)]+)\)", $lines[$i], $regs)) 483 { 484 //print "Line:" . $lines[$i] . " <br>"; 485 $name = $regs[1]; 486 $ev = "\$directory = ". $regs[2] . ";"; 487 print $ev; 488 eval($ev); 489 $domains[] = array($name, $directory); 490 } 491 if(ereg("textdomain\(([^\)]+)\)", $lines[$i], $regs)) 492 $default_domain = $regs[1]; 493 } 494 return array($default_domain, $domains); 495 } 496 497 498 class PORManager extends HtmlValidator 499 { 500 var $por_a; 501 502 function PORManager() 503 { 504 $this->por_a = array(); 505 } 506 507 function addPOReader($d_name, &$por) 508 { 509 $this->por_a[$d_name] = &$por; 510 } 511 512 function &getPOReader($domain) 513 { 514 return $this->por_a[$domain]; 515 } 516 517 function getDomainNames() 518 { 519 return array_keys($this->por_a); 520 } 521 } 522 523 function &loadPORManager() 524 { 525 global $LCE_PORMAN; 526 if(!isset($LCE_PORMAN)) 527 { 528 $LCE_PORMAN = new PORManager(); 529 } 530 return $LCE_PORMAN; 531 } 532 533 534 // More or less intelligent filename joining 535 // As available in PYTHONs os.path 536 function fileJoin() 537 { 538 $numargs = func_num_args(); 539 $args = func_get_args(); 540 for($i = 0; $i < $numargs - 1; $i++) 541 { 542 if(substr($args[$i], -1) != "/") 543 $args[$i] = $args[$i] . "/"; 544 if($i > 0) 545 { 546 if(substr($args[$i],0 , 1) == "/") 547 $args[$i] = substr($args[$i], 1); 548 } 549 550 } 551 return join("", $args); 552 } 553 554 if(defined("LCE_TESTSERVER")) 555 { 556 557 function lce_bindtextdomain($d_name, $d_path) 558 { 559 global $LANG, $LC_MESSAGES, $LC_ALL, $LCE_LANG; 560 global $LCE_ERR; 561 global $LCE_PO_SUFFIX; 562 global $LCE_MANAGER; 563 564 $path_orig = $d_path; 565 // This is not complete and reflects 566 // my not very far going understanding of the 567 // different $LC_x thingies. 568 if(isset($LC_MESSAGES)) 569 { 570 //print "LC_MESSAGES<br>"; 571 $lang_suffix = $LC_MESSAGES; 572 } 573 else if(isset($LC_ALL)) 574 { 575 //print "LC_ALL<br>"; 576 $lang_suffix = $LC_ALL; 577 } 578 else if(isset($LANG)) 579 { 580 //print "LANG<br>"; 581 $lang_suffix = $LANG; 582 } 583 else 584 { 585 //print "LCE_LANG<br>"; 586 $lang_suffix = $LCE_LANG; 587 } 588 589 //print "LangSuffix: $lang_suffix \n"; 590 //print "D_Path: " . fileJoin($d_path, $lang_suffix, "LC_MESSAGES", $d_name . $LCE_PO_SUFFIX) . "<br>"; 591 // First try: the whole lang_suffix 592 593 if(file_exists(fileJoin($d_path, $lang_suffix, "LC_MESSAGES", $d_name . $LCE_PO_SUFFIX))) 594 $d_path = fileJoin($d_path, $lang_suffix, "LC_MESSAGES", $d_name . $LCE_PO_SUFFIX); 595 else 596 { 597 $lang_suffix = substr($lang_suffix, 0, 2); 598 if(file_exists(fileJoin($d_path, $lang_suffix, "LC_MESSAGES", $d_name. $LCE_PO_SUFFIX))) 599 $d_path = fileJoin(fileJoin($d_path, $lang_suffix, "LC_MESSAGES", $d_name . $LCE_PO_SUFFIX)); 600 else 601 { 602 $LCE_ERR = "No PO-file found"; 603 return false; 604 } 605 } 606 //print "D_Path: $d_path \n"; 607 $por = new POReader($d_name, $d_path, $path_orig); 608 $por->read(); 609 $porman =& loadPORManager(); 610 $porman->addPOReader($d_name, $por); 611 return true; 612 } 613 614 function lce_textdomain($domain) 615 { 616 global $LCE_DOMAIN; 617 $LCE_DOMAIN = $domain; 618 } 619 620 function lce_gettext($msgid) 621 { 622 global $LCE_DOMAIN; 623 return lce_dgettext($LCE_DOMAIN, $msgid); 624 } 625 626 function lce_dgettext($domain, $msgid) 627 { 628 $porman =& loadPORManager(); 629 if($por = &$porman->getPOReader($domain)) 630 return $por->gettext($msgid); 631 return $msgid; 632 } 633 634 function lce() 635 { 636 global $LCE_LCEDITLOC; 637 $porman =& loadPORManager(); 638 $domains = $porman->getDomainNames(); 639 for($i = 0; $i < count($domains); $i++) 640 { 641 $por =& $porman->getPOReader($domains[$i]); 642 $domain = "domain=" . urlencode($por->domain); 643 $filename = "filename=" . urlencode($por->filename); 644 $url = $LCE_LCEDITLOC . "?" . $domain . "&" . $filename; 645 print "<a target=\"_blank\" href=\"" . $url . "\">Domain: $por->domain</a><br>"; 646 } 647 } 648 } 649 else 650 { 651 function lce_bindtextdomain($domain, $path) 652 { 653 bindtextdomain($domain, $path); 654 } 655 656 function lce_textdomain($domain) 657 { 658 textdomain($domain); 659 } 660 661 function lce_gettext($msgid) 662 { 663 return gettext($msgid); 664 } 665 666 function lce_dgettext($domain, $msgid) 667 { 668 return dgettext($domain, $msgid); 669 } 670 function lce() 671 { 672 } 673 } 674 675 676 function lce_geteditcode($type, $name, $text, $rows=2) 677 { 678 global $LCE_EDIT_LEVEL; 679 $level_map = array("msgid" => 4, 680 "sys_comment" => 3, 681 "user_comment" => 2, 682 "msgstr" => 1 683 ); 684 if($level_map[$type] > $LCE_EDIT_LEVEL) 685 { 686 return "<input type=\"hidden\" name=\"" . $name . "\" value=\"" . $text . "\"><pre>\n" . $text . "\n</pre>"; 687 } 688 else 689 { 690 return "<textarea name=\"" . $name . "\" rows=\"" . $rows . "\" cols=\"60\">" . $text . "</textarea>"; 691 } 692 } 693} 694/* 695 ;;; Local Variables: *** 696 ;;; mode:C *** 697 ;;; End: *** 698*/ 699?> 700