2010-09-27 08:45:29 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2011-01-15 13:29:43 +00:00
|
|
|
* This file is part of the Symfony package.
|
2010-09-27 08:45:29 +01:00
|
|
|
*
|
2011-03-06 11:40:06 +00:00
|
|
|
* (c) Fabien Potencier <fabien@symfony.com>
|
2010-09-27 08:45:29 +01:00
|
|
|
*
|
2011-01-15 13:29:43 +00:00
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
|
|
|
|
2011-01-15 13:29:43 +00:00
|
|
|
namespace Symfony\Component\Translation;
|
|
|
|
|
|
|
|
use Symfony\Component\Translation\Loader\LoaderInterface;
|
2012-12-13 17:37:08 +00:00
|
|
|
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
2011-01-15 13:29:43 +00:00
|
|
|
|
2010-09-27 08:45:29 +01:00
|
|
|
/**
|
|
|
|
* Translator.
|
|
|
|
*
|
2011-03-06 11:40:06 +00:00
|
|
|
* @author Fabien Potencier <fabien@symfony.com>
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
|
|
|
class Translator implements TranslatorInterface
|
|
|
|
{
|
2012-11-01 15:08:59 +00:00
|
|
|
/**
|
|
|
|
* @var MessageCatalogueInterface[]
|
|
|
|
*/
|
|
|
|
protected $catalogues = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
2011-03-09 09:24:16 +00:00
|
|
|
protected $locale;
|
2012-11-01 15:08:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $fallbackLocales = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var LoaderInterface[]
|
|
|
|
*/
|
|
|
|
private $loaders = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $resources = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var MessageSelector
|
|
|
|
*/
|
2011-03-08 19:47:32 +00:00
|
|
|
private $selector;
|
2010-09-27 08:45:29 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
2013-02-13 00:53:15 +00:00
|
|
|
* @param string $locale The locale
|
|
|
|
* @param MessageSelector|null $selector The message selector for pluralization
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
2014-07-04 18:20:43 +01:00
|
|
|
* @throws \InvalidArgumentException If a locale contains invalid characters
|
|
|
|
*
|
2011-03-24 08:07:52 +00:00
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
2011-10-23 13:08:03 +01:00
|
|
|
public function __construct($locale, MessageSelector $selector = null)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
2014-07-04 18:20:43 +01:00
|
|
|
$this->setLocale($locale);
|
2013-02-13 00:53:15 +00:00
|
|
|
$this->selector = $selector ?: new MessageSelector();
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a Loader.
|
|
|
|
*
|
|
|
|
* @param string $format The name of the loader (@see addResource())
|
|
|
|
* @param LoaderInterface $loader A LoaderInterface instance
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
|
|
|
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
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
2014-07-04 18:20:43 +01:00
|
|
|
* @throws \InvalidArgumentException If the locale contains invalid characters
|
|
|
|
*
|
2011-03-24 08:07:52 +00:00
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
2013-05-03 07:41:16 +01:00
|
|
|
public function addResource($format, $resource, $locale, $domain = null)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
2013-05-03 07:41:16 +01:00
|
|
|
if (null === $domain) {
|
|
|
|
$domain = 'messages';
|
|
|
|
}
|
|
|
|
|
2014-07-04 18:20:43 +01:00
|
|
|
$this->assertValidLocale($locale);
|
|
|
|
|
2010-09-27 08:45:29 +01:00
|
|
|
$this->resources[$locale][] = array($format, $resource, $domain);
|
2012-10-03 11:03:29 +01:00
|
|
|
|
2013-05-10 17:49:00 +01:00
|
|
|
if (in_array($locale, $this->fallbackLocales)) {
|
2013-04-23 17:01:41 +01:00
|
|
|
$this->catalogues = array();
|
|
|
|
} else {
|
|
|
|
unset($this->catalogues[$locale]);
|
2013-04-23 15:03:00 +01:00
|
|
|
}
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
|
|
|
public function setLocale($locale)
|
|
|
|
{
|
2014-07-04 18:20:43 +01:00
|
|
|
$this->assertValidLocale($locale);
|
2010-09-27 08:45:29 +01:00
|
|
|
$this->locale = $locale;
|
|
|
|
}
|
|
|
|
|
2010-10-06 13:18:36 +01:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
|
|
|
* @api
|
2010-10-06 13:18:36 +01:00
|
|
|
*/
|
|
|
|
public function getLocale()
|
|
|
|
{
|
|
|
|
return $this->locale;
|
|
|
|
}
|
|
|
|
|
2010-09-27 08:45:29 +01:00
|
|
|
/**
|
2011-09-15 07:19:52 +01:00
|
|
|
* Sets the fallback locale(s).
|
2010-09-27 08:45:29 +01:00
|
|
|
*
|
2012-01-11 14:52:51 +00:00
|
|
|
* @param string|array $locales The fallback locale(s)
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
2014-07-04 18:20:43 +01:00
|
|
|
* @throws \InvalidArgumentException If a locale contains invalid characters
|
|
|
|
*
|
2013-02-17 17:30:02 +00:00
|
|
|
* @deprecated since 2.3, to be removed in 3.0. Use setFallbackLocales() instead.
|
|
|
|
*
|
2011-03-24 08:07:52 +00:00
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
2011-09-15 07:19:52 +01:00
|
|
|
public function setFallbackLocale($locales)
|
2013-02-17 17:30:02 +00:00
|
|
|
{
|
2013-03-06 21:28:09 +00:00
|
|
|
$this->setFallbackLocales(is_array($locales) ? $locales : array($locales));
|
2013-02-17 17:30:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the fallback locales.
|
|
|
|
*
|
|
|
|
* @param array $locales The fallback locales
|
|
|
|
*
|
2014-07-04 18:20:43 +01:00
|
|
|
* @throws \InvalidArgumentException If a locale contains invalid characters
|
|
|
|
*
|
2013-02-17 17:30:02 +00:00
|
|
|
* @api
|
|
|
|
*/
|
|
|
|
public function setFallbackLocales(array $locales)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
2011-09-15 07:19:52 +01:00
|
|
|
// needed as the fallback locales are linked to the already loaded catalogues
|
2010-10-31 21:33:08 +00:00
|
|
|
$this->catalogues = array();
|
2010-09-27 08:45:29 +01:00
|
|
|
|
2014-07-04 18:20:43 +01:00
|
|
|
foreach ($locales as $locale) {
|
|
|
|
$this->assertValidLocale($locale);
|
|
|
|
}
|
|
|
|
|
2013-02-17 17:30:02 +00:00
|
|
|
$this->fallbackLocales = $locales;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the fallback locales.
|
|
|
|
*
|
|
|
|
* @return array $locales The fallback locales
|
|
|
|
*
|
|
|
|
* @api
|
|
|
|
*/
|
|
|
|
public function getFallbackLocales()
|
|
|
|
{
|
|
|
|
return $this->fallbackLocales;
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
2013-05-03 07:41:16 +01:00
|
|
|
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
2013-02-13 00:53:15 +00:00
|
|
|
if (null === $locale) {
|
2010-10-06 10:57:38 +01:00
|
|
|
$locale = $this->getLocale();
|
2014-07-04 18:20:43 +01:00
|
|
|
} else {
|
|
|
|
$this->assertValidLocale($locale);
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
2013-05-03 07:41:16 +01:00
|
|
|
if (null === $domain) {
|
|
|
|
$domain = 'messages';
|
|
|
|
}
|
|
|
|
|
2010-09-27 08:45:29 +01:00
|
|
|
if (!isset($this->catalogues[$locale])) {
|
|
|
|
$this->loadCatalogue($locale);
|
|
|
|
}
|
|
|
|
|
2011-04-24 08:39:28 +01:00
|
|
|
return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters);
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
2011-03-24 08:07:52 +00:00
|
|
|
*
|
|
|
|
* @api
|
2010-09-27 08:45:29 +01:00
|
|
|
*/
|
2013-05-03 07:41:16 +01:00
|
|
|
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
2013-02-13 00:53:15 +00:00
|
|
|
if (null === $locale) {
|
2010-10-06 10:57:38 +01:00
|
|
|
$locale = $this->getLocale();
|
2014-07-04 18:20:43 +01:00
|
|
|
} else {
|
|
|
|
$this->assertValidLocale($locale);
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
2013-05-03 07:41:16 +01:00
|
|
|
if (null === $domain) {
|
|
|
|
$domain = 'messages';
|
|
|
|
}
|
|
|
|
|
2010-09-27 08:45:29 +01:00
|
|
|
if (!isset($this->catalogues[$locale])) {
|
|
|
|
$this->loadCatalogue($locale);
|
|
|
|
}
|
|
|
|
|
2011-09-15 07:19:52 +01:00
|
|
|
$id = (string) $id;
|
|
|
|
|
2011-09-28 15:46:33 +01:00
|
|
|
$catalogue = $this->catalogues[$locale];
|
|
|
|
while (!$catalogue->defines($id, $domain)) {
|
|
|
|
if ($cat = $catalogue->getFallbackCatalogue()) {
|
|
|
|
$catalogue = $cat;
|
|
|
|
$locale = $catalogue->getLocale();
|
|
|
|
} else {
|
|
|
|
break;
|
2011-09-15 07:19:52 +01:00
|
|
|
}
|
2011-08-22 15:07:39 +01:00
|
|
|
}
|
|
|
|
|
2013-02-14 08:34:20 +00:00
|
|
|
return strtr($this->selector->choose($catalogue->get($id, $domain), (int) $number, $locale), $parameters);
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
|
2011-03-09 09:24:16 +00:00
|
|
|
protected function loadCatalogue($locale)
|
2011-09-15 07:19:52 +01:00
|
|
|
{
|
2012-12-13 17:37:08 +00:00
|
|
|
try {
|
|
|
|
$this->doLoadCatalogue($locale);
|
|
|
|
} catch (NotFoundResourceException $e) {
|
|
|
|
if (!$this->computeFallbackLocales($locale)) {
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
}
|
2011-09-16 12:27:17 +01:00
|
|
|
$this->loadFallbackCatalogues($locale);
|
2011-09-15 07:19:52 +01:00
|
|
|
}
|
|
|
|
|
2011-09-28 15:46:33 +01:00
|
|
|
private function doLoadCatalogue($locale)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
|
|
|
$this->catalogues[$locale] = new MessageCatalogue($locale);
|
|
|
|
|
2011-02-25 12:56:27 +00:00
|
|
|
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]));
|
|
|
|
}
|
2011-10-23 13:08:03 +01:00
|
|
|
$this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-16 12:27:17 +01:00
|
|
|
private function loadFallbackCatalogues($locale)
|
2010-09-27 08:45:29 +01:00
|
|
|
{
|
2011-09-15 07:19:52 +01:00
|
|
|
$current = $this->catalogues[$locale];
|
2011-09-28 15:08:31 +01:00
|
|
|
|
2011-09-15 07:19:52 +01:00
|
|
|
foreach ($this->computeFallbackLocales($locale) as $fallback) {
|
|
|
|
if (!isset($this->catalogues[$fallback])) {
|
|
|
|
$this->doLoadCatalogue($fallback);
|
|
|
|
}
|
2010-10-31 21:33:08 +00:00
|
|
|
|
2011-09-15 07:19:52 +01:00
|
|
|
$current->addFallbackCatalogue($this->catalogues[$fallback]);
|
|
|
|
$current = $this->catalogues[$fallback];
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|
|
|
|
}
|
2011-08-22 15:07:39 +01:00
|
|
|
|
2011-09-28 15:46:33 +01:00
|
|
|
protected function computeFallbackLocales($locale)
|
2011-08-22 15:07:39 +01:00
|
|
|
{
|
2011-09-20 06:50:47 +01:00
|
|
|
$locales = array();
|
|
|
|
foreach ($this->fallbackLocales as $fallback) {
|
|
|
|
if ($fallback === $locale) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$locales[] = $fallback;
|
|
|
|
}
|
2011-09-15 07:19:52 +01:00
|
|
|
|
2012-02-22 17:59:56 +00:00
|
|
|
if (strrchr($locale, '_') !== false) {
|
2011-09-15 07:19:52 +01:00
|
|
|
array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_'))));
|
2011-08-22 15:07:39 +01:00
|
|
|
}
|
2011-09-15 07:19:52 +01:00
|
|
|
|
2011-09-28 15:46:33 +01:00
|
|
|
return array_unique($locales);
|
2011-08-22 15:07:39 +01:00
|
|
|
}
|
2014-07-04 18:20:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
private function assertValidLocale($locale)
|
|
|
|
{
|
|
|
|
if (0 !== preg_match('/[^a-z0-9_\\.\\-]+/i', $locale, $match)) {
|
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid locale: %s.', $locale));
|
|
|
|
}
|
|
|
|
}
|
2010-09-27 08:45:29 +01:00
|
|
|
}
|