[ Index ]
 

Code source de Symfony 1.0.0

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

title

Body

[fermer]

/lib/i18n/ -> sfMessageSource_XLIFF.class.php (source)

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


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7