[ Index ]
 

Code source de PRADO 3.0.6

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/framework/I18N/core/ -> MessageSource_XLIFF.php (source)

   1  <?php
   2  
   3  /**
   4   * MessageSource_XLIFF class file.
   5   *
   6   * This program is free software; you can redistribute it and/or modify
   7   * it under the terms of the BSD License.
   8   *
   9   * Copyright(c) 2004 by Qiang Xue. All rights reserved.
  10   *
  11   * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
  12   * The latest version of PRADO can be obtained from:
  13   * {@link http://prado.sourceforge.net/}
  14   *
  15   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
  16   * @version $Revision: 1.8 $  $Date: 2005/12/17 06:11:28 $
  17   * @package System.I18N.core
  18   */
  19  
  20  /**
  21   * Get the MessageSource class file.
  22   */
  23  require_once(dirname(__FILE__).'/MessageSource.php');
  24  
  25  /**
  26   * MessageSource_XLIFF class.
  27   *
  28   * Using XML XLIFF format as the message source for translation.
  29   * Details and example of XLIFF can be found in the following URLs.
  30   *
  31   * # http://www.opentag.com/xliff.htm
  32   * # http://www-106.ibm.com/developerworks/xml/library/x-localis2/
  33   *
  34   * See the MessageSource::factory() method to instantiate this class.
  35   *
  36   * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
  37   * @version v1.0, last update on Fri Dec 24 16:18:44 EST 2004
  38   * @package System.I18N.core
  39   */
  40  class MessageSource_XLIFF extends MessageSource
  41  {
  42      /**
  43       * Message data filename extension.
  44       * @var string
  45       */
  46      protected $dataExt = '.xml';
  47  
  48      /**
  49       * Separator between culture name and source.
  50       * @var string
  51       */
  52      protected $dataSeparator = '.';
  53  
  54      /**
  55       * Constructor.
  56       * @param string the directory where the messages are stored.
  57       * @see MessageSource::factory();
  58       */
  59  	function __construct($source)
  60      {
  61          $this->source = (string)$source;
  62      }
  63  
  64      /**
  65       * Load the messages from a XLIFF file.
  66       * @param string XLIFF file.
  67       * @return array of messages.
  68       */
  69      protected function &loadData($filename)
  70      {
  71          //load it.
  72  
  73          $XML = simplexml_load_file($filename);
  74  
  75          if(!$XML) return false;
  76  
  77          $translationUnit = $XML->xpath('//trans-unit');
  78  
  79          $translations = array();
  80  
  81          foreach($translationUnit as $unit)
  82          {
  83              $source = (string)$unit->source;
  84              $translations[$source][] = (string)$unit->target;
  85              $translations[$source][]= (string)$unit['id'];
  86              $translations[$source][]= (string)$unit->note;
  87          }
  88  
  89          return $translations;
  90      }
  91  
  92      /**
  93       * Get the last modified unix-time for this particular catalogue+variant.
  94       * Just use the file modified time.
  95       * @param string catalogue+variant
  96       * @return int last modified in unix-time format.
  97       */
  98  	protected function getLastModified($source)
  99      {
 100          if(is_file($source))
 101              return filemtime($source);
 102          else
 103              return 0;
 104      }
 105  
 106      /**
 107       * Get the XLIFF file for a specific message catalogue and cultural
 108       * vairant.
 109       * @param string message catalogue
 110       * @return string full path to the XLIFF file.
 111       */
 112  	protected function getSource($variant)
 113      {
 114          return $this->source.'/'.$variant;
 115      }
 116  
 117      /**
 118       * Determin if the XLIFF file source is valid.
 119       * @param string XLIFF file
 120       * @return boolean true if valid, false otherwise.
 121       */
 122  	protected function isValidSource($source)
 123      {
 124          return is_file($source);
 125      }
 126  
 127      /**
 128       * Get all the variants of a particular catalogue.
 129       * @param string catalogue name
 130       * @return array list of all variants for this catalogue.
 131       */
 132  	protected function getCatalogueList($catalogue)
 133      {
 134          $variants = explode('_',$this->culture);
 135          $source = $catalogue.$this->dataExt;
 136  
 137          $catalogues = array($source);
 138  
 139          $variant = null;
 140  
 141          for($i = 0, $k = count($variants); $i < $k; ++$i)
 142          {
 143              if(isset($variants[$i]{0}))
 144              {
 145                  $variant .= ($variant)?'_'.$variants[$i]:$variants[$i];
 146                  $catalogues[] = $catalogue.$this->dataSeparator.
 147                                  $variant.$this->dataExt;
 148              }
 149          }
 150  
 151          $byDir = $this->getCatalogueByDir($catalogue);
 152          $catalogues = array_merge($byDir,array_reverse($catalogues));
 153          return $catalogues;
 154      }
 155  
 156      /**
 157       * Traverse through the directory structure to find the catalogues.
 158       * This should only be called by getCatalogueList()
 159       * @param string a particular catalogue.
 160       * @return array a list of catalogues.
 161       * @see getCatalogueList()
 162       */
 163  	private function getCatalogueByDir($catalogue)
 164      {
 165          $variants = explode('_',$this->culture);
 166          $catalogues = array();
 167  
 168          $variant = null;
 169  
 170          for($i = 0, $k = count($variants); $i < $k; ++$i)
 171          {
 172              if(isset($variants[$i]{0}))
 173              {
 174                  $variant .= ($variant)?'_'.$variants[$i]:$variants[$i];
 175                  $catalogues[] = $variant.'/'.$catalogue.$this->dataExt;
 176              }
 177          }
 178          return array_reverse($catalogues);
 179      }
 180  
 181      /**
 182       * Returns a list of catalogue and its culture ID.
 183       * E.g. array('messages','en_AU')
 184       * @return array list of catalogues
 185       * @see getCatalogues()
 186       */
 187  	public function catalogues()
 188      {
 189          return $this->getCatalogues();
 190      }
 191  
 192      /**
 193       * Returns a list of catalogue and its culture ID. This takes care
 194       * of directory structures.
 195       * E.g. array('messages','en_AU')
 196       * @return array list of catalogues
 197       */
 198  	protected function getCatalogues($dir=null,$variant=null)
 199      {
 200          $dir = $dir?$dir:$this->source;
 201          $files = scandir($dir);
 202  
 203          $catalogue = array();
 204  
 205          foreach($files as $file)
 206          {
 207              if(is_dir($dir.'/'.$file)
 208                  && preg_match('/^[a-z]{2}(_[A-Z]{2,3})?$/',$file))
 209              {
 210                  $catalogue = array_merge($catalogue,
 211                                  $this->getCatalogues($dir.'/'.$file, $file));
 212              }
 213  
 214              $pos = strpos($file,$this->dataExt);
 215              if($pos >0
 216                  && substr($file,-1*strlen($this->dataExt)) == $this->dataExt)
 217              {
 218                  $name = substr($file,0,$pos);
 219                  $dot = strrpos($name,$this->dataSeparator);
 220                  $culture = $variant;
 221                  $cat = $name;
 222                  if(is_int($dot))
 223                  {
 224                      $culture = substr($name, $dot+1,strlen($name));
 225                      $cat = substr($name,0,$dot);
 226                  }
 227                  $details[0] = $cat;
 228                  $details[1] = $culture;
 229  
 230  
 231                  $catalogue[] = $details;
 232              }
 233          }
 234          sort($catalogue);
 235          return $catalogue;
 236      }
 237  
 238      /**
 239       * Get the variant for a catalogue depending on the current culture.
 240       * @param string catalogue
 241       * @return string the variant.
 242       * @see save()
 243       * @see update()
 244       * @see delete()
 245       */
 246  	private function getVariants($catalogue='messages')
 247      {
 248          if(is_null($catalogue))
 249              $catalogue = 'messages';
 250  
 251          foreach($this->getCatalogueList($catalogue) as $variant)
 252          {
 253              $file = $this->getSource($variant);
 254              if(is_file($file))
 255                  return array($variant, $file);
 256          }
 257          return false;
 258      }
 259  
 260      /**
 261       * Save the list of untranslated blocks to the translation source.
 262       * If the translation was not found, you should add those
 263       * strings to the translation source via the <b>append()</b> method.
 264       * @param string the catalogue to add to
 265       * @return boolean true if saved successfuly, false otherwise.
 266       */
 267  	public function save($catalogue='messages')
 268      {
 269          $messages = $this->untranslated;
 270          if(count($messages) <= 0) return false;
 271  
 272          $variants = $this->getVariants($catalogue);
 273  
 274          if($variants)
 275              list($variant, $filename) = $variants;
 276          else
 277              list($variant, $filename) = $this->createMessageTemplate($catalogue);
 278  
 279          if(is_writable($filename) == false)
 280              throw new TIOException("Unable to save to file {$filename}, file must be writable.");
 281  
 282          //create a new dom, import the existing xml
 283          $dom = new DOMDocument();
 284          $dom->load($filename);
 285  
 286          //find the body element
 287          $xpath = new DomXPath($dom);
 288          $body = $xpath->query('//body')->item(0);
 289  
 290          $lastNodes = $xpath->query('//trans-unit[last()]');
 291          if(($last=$lastNodes->item(0))!==null)
 292              $count = intval($last->getAttribute('id'));
 293          else
 294              $count = 0;
 295  
 296          //for each message add it to the XML file using DOM
 297          foreach($messages as $message)
 298          {
 299              $unit = $dom->createElement('trans-unit');
 300              $unit->setAttribute('id',++$count);
 301  
 302              $source = $dom->createElement('source', $message);
 303              $target = $dom->createElement('target','');
 304  
 305              $unit->appendChild($dom->createTextNode("\n"));
 306              $unit->appendChild($source);
 307              $unit->appendChild($dom->createTextNode("\n"));
 308              $unit->appendChild($target);
 309              $unit->appendChild($dom->createTextNode("\n"));
 310  
 311              $body->appendChild($dom->createTextNode("\n"));
 312              $body->appendChild($unit);
 313              $body->appendChild($dom->createTextNode("\n"));
 314          }
 315  
 316  
 317          $fileNode = $xpath->query('//file')->item(0);
 318          $fileNode->setAttribute('date', @date('Y-m-d\TH:i:s\Z'));
 319  
 320          //save it and clear the cache for this variant
 321          $dom->save($filename);
 322          if(!empty($this->cache))
 323              $this->cache->clean($variant, $this->culture);
 324  
 325          return true;
 326      }
 327  
 328      /**
 329       * Update the translation.
 330       * @param string the source string.
 331       * @param string the new translation string.
 332       * @param string comments
 333       * @param string the catalogue to save to.
 334       * @return boolean true if translation was updated, false otherwise.
 335       */
 336  	public function update($text, $target, $comments, $catalogue='messages')
 337      {
 338          $variants = $this->getVariants($catalogue);
 339          if($variants)
 340              list($variant, $filename) = $variants;
 341          else
 342              return false;
 343  
 344          if(is_writable($filename) == false)
 345              throw new TIOException("Unable to update file {$filename}, file must be writable.");
 346  
 347          //create a new dom, import the existing xml
 348          $dom = DOMDocument::load($filename);
 349  
 350          //find the body element
 351          $xpath = new DomXPath($dom);
 352          $units = $xpath->query('//trans-unit');
 353  
 354          //for each of the existin units
 355          foreach($units as $unit)
 356          {
 357              $found = false;
 358              $targetted = false;
 359              $commented = false;
 360  
 361              //in each unit, need to find the source, target and comment nodes
 362              //it will assume that the source is before the target.
 363              foreach($unit->childNodes as $node)
 364              {
 365                  //source node
 366                  if($node->nodeName == 'source'
 367                    && $node->firstChild->wholeText == $text)
 368                  {
 369                           $found = true;
 370                  }
 371  
 372                  //found source, get the target and notes
 373                  if($found)
 374                  {
 375                      //set the new translated string
 376                      if($node->nodeName == 'target')
 377                      {
 378                          $node->nodeValue = $target;
 379                          $targetted = true;
 380                      }
 381                      //set the notes
 382                      if(!empty($comments) && $node->nodeName == 'note')
 383                      {
 384                          $node->nodeValue = $comments;
 385                          $commented = true;
 386                      }
 387                  }
 388              }
 389  
 390              //append a target
 391              if($found && !$targetted)
 392                  $unit->appendChild($dom->createElement('target',$target));
 393  
 394              //append a note
 395              if($found && !$commented && !empty($comments))
 396                  $unit->appendChild($dom->createElement('note',$comments));
 397  
 398              //finished searching
 399              if($found) break;
 400          }
 401  
 402          $fileNode = $xpath->query('//file')->item(0);
 403          $fileNode->setAttribute('date', @date('Y-m-d\TH:i:s\Z'));
 404  
 405          if($dom->save($filename) >0)
 406          {
 407              if(!empty($this->cache))
 408                  $this->cache->clean($variant, $this->culture);
 409              return true;
 410          }
 411  
 412          return false;
 413      }
 414  
 415      /**
 416       * Delete a particular message from the specified catalogue.
 417       * @param string the source message to delete.
 418       * @param string the catalogue to delete from.
 419       * @return boolean true if deleted, false otherwise.
 420       */
 421  	public function delete($message, $catalogue='messages')
 422      {
 423          $variants = $this->getVariants($catalogue);
 424          if($variants)
 425              list($variant, $filename) = $variants;
 426          else
 427              return false;
 428  
 429          if(is_writable($filename) == false)
 430              throw new TIOException("Unable to modify file {$filename}, file must be writable.");
 431  
 432          //create a new dom, import the existing xml
 433          $dom = DOMDocument::load($filename);
 434  
 435          //find the body element
 436          $xpath = new DomXPath($dom);
 437          $units = $xpath->query('//trans-unit');
 438  
 439          //for each of the existin units
 440          foreach($units as $unit)
 441          {
 442              //in each unit, need to find the source, target and comment nodes
 443              //it will assume that the source is before the target.
 444              foreach($unit->childNodes as $node)
 445              {
 446                  //source node
 447                  if($node->nodeName == 'source'
 448                    && $node->firstChild->wholeText == $message)
 449                  {
 450  
 451                      //we found it, remove and save the xml file.
 452                      $unit->parentNode->removeChild($unit);
 453  
 454                      $fileNode = $xpath->query('//file')->item(0);
 455                      $fileNode->setAttribute('date', @date('Y-m-d\TH:i:s\Z'));
 456  
 457                      if($dom->save($filename) >0)
 458                      {
 459                          if(!empty($this->cache))
 460                              $this->cache->clean($variant, $this->culture);
 461                          return true;
 462                      }
 463                      else return false;
 464  
 465                  }
 466              }
 467  
 468          }
 469  
 470          return false;
 471      }
 472  
 473  	protected function createMessageTemplate($catalogue)
 474      {
 475          if(is_null($catalogue))
 476              $catalogue = 'messages';
 477          $variants = $this->getCatalogueList($catalogue);
 478          $variant = array_shift($variants);
 479          $file = $this->getSource($variant);
 480          $dir = dirname($file);
 481          if(!is_dir($dir)) 
 482          {
 483              @mkdir($dir);
 484              @chmod($dir,0777);
 485          }
 486          if(!is_dir($dir))
 487              throw new TException("Unable to create directory $dir");
 488          file_put_contents($file, $this->getTemplate($catalogue));
 489          chmod($file, 0777);
 490          return array($variant, $file);
 491      }
 492  
 493  	protected function getTemplate($catalogue)
 494      {
 495          $date = @date('c');
 496  $xml = <<<EOD
 497  <?xml version="1.0"?>
 498  <xliff version="1.0">
 499   <file
 500      source-language="EN"
 501      target-language="{$this->culture}"
 502      datatype="plaintext"
 503      original="$catalogue"
 504      date="$date"
 505      product-name="$catalogue">
 506    <body>
 507    </body>
 508   </file>
 509  </xliff>
 510  EOD;
 511          return $xml;
 512      }
 513  }
 514  
 515  ?>


Généré le : Sun Feb 25 21:07:04 2007 par Balluche grâce à PHPXref 0.7