You are here

XliffFileLoader.php in Zircon Profile 8

Same filename and directory in other branches
  1. 8.0 vendor/symfony/translation/Loader/XliffFileLoader.php

File

vendor/symfony/translation/Loader/XliffFileLoader.php
View source
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Symfony\Component\Translation\Loader;

use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Config\Resource\FileResource;

/**
 * XliffFileLoader loads translations from XLIFF files.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class XliffFileLoader implements LoaderInterface {

  /**
   * {@inheritdoc}
   */
  public function load($resource, $locale, $domain = 'messages') {
    if (!stream_is_local($resource)) {
      throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
    }
    if (!file_exists($resource)) {
      throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
    }
    list($xml, $encoding) = $this
      ->parseFile($resource);
    $xml
      ->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
    $catalogue = new MessageCatalogue($locale);
    foreach ($xml
      ->xpath('//xliff:trans-unit') as $translation) {
      $attributes = $translation
        ->attributes();
      if (!(isset($attributes['resname']) || isset($translation->source))) {
        continue;
      }
      $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;

      // If the xlf file has another encoding specified, try to convert it because
      // simple_xml will always return utf-8 encoded values
      $target = $this
        ->utf8ToCharset((string) (isset($translation->target) ? $translation->target : $source), $encoding);
      $catalogue
        ->set((string) $source, $target, $domain);
      if (isset($translation->note)) {
        $notes = array();
        foreach ($translation->note as $xmlNote) {
          $noteAttributes = $xmlNote
            ->attributes();
          $note = array(
            'content' => $this
              ->utf8ToCharset((string) $xmlNote, $encoding),
          );
          if (isset($noteAttributes['priority'])) {
            $note['priority'] = (int) $noteAttributes['priority'];
          }
          if (isset($noteAttributes['from'])) {
            $note['from'] = (string) $noteAttributes['from'];
          }
          $notes[] = $note;
        }
        $catalogue
          ->setMetadata((string) $source, array(
          'notes' => $notes,
        ), $domain);
      }
    }
    if (class_exists('Symfony\\Component\\Config\\Resource\\FileResource')) {
      $catalogue
        ->addResource(new FileResource($resource));
    }
    return $catalogue;
  }

  /**
   * Convert a UTF8 string to the specified encoding.
   *
   * @param string $content  String to decode
   * @param string $encoding Target encoding
   *
   * @return string
   */
  private function utf8ToCharset($content, $encoding = null) {
    if ('UTF-8' !== $encoding && !empty($encoding)) {
      if (function_exists('mb_convert_encoding')) {
        return mb_convert_encoding($content, $encoding, 'UTF-8');
      }
      if (function_exists('iconv')) {
        return iconv('UTF-8', $encoding, $content);
      }
      throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
    }
    return $content;
  }

  /**
   * Validates and parses the given file into a SimpleXMLElement.
   *
   * @param string $file
   *
   * @throws \RuntimeException
   *
   * @return \SimpleXMLElement
   *
   * @throws InvalidResourceException
   */
  private function parseFile($file) {
    try {
      $dom = XmlUtils::loadFile($file);
    } catch (\InvalidArgumentException $e) {
      throw new InvalidResourceException(sprintf('Unable to load "%s": %s', $file, $e
        ->getMessage()), $e
        ->getCode(), $e);
    }
    $internalErrors = libxml_use_internal_errors(true);
    $location = str_replace('\\', '/', __DIR__) . '/schema/dic/xliff-core/xml.xsd';
    $parts = explode('/', $location);
    if (0 === stripos($location, 'phar://')) {
      $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
      if ($tmpfile) {
        copy($location, $tmpfile);
        $parts = explode('/', str_replace('\\', '/', $tmpfile));
      }
    }
    $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts) . '/' : '';
    $location = 'file:///' . $drive . implode('/', array_map('rawurlencode', $parts));
    $source = file_get_contents(__DIR__ . '/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
    $source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
    if (!@$dom
      ->schemaValidateSource($source)) {
      throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: %s', $file, implode("\n", $this
        ->getXmlErrors($internalErrors))));
    }
    $dom
      ->normalizeDocument();
    libxml_clear_errors();
    libxml_use_internal_errors($internalErrors);
    return array(
      simplexml_import_dom($dom),
      strtoupper($dom->encoding),
    );
  }

  /**
   * Returns the XML errors of the internal XML parser.
   *
   * @param bool $internalErrors
   *
   * @return array An array of errors
   */
  private function getXmlErrors($internalErrors) {
    $errors = array();
    foreach (libxml_get_errors() as $error) {
      $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)', LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR', $error->code, trim($error->message), $error->file ?: 'n/a', $error->line, $error->column);
    }
    libxml_clear_errors();
    libxml_use_internal_errors($internalErrors);
    return $errors;
  }

}

Classes

Namesort descending Description
XliffFileLoader XliffFileLoader loads translations from XLIFF files.