You are here

class XliffFileLoader in Plug 7

XliffFileLoader loads translations from XLIFF files.

@author Fabien Potencier <fabien@symfony.com>

@api

Hierarchy

Expanded class hierarchy of XliffFileLoader

1 file declares its use of XliffFileLoader
XliffFileLoaderTest.php in lib/Symfony/translation/Tests/Loader/XliffFileLoaderTest.php
1 string reference to 'XliffFileLoader'
TranslatorTest::getTransFileTests in lib/Symfony/translation/Tests/TranslatorTest.php

File

lib/Symfony/translation/Loader/XliffFileLoader.php, line 27

Namespace

Symfony\Component\Translation\Loader
View source
class XliffFileLoader implements LoaderInterface {

  /**
   * {@inheritdoc}
   *
   * @api
   */
  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)) || !isset($translation->target)) {
        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) $translation->target, $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;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
XliffFileLoader::getXmlErrors private function Returns the XML errors of the internal XML parser.
XliffFileLoader::load public function @api Overrides LoaderInterface::load
XliffFileLoader::parseFile private function Validates and parses the given file into a SimpleXMLElement.
XliffFileLoader::utf8ToCharset private function Convert a UTF8 string to the specified encoding.