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 ;
2014-06-21 22:28:07 +01:00
use Symfony\Component\Config\ConfigCache ;
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
*/
2014-05-10 23:14:12 +01:00
class Translator implements TranslatorInterface , TranslatorBagInterface
2010-09-27 08:45:29 +01:00
{
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
2014-07-11 12:30:03 +01:00
/**
* @ var string
*/
private $cacheDir ;
/**
* @ var bool
*/
private $debug ;
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
2014-07-11 12:30:03 +01:00
* @ param string | null $cacheDir The directory to use for the cache
* @ param bool $debug Use cache in debug mode ?
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
*/
2014-07-11 12:30:03 +01:00
public function __construct ( $locale , MessageSelector $selector = null , $cacheDir = null , $debug = false )
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 ();
2014-07-11 12:30:03 +01:00
$this -> cacheDir = $cacheDir ;
$this -> debug = $debug ;
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
*
2014-11-29 11:23:49 +00:00
* @ deprecated Deprecated since version 2.3 , to be removed in 3.0 . Use setFallbackLocales () instead .
2013-02-17 17:30:02 +00:00
*
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
{
2014-12-21 11:39:54 +00:00
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 );
2014-11-29 11:23:49 +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
}
2014-05-10 23:14:12 +01:00
/**
* { @ inheritdoc }
*/
public function getCatalogue ( $locale = null )
{
if ( null === $locale ) {
$locale = $this -> getLocale ();
}
if ( ! isset ( $this -> catalogues [ $locale ])) {
$this -> loadCatalogue ( $locale );
}
return $this -> catalogues [ $locale ];
}
2013-09-10 18:47:19 +01:00
/**
* Gets the loaders .
*
* @ return array LoaderInterface []
*/
protected function getLoaders ()
{
return $this -> loaders ;
}
2013-07-26 10:16:23 +01:00
/**
* Collects all messages for the given locale .
*
* @ param string | null $locale Locale of translations , by default is current locale
*
2014-08-27 13:56:02 +01:00
* @ return array [ array ] indexed by catalog
2013-07-26 10:16:23 +01:00
*/
public function getMessages ( $locale = null )
{
if ( null === $locale ) {
$locale = $this -> getLocale ();
}
if ( ! isset ( $this -> catalogues [ $locale ])) {
$this -> loadCatalogue ( $locale );
}
$catalogues = array ();
$catalogues [] = $catalogue = $this -> catalogues [ $locale ];
while ( $catalogue = $catalogue -> getFallbackCatalogue ()) {
$catalogues [] = $catalogue ;
}
$messages = array ();
for ( $i = count ( $catalogues ) - 1 ; $i >= 0 ; $i -- ) {
$localeMessages = $catalogues [ $i ] -> all ();
$messages = array_replace_recursive ( $messages , $localeMessages );
}
return $messages ;
}
2014-06-21 22:28:07 +01:00
/*
* @ param string $locale
*/
2011-03-09 09:24:16 +00:00
protected function loadCatalogue ( $locale )
2014-06-21 22:28:07 +01:00
{
2014-07-11 12:30:03 +01:00
if ( null === $this -> cacheDir ) {
2014-06-21 22:28:07 +01:00
$this -> initializeCatalogue ( $locale );
} else {
$this -> initializeCacheCatalogue ( $locale );
}
}
/**
* @ param string $locale
*/
protected function initializeCatalogue ( $locale )
2011-09-15 07:19:52 +01:00
{
2014-07-11 12:30:03 +01:00
$this -> assertValidLocale ( $locale );
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
}
2014-06-21 22:28:07 +01:00
/**
* @ param string $locale
*/
private function initializeCacheCatalogue ( $locale )
{
if ( isset ( $this -> catalogues [ $locale ])) {
return ;
}
2014-07-11 12:30:03 +01:00
if ( null === $this -> cacheDir ) {
2014-06-21 22:28:07 +01:00
$this -> initialize ();
2014-07-11 12:30:03 +01:00
return $this -> loadCatalogue ( $locale );
2014-06-21 22:28:07 +01:00
}
2014-07-11 12:30:03 +01:00
$this -> assertValidLocale ( $locale );
$cache = new ConfigCache ( $this -> cacheDir . '/catalogue.' . $locale . '.php' , $this -> debug );
2014-06-21 22:28:07 +01:00
if ( ! $cache -> isFresh ()) {
2014-07-11 12:30:03 +01:00
$this -> initializeCatalogue ( $locale );
2014-06-21 22:28:07 +01:00
$fallbackContent = '' ;
$current = '' ;
$replacementPattern = '/[^a-z0-9_]/i' ;
foreach ( $this -> computeFallbackLocales ( $locale ) as $fallback ) {
$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 ( $this -> catalogues [ $fallback ] -> all (), true ),
$currentSuffix ,
$fallbackSuffix
);
$current = $fallback ;
}
$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 ());
return ;
}
$this -> catalogues [ $locale ] = include $cache ;
}
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
*/
2014-07-25 21:18:02 +01:00
protected function assertValidLocale ( $locale )
2014-07-04 18:20:43 +01:00
{
2014-07-22 22:54:07 +01:00
if ( 1 !== preg_match ( '/^[a-z0-9@_\\.\\-]*$/i' , $locale )) {
2014-07-24 16:02:45 +01:00
throw new \InvalidArgumentException ( sprintf ( 'Invalid "%s" locale.' , $locale ));
2014-07-04 18:20:43 +01:00
}
}
2010-09-27 08:45:29 +01:00
}