Allow config for different domain specific formatters

This commit is contained in:
Nyholm 2018-05-28 21:22:49 +02:00
parent b43fe21997
commit a325a443ed
9 changed files with 64 additions and 22 deletions

View File

@ -11,6 +11,7 @@ CHANGELOG
* Deprecated the `Symfony\Bundle\FrameworkBundle\Controller\Controller` class in favor of `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`.
* Enabled autoconfiguration for `Psr\Log\LoggerAwareInterface`
* Added new "auto" mode for `framework.session.cookie_secure` to turn it on when HTTPS is used
* Added support for configuring the `Translator` with multiple formatters.
4.1.0
-----

View File

@ -690,6 +690,7 @@ class Configuration implements ConfigurationInterface
->{!class_exists(FullStack::class) && class_exists(Translator::class) ? 'canBeDisabled' : 'canBeEnabled'}()
->fixXmlConfig('fallback')
->fixXmlConfig('path')
->fixXmlConfig('domain_formatter')
->children()
->arrayNode('fallbacks')
->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end()
@ -697,7 +698,19 @@ class Configuration implements ConfigurationInterface
->defaultValue(array('en'))
->end()
->booleanNode('logging')->defaultValue(false)->end()
->scalarNode('formatter')->defaultValue('translator.formatter.default')->end()
->scalarNode('formatter')
->info('The default formatter to use if none is specified.')
->defaultValue('translator.formatter.default')
->end()
->arrayNode('domain_formatters')
->info('Configure different formatters per domain.')
->useAttributeAsKey('domain')
->prototype('array')
->children()
->scalarNode('service')->cannotBeEmpty()->end()
->end()
->end()
->end()
->scalarNode('default_path')
->info('The default path used to load translations')
->defaultValue('%kernel.project_dir%/translations')

View File

@ -981,6 +981,9 @@ class FrameworkExtension extends Extension
$container->setAlias('translator.formatter', new Alias($config['formatter'], false));
$translator = $container->findDefinition('translator.default');
$translator->addMethodCall('setFallbackLocales', array($config['fallbacks']));
foreach ($config['domain_formatters'] as $formatter) {
$translator->addMethodCall('addFormatter', array($formatter['domain'], new Reference($formatter['service'])));
}
$container->setParameter('translator.logging', $config['logging']);
$container->setParameter('translator.default_path', $config['default_path']);

View File

@ -185,6 +185,7 @@
<xsd:sequence>
<xsd:element name="fallback" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="path" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="domain-formatter" type="translator_formatter" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="fallback" type="xsd:string" />
@ -192,6 +193,11 @@
<xsd:attribute name="formatter" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="translator_formatter">
<xsd:attribute name="domain" type="xsd:string" use="required" />
<xsd:attribute name="service" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="validation">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="static-method" type="xsd:string" />

View File

@ -7,6 +7,8 @@ CHANGELOG
* Started using ICU parent locales as fallback locales.
* deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`
* deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead
* Added intl message formatter.
* Added support for one formatter per domain
4.1.0
-----
@ -41,7 +43,6 @@ CHANGELOG
-----
* Added support for escaping `|` in plural translations with double pipe.
* Added intl message formatter.
3.1.0
-----

View File

@ -22,13 +22,17 @@ class IntlMessageFormatter implements MessageFormatterInterface, ChoiceMessageFo
*/
public function format($message, $locale, array $parameters = array())
{
$formatter = new \MessageFormatter($locale, $message);
try {
$formatter = new \MessageFormatter($locale, $message);
} catch (\Throwable $e) {
throw new \InvalidArgumentException('Invalid message format.', $e);
}
if (null === $formatter) {
throw new \InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code()));
}
$message = $formatter->format($parameters);
if ($formatter->getErrorCode() !== U_ZERO_ERROR) {
if (U_ZERO_ERROR !== $formatter->getErrorCode()) {
throw new \InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode()));
}

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Translation\Tests\Formatter;
use Symfony\Component\Translation\Formatter\IntlMessageFormatter;
class IntlMessageFormatterTest extends \PHPUnit_Framework_TestCase
class IntlMessageFormatterTest extends \PHPUnit\Framework\TestCase
{
public function setUp()
{
@ -34,7 +34,7 @@ class IntlMessageFormatterTest extends \PHPUnit_Framework_TestCase
public function testFormatWithNamedArguments()
{
if (PHP_VERSION_ID < 50500 || version_compare(INTL_ICU_VERSION, '4.8', '<')) {
if (version_compare(INTL_ICU_VERSION, '4.8', '<')) {
$this->markTestSkipped('Format with named arguments can only be run with ICU 4.8 or higher and PHP >= 5.5');
}

View File

@ -12,6 +12,8 @@
namespace Symfony\Component\Translation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Translator;
@ -567,6 +569,30 @@ class TranslatorTest extends TestCase
// unchanged if it can't be found
$this->assertEquals('some_message2', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
}
public function testDomainSpecificFormatter()
{
$fooFormatter = $this->getMockBuilder(MessageFormatterInterface::class)
->setMethods(array('format'))
->getMock();
$fooFormatter->expects($this->exactly(2))
->method('format')
->with('foo', 'en', array());
$barFormatter = $this->getMockBuilder(MessageFormatterInterface::class)
->setMethods(array('format'))
->getMock();
$barFormatter->expects($this->exactly(1))
->method('format')
->with('bar', 'en', array());
$translator = new Translator('en', $fooFormatter);
$translator->addFormatter('bar_domain', $barFormatter);
$translator->trans('foo');
$translator->trans('foo', array(), 'foo_domain');
$translator->trans('bar', array(), 'bar_domain');
}
}
class StringClass

View File

@ -89,7 +89,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
$formatter = new MessageFormatter();
}
$this->formatters['default'] = $formatter;
$this->formatters['_default'] = $formatter;
$this->cacheDir = $cacheDir;
$this->debug = $debug;
}
@ -137,11 +137,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
}
}
/**
* @param string $domain
* @param MessageFormatterInterface $formatter
*/
public function addFormatter(string $domain, MessageFormatterInterface $formatter)
public function addFormatter(string $domain, MessageFormatterInterface $formatter): void
{
$this->formatters[$domain] = $formatter;
}
@ -470,16 +466,8 @@ EOF
return $this->configCacheFactory;
}
/**
* @param string $domain
* @return MessageFormatterInterface
*/
private function getFormatter(string $domain)
private function getFormatter(string $domain): MessageFormatterInterface
{
if (isset($this->formatters[$domain])) {
return $this->formatters[$domain];
}
return $this->formatters['default'];
return $this->formatters[$domain] ?? $this->formatters['_default'];
}
}