[ Index ]

PHP Cross Reference of Mambo 4.6.5

[ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/includes/phpgettext/ -> phpgettext.catalog.php (source)

   1  <?php
   2  /**

   3   * @version        0.9

   4   * @author      Carlos Souza

   5   * @copyright   Copyright (c) 2005 Carlos Souza <csouza@web-sense.net>

   6   * @package     PHPGettext

   7   * @license        MIT License (http://www.opensource.org/licenses/mit-license.php)

   8   * @link        http://phpgettext.web-sense.net

   9   */
  10  defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  11  
  12  define('_MODE_MO_', 'mo');
  13  define('_MODE_PO_', 'po');
  14  define('_MODE_POT_','pot');
  15  define('_MODE_GLO_','go');
  16  
  17  require_once(dirname(__FILE__).'/phpgettext.message.php');
  18  class PHPGettext_Catalog
  19  {
  20      var $mode = _MODE_MO_;
  21      var $name = '';
  22      var $path = '';
  23      var $lang = 'en';
  24      var $charset = 'utf-8';
  25      var $category = 'LC_MESSAGES';
  26      var $comments = array();
  27      var $headers = array();
  28      var $strings = array();
  29      function PHPGettext_Catalog($name, $path)
  30      {
  31          $this->name = trim($name);
  32          $this->path = trim($path);
  33      }
  34  
  35      function load()
  36      {
  37          switch ($this->mode)
  38          {
  39              case _MODE_MO_:
  40              return $this->_readMO();
  41              break;
  42              case _MODE_PO_:
  43              return $this->_readPO();
  44              break;
  45              case _MODE_POT_:
  46              return $this->_readPO();            
  47              break;
  48              case _MODE_GLO_:
  49              $this->mode = _MODE_PO_;
  50              $this->lang = 'glossary';
  51              return $this->_readPO();            
  52              break;
  53              default:
  54              trigger_error('Unrecognized mode in '.__CLASS__.'->'.__FUNCTION__, E_USER_ERROR);
  55              return false;
  56              break;
  57          }
  58      }
  59  
  60      function save()
  61      {
  62  
  63          $langdir = $this->path.DIRECTORY_SEPARATOR.$this->lang;
  64          if (!is_dir($langdir)) {
  65              $this->createdir($langdir.DIRECTORY_SEPARATOR.$this->category);
  66          }
  67  
  68          switch ($this->mode)
  69          {
  70              case _MODE_MO_:
  71              return $this->_writeMO();
  72              break;
  73              case _MODE_PO_:
  74              $this->setRevisionDate();
  75              return $this->_writePO();
  76              case _MODE_POT_:
  77              return $this->_writePO();
  78              break;
  79              case _MODE_GLO_:
  80              $this->mode = _MODE_PO_;
  81              $this->lang = 'glossary';
  82              return $this->_writePO();
  83              break;
  84              default:
  85              trigger_error('Unrecognized mode in '.__CLASS__.'->'.__FUNCTION__, E_USER_ERROR);
  86              return false;
  87              break;
  88          }
  89      }
  90  
  91  
  92      function filename()
  93      {
  94          $return = $this->path.DIRECTORY_SEPARATOR;
  95          $return .= !empty($this->lang) ? $this->lang.DIRECTORY_SEPARATOR : '';
  96          $return .= (!empty($this->category) && $this->mode == _MODE_MO_) ? $this->category.DIRECTORY_SEPARATOR : '';
  97          $return .= $this->name.'.'.$this->mode;
  98          return  $return;
  99      }
 100  
 101      function createdir($path)
 102      {
 103          if (!file_exists($path))
 104          {
 105              // The directory doesn't exist.  Recurse, passing in the parent

 106              // directory so that it gets created.

 107              $this->createdir(dirname($path));
 108              mkdir($path, 0777);
 109          }
 110      }
 111  
 112      function setRevisionDate()
 113      {
 114          $this->headers['PO-Revision-Date'] = date('Y-m-d G:iO');
 115      }
 116      
 117      function setComments($comments)
 118      {        
 119          $comments   = trim($comments);
 120          if (is_string($comments)) {
 121              $comments = explode("\n", $comments);
 122              if (is_array($comments)) {
 123                  foreach ($comments as $comment)   {
 124                      if (strpos($comment, '#') == 1)  {
 125                          $this->comments .= $comment."\n";
 126                      }
 127                  }
 128              }
 129          }
 130      }
 131      
 132      function setHeaders($headers)
 133      {
 134          if (!is_array($headers)) {
 135              return false;
 136          }
 137          foreach ($headers as $key => $value) {
 138              $this->headers[$key] = $value;
 139          }
 140      }
 141  
 142      function setproperty($property, $value = null) {
 143          $return = $this->$property;
 144          $this->$property = $value;
 145          return $return;
 146      }
 147      function getproperty($property) {
 148          return $this->$property;
 149      }
 150  
 151      function addentry($msgid, $msgid_plural=null, $msgstr=null, $comments=array())
 152      {
 153          $entry =  new PHPGettext_Message($msgid, $msgid_plural);
 154          if (!is_null($msgstr)) $entry->setmsgstr($msgstr);
 155          if (!empty($comments)) $entry->setcomments($comments);
 156          $this->strings[$msgid] = $entry;
 157      }
 158  
 159      function translate(&$translations)
 160      {
 161          $n = count($this->strings);
 162          for ($i=0;$i<$n;$i++){
 163              if (!empty($translations[$this->strings[$i]->msgid])){
 164                 $this->strings[$i]->setmsgstr ($translations[$this->strings[$i]->msgid]);
 165              }
 166          }
 167      }
 168  
 169      function merge(&$glossary)
 170      {
 171          foreach ($this->strings as $msgid => $string){
 172                if (!$glossary[$string->msgid]){
 173                    $glossary[$string->msgid] = $string;
 174                }else{
 175                    $glossary[$string->msgid]->comments = array_merge($glossary[$string->msgid]->comments,$string->comments);
 176                    $glossary[$string->msgid]->comments = array_unique($glossary[$string->msgid]->comments);
 177                }
 178          }
 179          $n = count($glossary);
 180          unset($this->strings);
 181          foreach ($glossary as $msgid => $string){
 182             $this->addentry($msgid, $string->msgid_plural, $string->msgstr, $string->comments);
 183          }
 184      }
 185  
 186      function _writePO()
 187      {
 188          $file = $this->filename();
 189  
 190          // open PO file

 191          if (!is_resource($res = @fopen($file, 'a'))) {
 192              trigger_error("Cannot create '$file'. ", E_USER_WARNING);
 193              return false;
 194          }
 195          // lock PO file exclusively

 196          if (!@flock($res, LOCK_EX)) {
 197              @fclose($res);
 198              trigger_error("Cannot lock '$file'. ", E_USER_WARNING);
 199              return false;
 200          }
 201          @ftruncate($res,0);
 202          // write comments

 203          if (count($this->comments > 0)) {
 204              foreach ($this->comments as $line) {
 205                  fwrite($res, trim($line)."\n");
 206              }
 207          }
 208          // write meta info

 209          if (count($this->headers > 0)) {
 210              $header = 'msgid ""' . "\nmsgstr " . '""' . "\n";
 211              foreach ($this->headers as $k => $v) {
 212                  $header .= '"' . $k . ': ' . $v . '\n"' . "\n";
 213              }
 214              fwrite($res, $header . "\n");
 215          }
 216  
 217          // write strings

 218          if (count($this->strings > 0)) {
 219              foreach ($this->strings as $string) {
 220                  fwrite($res, $string->toString());
 221              }
 222          }
 223          //done

 224          @flock($res, LOCK_UN);
 225          @fclose($res);
 226          return true;
 227      }
 228  
 229      function _readPO()
 230      {
 231          $file = $this->filename();
 232          if (!is_readable($file)) {
 233              trigger_error('Gettext Catalog '.$this->filename().' not found', E_USER_WARNING);
 234              return false;
 235          }
 236          // load file

 237          if (!$data = @file($file)) {
 238              trigger_error('Gettext Catalog '.$this->filename().' not found', E_USER_WARNING);
 239              return false;
 240          }
 241          $count      = 0;
 242          $comments   = '';
 243          $is_fuzzy   = false;
 244          $nplural    = false;
 245  
 246          // get all strings

 247          foreach ($data as $line) {
 248              // comments

 249              if (strncmp($line, "#", 1) == 0) {
 250                  if ($count < 1) {
 251                      $this->comments[] = $line;
 252                  } else {
 253                      if (strncmp($line, "#,", 2) == 0 && preg_match('/fuzzy/', $line)) {
 254                          unset($line);
 255                          $is_fuzzy = true;
 256                      }
 257                      if (isset($line)) {
 258                          $comments[] = $line;
 259                      }
 260                  }
 261              }// msgid

 262              elseif (preg_match('/^msgid\s*"(.*)"\s*|^msgid_plural\s*"(.*)"\s*/s', $line, $matches)) {
 263                  if (preg_match('/^msgid_plural\s*/s', $line, $arr)) {
 264                      $nplural = true;
 265                      $strings[$count]['msgid_plural'] = $matches[2];
 266                  } else {
 267                      $count++;
 268                      $strings[$count]['comments'] = isset($comments) ? $comments : '';
 269                      $strings[$count]['msgid']    = '';
 270                      $strings[$count]['msgid_plural']    = '';
 271                      $strings[$count]['msgstr']   = '';
 272                      $strings[$count]['is_fuzzy'] = $is_fuzzy;
 273                      if (!empty($matches[1])) {
 274                          $strings[$count]['msgid'] = $matches[1];
 275                      }
 276                      unset($msgstr);
 277                      unset($comments);
 278                      $nplural  = false;
 279                      $is_fuzzy = false;
 280  
 281                  }
 282              } // msgstr

 283              elseif  (preg_match('/^msgstr\s*"(.*)"\s*|^msgstr\[[0-9]\]\s*"(.*)"\s*/s', $line, $matches)) {
 284                  $msgstr = true;
 285                  if ($nplural) {
 286                      $strings[$count]['msgstr'][] = isset($matches[2]) ? $matches[2] : '';
 287                  } else {
 288                      $strings[$count]['msgstr'] = $matches[1];
 289                  }
 290              } // multiline msgid or msgstr

 291              elseif (preg_match('/^"(.*)"\s*$/s', $line, $matches)) {
 292                  // headers

 293                  if (isset($msgstr) && $count == 1) {
 294                      list($key, $value) = explode(':', $matches[1], 2);
 295                      $this->headers[$key] = $value;
 296                  }
 297                  elseif (isset($msgstr) && $count > 1) {
 298                      $strings[$count]['msgstr'] .= $matches[1];
 299                  }
 300                  else { // msgid
 301                      $strings[$count]['msgid']  .= $matches[1];
 302                  }
 303              }
 304          }
 305  
 306          // load the strings

 307          array_shift($strings);
 308          for ($a=0; $a < count($strings); $a++) {
 309              $this->strings[$a] = new PHPGettext_Message($strings[$a]['msgid'], $strings[$a]['msgid_plural']);
 310              $this->strings[$a]->setmsgstr($strings[$a]['msgstr']);
 311              $this->strings[$a]->setfuzzy($strings[$a]['is_fuzzy']);
 312              $this->strings[$a]->setcomments($strings[$a]['comments']);
 313          }
 314          return true;
 315      }
 316  
 317      function _writeMO()
 318      {
 319          $file = $this->filename();
 320  
 321          // open MO file

 322          if (!is_resource($res = @fopen($file, 'w'))) {
 323              trigger_error("Cannot create '$file'. ", E_USER_WARNING);
 324          }
 325          // lock MO file exclusively

 326          if (!@flock($res, LOCK_EX)) {
 327              @fclose($res);
 328              trigger_error("Cannot lock '$file'. ", E_USER_WARNING);
 329          }
 330  
 331          // get the headers

 332          $headers = "";
 333          foreach ($this->headers as $key => $val) {
 334              $headers .= $key . ': ' . $val . "\n";
 335          }
 336          $strings[] = array('msgid' => "", 'msgstr' => $headers);
 337  
 338          // don't write fuzzy entries

 339          foreach ($this->strings as $message) {
 340              if (!$message->is_fuzzy) {
 341                  $strings[] = array('msgid' => $message->msgid,'msgid_plural' => $message->msgid_plural, 'msgstr' => $message->msgstr);
 342              }
 343  
 344          }
 345  
 346          $count = count($strings);
 347          fwrite($res, pack('L', (int) 0x950412de));  // magic number

 348          fwrite($res, pack('L', 0));                 // revision  0

 349          fwrite($res, pack('L', $count));            // N - number of strings

 350          $offset = 28;
 351          fwrite($res, pack('L', $offset));           // O - offset of table with original strings

 352          $offset += ($count * 8);
 353          fwrite($res, pack('L', $offset));           // T - offset of table with translation strings

 354          fwrite($res, pack('L', 0));                 // S - size of hashing table (set to 0 to omit the table)

 355          $offset += ($count * 8);
 356          fwrite($res, pack('L', $offset));           // H - offset of hashing table

 357  
 358          // offsets for original strings

 359          for ($a=0; $a<$count; $a++) {
 360              if (isset($strings[$a]['msgid_plural'])) { // plurals
 361                  $strings[$a]['msgid'] = $strings[$a]['msgid'] ."\0".$strings[$a]['msgid_plural'];
 362              }
 363              $len = strlen($strings[$a]['msgid']);
 364              fwrite($res, pack('L', $len));
 365              fwrite($res, pack('L', $offset));
 366              $offset += $len + 1;
 367          }
 368  
 369          // offsets for translated strings

 370          for ($a=0; $a<$count; $a++) {
 371              if (is_array($strings[$a]['msgstr'])) { // plurals
 372                  $strings[$a]['msgstr'] = implode("\0", $strings[$a]['msgstr']);
 373              }
 374              $len = strlen($strings[$a]['msgstr']);
 375              fwrite($res, pack('L', $len));
 376              fwrite($res, pack('L', $offset));
 377              $offset += $len + 1;
 378          }
 379  
 380          // write original strings

 381          foreach ($strings as $str) {
 382              fwrite($res, $str['msgid'] . "\0");
 383          }
 384          // write translated strings

 385          foreach ($strings as $str) {
 386              fwrite($res, $str['msgstr'] . "\0");
 387          }
 388          // done

 389          @flock($res, LOCK_UN);
 390          @fclose($res);
 391          return true;
 392      }
 393  
 394  
 395      function _readMO()
 396      {
 397          $file = $this->filename();
 398          if (!file_exists($file)) return false;
 399  
 400          //  read in data file completely

 401          $f = fopen($file, "rb");
 402          $data = fread($f, 1<<20);
 403          fclose($f);
 404  
 405          //  extract header fields and check file magic

 406          if ($data) {
 407              $header = substr($data, 0, 20);
 408              $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
 409              extract($header);
 410              $magicNumber = substr(dechex($magic),-8);
 411              if (($magicNumber == "950412de") && ($version == 0)) {
 412                  //  fetch all strings

 413                  for ($a=0; $a<$count; $a++) {
 414                      //  msgid

 415                      $r = unpack("L1len/L1offs", substr($data, $o_msg + $a * 8, 8));
 416                      $msgid = substr($data, $r["offs"], $r["len"]);
 417                      unset($msgid_plural);
 418                      if (strpos($msgid, "\0")) { // plurals
 419                          list($msgid, $msgid_plural) = explode("\0", $msgid);
 420                      }
 421                      //  msgstr

 422                      $r = unpack("L1len/L1offs", substr($data, $o_trn + $a * 8, 8));
 423                      $msgstr = substr($data, $r["offs"], $r["len"]);
 424                      if (isset($msgid_plural)) { // plurals
 425                          $msgstr = explode("\0", $msgstr);
 426                      }
 427                      $strings[$a]['msgid'] = $msgid;
 428                      $strings[$a]['msgstr'] = $msgstr;
 429                      $strings[$a]['msgid_plural'] = isset($msgid_plural) ? $msgid_plural : '';
 430                  }
 431                  if (!empty($strings[0]['msgstr'])){ // header
 432                      $str = explode("\n", $strings[0]['msgstr']);
 433                      foreach ($str as $s){
 434                          if (!empty($s)) {
 435                              @list($key, $value) = explode(':', $s, 2);
 436                              $this->headers[$key] = $value;
 437                          }
 438                      }
 439                  }
 440                  // load the strings

 441                  array_shift($strings);
 442                  for ($a=0; $a < count($strings); $a++) {
 443                      $this->strings[$a] = new PHPGettext_Message($strings[$a]['msgid'], $strings[$a]['msgid_plural']);
 444                      $this->strings[$a]->setmsgstr($strings[$a]['msgstr']);
 445                  }
 446                  return true;
 447              }
 448          }
 449          return false;
 450      }
 451  
 452  
 453  }
 454  ?>