You are here

class Translator in Plug 7

Translator.

@author Fabien Potencier <fabien@symfony.com>

@api

Hierarchy

Expanded class hierarchy of Translator

4 files declare their use of Translator
DataCollectorTranslatorTest.php in lib/Symfony/translation/Tests/DataCollectorTranslatorTest.php
LoggingTranslatorTest.php in lib/Symfony/translation/Tests/LoggingTranslatorTest.php
TranslatorCacheTest.php in lib/Symfony/translation/Tests/TranslatorCacheTest.php
TranslatorTest.php in lib/Symfony/translation/Tests/TranslatorTest.php

File

lib/Symfony/translation/Translator.php, line 27

Namespace

Symfony\Component\Translation
View source
class Translator implements TranslatorInterface, TranslatorBagInterface {

  /**
   * @var MessageCatalogueInterface[]
   */
  protected $catalogues = array();

  /**
   * @var string
   */
  protected $locale;

  /**
   * @var array
   */
  private $fallbackLocales = array();

  /**
   * @var LoaderInterface[]
   */
  private $loaders = array();

  /**
   * @var array
   */
  private $resources = array();

  /**
   * @var MessageSelector
   */
  private $selector;

  /**
   * @var string
   */
  private $cacheDir;

  /**
   * @var bool
   */
  private $debug;

  /**
   * @var ConfigCacheFactoryInterface|null
   */
  private $configCacheFactory;

  /**
   * Constructor.
   *
   * @param string               $locale   The locale
   * @param MessageSelector|null $selector The message selector for pluralization
   * @param string|null          $cacheDir The directory to use for the cache
   * @param bool                 $debug    Use cache in debug mode ?
   *
   * @throws \InvalidArgumentException If a locale contains invalid characters
   *
   * @api
   */
  public function __construct($locale, MessageSelector $selector = null, $cacheDir = null, $debug = false) {
    $this
      ->setLocale($locale);
    $this->selector = $selector ?: new MessageSelector();
    $this->cacheDir = $cacheDir;
    $this->debug = $debug;
  }

  /**
   * Sets the ConfigCache factory to use.
   *
   * @param ConfigCacheFactoryInterface $configCacheFactory
   */
  public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory) {
    $this->configCacheFactory = $configCacheFactory;
  }

  /**
   * Adds a Loader.
   *
   * @param string          $format The name of the loader (@see addResource())
   * @param LoaderInterface $loader A LoaderInterface instance
   *
   * @api
   */
  public function addLoader($format, LoaderInterface $loader) {
    $this->loaders[$format] = $loader;
  }

  /**
   * Adds a Resource.
   *
   * @param string $format   The name of the loader (@see addLoader())
   * @param mixed  $resource The resource name
   * @param string $locale   The locale
   * @param string $domain   The domain
   *
   * @throws \InvalidArgumentException If the locale contains invalid characters
   *
   * @api
   */
  public function addResource($format, $resource, $locale, $domain = null) {
    if (null === $domain) {
      $domain = 'messages';
    }
    $this
      ->assertValidLocale($locale);
    $this->resources[$locale][] = array(
      $format,
      $resource,
      $domain,
    );
    if (in_array($locale, $this->fallbackLocales)) {
      $this->catalogues = array();
    }
    else {
      unset($this->catalogues[$locale]);
    }
  }

  /**
   * {@inheritdoc}
   *
   * @api
   */
  public function setLocale($locale) {
    $this
      ->assertValidLocale($locale);
    $this->locale = $locale;
  }

  /**
   * {@inheritdoc}
   *
   * @api
   */
  public function getLocale() {
    return $this->locale;
  }

  /**
   * Sets the fallback locale(s).
   *
   * @param string|array $locales The fallback locale(s)
   *
   * @throws \InvalidArgumentException If a locale contains invalid characters
   *
   * @deprecated since version 2.3, to be removed in 3.0. Use setFallbackLocales() instead.
   *
   * @api
   */
  public function setFallbackLocale($locales) {
    @trigger_error('The ' . __METHOD__ . ' method is deprecated since version 2.3 and will be removed in 3.0. Use the setFallbackLocales() method instead.', E_USER_DEPRECATED);
    $this
      ->setFallbackLocales(is_array($locales) ? $locales : array(
      $locales,
    ));
  }

  /**
   * Sets the fallback locales.
   *
   * @param array $locales The fallback locales
   *
   * @throws \InvalidArgumentException If a locale contains invalid characters
   *
   * @api
   */
  public function setFallbackLocales(array $locales) {

    // needed as the fallback locales are linked to the already loaded catalogues
    $this->catalogues = array();
    foreach ($locales as $locale) {
      $this
        ->assertValidLocale($locale);
    }
    $this->fallbackLocales = $locales;
  }

  /**
   * Gets the fallback locales.
   *
   * @return array $locales The fallback locales
   *
   * @api
   */
  public function getFallbackLocales() {
    return $this->fallbackLocales;
  }

  /**
   * {@inheritdoc}
   *
   * @api
   */
  public function trans($id, array $parameters = array(), $domain = null, $locale = null) {
    if (null === $domain) {
      $domain = 'messages';
    }
    return strtr($this
      ->getCatalogue($locale)
      ->get((string) $id, $domain), $parameters);
  }

  /**
   * {@inheritdoc}
   *
   * @api
   */
  public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) {
    if (null === $domain) {
      $domain = 'messages';
    }
    $id = (string) $id;
    $catalogue = $this
      ->getCatalogue($locale);
    $locale = $catalogue
      ->getLocale();
    while (!$catalogue
      ->defines($id, $domain)) {
      if ($cat = $catalogue
        ->getFallbackCatalogue()) {
        $catalogue = $cat;
        $locale = $catalogue
          ->getLocale();
      }
      else {
        break;
      }
    }
    return strtr($this->selector
      ->choose($catalogue
      ->get($id, $domain), (int) $number, $locale), $parameters);
  }

  /**
   * {@inheritdoc}
   */
  public function getCatalogue($locale = null) {
    if (null === $locale) {
      $locale = $this
        ->getLocale();
    }
    else {
      $this
        ->assertValidLocale($locale);
    }
    if (!isset($this->catalogues[$locale])) {
      $this
        ->loadCatalogue($locale);
    }
    return $this->catalogues[$locale];
  }

  /**
   * Gets the loaders.
   *
   * @return array LoaderInterface[]
   */
  protected function getLoaders() {
    return $this->loaders;
  }

  /**
   * Collects all messages for the given locale.
   *
   * @param string|null $locale Locale of translations, by default is current locale
   *
   * @return array[array] indexed by catalog
   *
   * @deprecated since version 2.8, to be removed in 3.0. Use TranslatorBagInterface::getCatalogue() method instead.
   */
  public function getMessages($locale = null) {
    @trigger_error('The ' . __METHOD__ . ' method is deprecated since version 2.8 and will be removed in 3.0. Use TranslatorBagInterface::getCatalogue() method instead.', E_USER_DEPRECATED);
    $catalogue = $this
      ->getCatalogue($locale);
    $messages = $catalogue
      ->all();
    while ($catalogue = $catalogue
      ->getFallbackCatalogue()) {
      $messages = array_replace_recursive($catalogue
        ->all(), $messages);
    }
    return $messages;
  }

  /**
   * @param string $locale
   */
  protected function loadCatalogue($locale) {
    if (null === $this->cacheDir) {
      $this
        ->initializeCatalogue($locale);
    }
    else {
      $this
        ->initializeCacheCatalogue($locale);
    }
  }

  /**
   * @param string $locale
   */
  protected function initializeCatalogue($locale) {
    $this
      ->assertValidLocale($locale);
    try {
      $this
        ->doLoadCatalogue($locale);
    } catch (NotFoundResourceException $e) {
      if (!$this
        ->computeFallbackLocales($locale)) {
        throw $e;
      }
    }
    $this
      ->loadFallbackCatalogues($locale);
  }

  /**
   * @param string $locale
   */
  private function initializeCacheCatalogue($locale) {
    if (isset($this->catalogues[$locale])) {

      /* Catalogue already initialized. */
      return;
    }
    $this
      ->assertValidLocale($locale);
    $self = $this;

    // required for PHP 5.3 where "$this" cannot be use()d in anonymous functions. Change in Symfony 3.0.
    $cache = $this
      ->getConfigCacheFactory()
      ->cache($this
      ->getCatalogueCachePath($locale), function (ConfigCacheInterface $cache) use ($self, $locale) {
      $self
        ->dumpCatalogue($locale, $cache);
    });
    if (isset($this->catalogues[$locale])) {

      /* Catalogue has been initialized as it was written out to cache. */
      return;
    }

    /* Read catalogue from cache. */
    $this->catalogues[$locale] = (include $cache
      ->getPath());
  }

  /**
   * This method is public because it needs to be callable from a closure in PHP 5.3. It should be made protected (or even private, if possible) in 3.0.
   *
   * @internal
   */
  public function dumpCatalogue($locale, ConfigCacheInterface $cache) {
    $this
      ->initializeCatalogue($locale);
    $fallbackContent = $this
      ->getFallbackContent($this->catalogues[$locale]);
    $content = sprintf(<<<EOF
<?php

use Symfony\\Component\\Translation\\MessageCatalogue;

\$catalogue = new MessageCatalogue('%s', %s);

%s
return \$catalogue;

EOF
, $locale, var_export($this->catalogues[$locale]
      ->all(), true), $fallbackContent);
    $cache
      ->write($content, $this->catalogues[$locale]
      ->getResources());
  }
  private function getFallbackContent(MessageCatalogue $catalogue) {
    $fallbackContent = '';
    $current = '';
    $replacementPattern = '/[^a-z0-9_]/i';
    $fallbackCatalogue = $catalogue
      ->getFallbackCatalogue();
    while ($fallbackCatalogue) {
      $fallback = $fallbackCatalogue
        ->getLocale();
      $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback));
      $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current));
      $fallbackContent .= sprintf(<<<EOF
\$catalogue%s = new MessageCatalogue('%s', %s);
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);

EOF
, $fallbackSuffix, $fallback, var_export($fallbackCatalogue
        ->all(), true), $currentSuffix, $fallbackSuffix);
      $current = $fallbackCatalogue
        ->getLocale();
      $fallbackCatalogue = $fallbackCatalogue
        ->getFallbackCatalogue();
    }
    return $fallbackContent;
  }
  private function getCatalogueCachePath($locale) {
    return $this->cacheDir . '/catalogue.' . $locale . '.' . sha1(serialize($this->fallbackLocales)) . '.php';
  }
  private function doLoadCatalogue($locale) {
    $this->catalogues[$locale] = new MessageCatalogue($locale);
    if (isset($this->resources[$locale])) {
      foreach ($this->resources[$locale] as $resource) {
        if (!isset($this->loaders[$resource[0]])) {
          throw new \RuntimeException(sprintf('The "%s" translation loader is not registered.', $resource[0]));
        }
        $this->catalogues[$locale]
          ->addCatalogue($this->loaders[$resource[0]]
          ->load($resource[1], $locale, $resource[2]));
      }
    }
  }
  private function loadFallbackCatalogues($locale) {
    $current = $this->catalogues[$locale];
    foreach ($this
      ->computeFallbackLocales($locale) as $fallback) {
      if (!isset($this->catalogues[$fallback])) {
        $this
          ->doLoadCatalogue($fallback);
      }
      $current
        ->addFallbackCatalogue($this->catalogues[$fallback]);
      $current = $this->catalogues[$fallback];
    }
  }
  protected function computeFallbackLocales($locale) {
    $locales = array();
    foreach ($this->fallbackLocales as $fallback) {
      if ($fallback === $locale) {
        continue;
      }
      $locales[] = $fallback;
    }
    if (strrchr($locale, '_') !== false) {
      array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_'))));
    }
    return array_unique($locales);
  }

  /**
   * Asserts that the locale is valid, throws an Exception if not.
   *
   * @param string $locale Locale to tests
   *
   * @throws \InvalidArgumentException If the locale contains invalid characters
   */
  protected function assertValidLocale($locale) {
    if (1 !== preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) {
      throw new \InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale));
    }
  }

  /**
   * Provides the ConfigCache factory implementation, falling back to a
   * default implementation if necessary.
   *
   * @return ConfigCacheFactoryInterface $configCacheFactory
   */
  private function getConfigCacheFactory() {
    if (!$this->configCacheFactory) {
      $this->configCacheFactory = new ConfigCacheFactory($this->debug);
    }
    return $this->configCacheFactory;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Translator::$cacheDir private property
Translator::$catalogues protected property
Translator::$configCacheFactory private property
Translator::$debug private property
Translator::$fallbackLocales private property
Translator::$loaders private property
Translator::$locale protected property
Translator::$resources private property
Translator::$selector private property
Translator::addLoader public function Adds a Loader.
Translator::addResource public function Adds a Resource.
Translator::assertValidLocale protected function Asserts that the locale is valid, throws an Exception if not.
Translator::computeFallbackLocales protected function
Translator::doLoadCatalogue private function
Translator::dumpCatalogue public function This method is public because it needs to be callable from a closure in PHP 5.3. It should be made protected (or even private, if possible) in 3.0.
Translator::getCatalogue public function Gets the catalogue by locale. Overrides TranslatorBagInterface::getCatalogue
Translator::getCatalogueCachePath private function
Translator::getConfigCacheFactory private function Provides the ConfigCache factory implementation, falling back to a default implementation if necessary.
Translator::getFallbackContent private function
Translator::getFallbackLocales public function Gets the fallback locales.
Translator::getLoaders protected function Gets the loaders.
Translator::getLocale public function @api Overrides TranslatorInterface::getLocale
Translator::getMessages Deprecated public function Collects all messages for the given locale.
Translator::initializeCacheCatalogue private function
Translator::initializeCatalogue protected function
Translator::loadCatalogue protected function
Translator::loadFallbackCatalogues private function
Translator::setConfigCacheFactory public function Sets the ConfigCache factory to use.
Translator::setFallbackLocale Deprecated public function Sets the fallback locale(s).
Translator::setFallbackLocales public function Sets the fallback locales.
Translator::setLocale public function @api Overrides TranslatorInterface::setLocale
Translator::trans public function @api Overrides TranslatorInterface::trans
Translator::transChoice public function @api Overrides TranslatorInterface::transChoice
Translator::__construct public function Constructor.