diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index bebeb8d9..c3c89dea 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -52,10 +52,11 @@ public function getDependencyConfig() Geography\CountryCodeListInterface::class => Geography\DefaultCountryCodeList::class, ], 'factories' => [ - Translator\TranslatorInterface::class => Translator\TranslatorServiceFactory::class, - Translator\LoaderPluginManager::class => Translator\LoaderPluginManagerFactory::class, - Translator\PlaceholderPluginManager::class => Translator\PlaceholderPluginManagerFactory::class, - Geography\DefaultCountryCodeList::class => [Geography\DefaultCountryCodeList::class, 'create'], + Translator\TranslatorInterface::class => Translator\TranslatorServiceFactory::class, + Translator\LoaderPluginManager::class => Translator\LoaderPluginManagerFactory::class, + Translator\FormatterPluginManager::class => Translator\FormatterPluginManagerFactory::class, + Translator\TranslatorFormatterDecorator::class => Translator\TranslatorFormatterDecoratorFactory::class, + Geography\DefaultCountryCodeList::class => [Geography\DefaultCountryCodeList::class, 'create'], ], ]; } diff --git a/src/Translator/Formatter/FormatterInterface.php b/src/Translator/Formatter/FormatterInterface.php new file mode 100644 index 00000000..f7b62b66 --- /dev/null +++ b/src/Translator/Formatter/FormatterInterface.php @@ -0,0 +1,13 @@ + $placeholders + */ + public function format(string $locale, string $message, iterable $placeholders = []): string; +} diff --git a/src/Translator/Placeholder/HandlebarPlaceholder.php b/src/Translator/Formatter/HandlebarFormatter.php similarity index 56% rename from src/Translator/Placeholder/HandlebarPlaceholder.php rename to src/Translator/Formatter/HandlebarFormatter.php index bbcac635..8fe33e00 100644 --- a/src/Translator/Placeholder/HandlebarPlaceholder.php +++ b/src/Translator/Formatter/HandlebarFormatter.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Laminas\I18n\Translator\Placeholder; +namespace Laminas\I18n\Translator\Formatter; use function str_replace; -class HandlebarPlaceholder implements PlaceholderInterface +class HandlebarFormatter implements FormatterInterface { - public function compile(string $locale, string $message, iterable $placeholders = []): string + public function format(string $locale, string $message, iterable $placeholders = []): string { $compiled = $message; foreach ($placeholders as $key => $value) { diff --git a/src/Translator/Placeholder/IcuPlaceholder.php b/src/Translator/Formatter/IcuFormatter.php similarity index 62% rename from src/Translator/Placeholder/IcuPlaceholder.php rename to src/Translator/Formatter/IcuFormatter.php index d0f6609b..f45e1d25 100644 --- a/src/Translator/Placeholder/IcuPlaceholder.php +++ b/src/Translator/Formatter/IcuFormatter.php @@ -2,16 +2,16 @@ declare(strict_types=1); -namespace Laminas\I18n\Translator\Placeholder; +namespace Laminas\I18n\Translator\Formatter; use MessageFormatter; use Traversable; use function iterator_to_array; -class IcuPlaceholder implements PlaceholderInterface +class IcuFormatter implements FormatterInterface { - public function compile(string $locale, string $message, iterable $placeholders = []): string + public function format(string $locale, string $message, iterable $placeholders = []): string { if ($placeholders instanceof Traversable) { $placeholders = iterator_to_array($placeholders); diff --git a/src/Translator/Placeholder/PrintfPlaceholder.php b/src/Translator/Formatter/PrintfFormatter.php similarity index 76% rename from src/Translator/Placeholder/PrintfPlaceholder.php rename to src/Translator/Formatter/PrintfFormatter.php index 7e32c64a..95058234 100644 --- a/src/Translator/Placeholder/PrintfPlaceholder.php +++ b/src/Translator/Formatter/PrintfFormatter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Laminas\I18n\Translator\Placeholder; +namespace Laminas\I18n\Translator\Formatter; use Laminas\I18n\Exception\ParseException; use Traversable; @@ -10,9 +10,9 @@ use function call_user_func_array; use function iterator_to_array; -class PrintfPlaceholder implements PlaceholderInterface +class PrintfFormatter implements FormatterInterface { - public function compile(string $locale, string $message, iterable $placeholders = []): string + public function format(string $locale, string $message, iterable $placeholders = []): string { if ($placeholders instanceof Traversable) { $placeholders = iterator_to_array($placeholders); diff --git a/src/Translator/Placeholder/SegmentPlaceholder.php b/src/Translator/Formatter/SegmentFormatter.php similarity index 89% rename from src/Translator/Placeholder/SegmentPlaceholder.php rename to src/Translator/Formatter/SegmentFormatter.php index cc96cfe8..f8138e78 100644 --- a/src/Translator/Placeholder/SegmentPlaceholder.php +++ b/src/Translator/Formatter/SegmentFormatter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Laminas\I18n\Translator\Placeholder; +namespace Laminas\I18n\Translator\Formatter; use Laminas\I18n\Exception\InvalidArgumentException; use Laminas\I18n\Exception\ParseException; @@ -17,9 +17,9 @@ use function ucfirst; use function uksort; -class SegmentPlaceholder implements PlaceholderInterface +class SegmentFormatter implements FormatterInterface { - public function compile(string $locale, string $message, iterable $placeholders = []): string + public function format(string $locale, string $message, iterable $placeholders = []): string { if ($placeholders instanceof Traversable) { $placeholders = iterator_to_array($placeholders); diff --git a/src/Translator/PlaceholderPluginManager.php b/src/Translator/FormatterPluginManager.php similarity index 54% rename from src/Translator/PlaceholderPluginManager.php rename to src/Translator/FormatterPluginManager.php index 802bb372..3484be16 100644 --- a/src/Translator/PlaceholderPluginManager.php +++ b/src/Translator/FormatterPluginManager.php @@ -19,31 +19,31 @@ * Placeholder\PlaceholderInterface. Additionally, it registers a number * of default placeholder compilers. * - * @template InstanceType of Placeholder\PlaceholderInterface + * @template InstanceType of Formatter\FormatterInterface * @extends AbstractPluginManager - * @method Placeholder\PlaceholderInterface get(string $name, ?array $options = null) + * @method Formatter\FormatterInterface get(string $name, ?array $options = null) */ -class PlaceholderPluginManager extends AbstractPluginManager +class FormatterPluginManager extends AbstractPluginManager { /** @inheritDoc */ protected $aliases = [ - 'segment' => Placeholder\SegmentPlaceholder::class, - 'colon' => Placeholder\SegmentPlaceholder::class, - 'laravel' => Placeholder\SegmentPlaceholder::class, - 'handlebar' => Placeholder\HandlebarPlaceholder::class, - 'handlebars' => Placeholder\HandlebarPlaceholder::class, - 'icu' => Placeholder\IcuPlaceholder::class, - 'vsprintf' => Placeholder\PrintfPlaceholder::class, - 'sprintf' => Placeholder\PrintfPlaceholder::class, - 'printf' => Placeholder\PrintfPlaceholder::class, + 'segment' => Formatter\SegmentFormatter::class, + 'colon' => Formatter\SegmentFormatter::class, + 'laravel' => Formatter\SegmentFormatter::class, + 'handlebar' => Formatter\HandlebarFormatter::class, + 'handlebars' => Formatter\HandlebarFormatter::class, + 'icu' => Formatter\IcuFormatter::class, + 'vsprintf' => Formatter\PrintfFormatter::class, + 'sprintf' => Formatter\PrintfFormatter::class, + 'printf' => Formatter\PrintfFormatter::class, ]; /** @inheritDoc */ protected $factories = [ - Placeholder\SegmentPlaceholder::class => InvokableFactory::class, - Placeholder\HandlebarPlaceholder::class => InvokableFactory::class, - Placeholder\IcuPlaceholder::class => InvokableFactory::class, - Placeholder\PrintfPlaceholder::class => InvokableFactory::class, + Formatter\SegmentFormatter::class => InvokableFactory::class, + Formatter\HandlebarFormatter::class => InvokableFactory::class, + Formatter\IcuFormatter::class => InvokableFactory::class, + Formatter\PrintfFormatter::class => InvokableFactory::class, ]; /** @@ -57,7 +57,7 @@ class PlaceholderPluginManager extends AbstractPluginManager */ public function validate(mixed $instance): void { - if ($instance instanceof Placeholder\PlaceholderInterface) { + if ($instance instanceof Formatter\FormatterInterface) { // we're okay return; } @@ -65,7 +65,7 @@ public function validate(mixed $instance): void throw new InvalidServiceException(sprintf( 'Plugin of type %s is invalid; must implement %s', is_object($instance) ? $instance::class : gettype($instance), - Placeholder\PlaceholderInterface::class + Formatter\FormatterInterface::class )); } } diff --git a/src/Translator/PlaceholderPluginManagerFactory.php b/src/Translator/FormatterPluginManagerFactory.php similarity index 74% rename from src/Translator/PlaceholderPluginManagerFactory.php rename to src/Translator/FormatterPluginManagerFactory.php index ad38edc8..98629a14 100644 --- a/src/Translator/PlaceholderPluginManagerFactory.php +++ b/src/Translator/FormatterPluginManagerFactory.php @@ -12,25 +12,22 @@ use function is_array; /** @psalm-import-type ServiceManagerConfiguration from ServiceManager */ -class PlaceholderPluginManagerFactory implements FactoryInterface +final class FormatterPluginManagerFactory implements FactoryInterface { /** - * Create and return a PlaceholderPluginManager. - * * @param string $requestedName * @param array|null $options * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface - * @psalm-suppress ArgumentTypeCoercion * @psalm-suppress DeprecatedClass */ public function __invoke( ContainerInterface $container, $requestedName, ?array $options = null - ): PlaceholderPluginManager { + ): FormatterPluginManager { $options ??= []; - $pluginManager = new PlaceholderPluginManager($container, $options); + $pluginManager = new FormatterPluginManager($container, $options); // If this is in a laminas-mvc application, the ServiceListener will inject // merged configuration during bootstrap. @@ -46,12 +43,12 @@ public function __invoke( $config = $container->get('config'); // If we do not have translator_plugins configuration, nothing more to do - if (! isset($config['translator_placeholders']) || ! is_array($config['translator_placeholders'])) { + if (! isset($config['translator_formatter']) || ! is_array($config['translator_formatter'])) { return $pluginManager; } // Wire service configuration for translator_plugins - (new Config($config['translator_placeholders']))->configureServiceManager($pluginManager); + (new Config($config['translator_formatter']))->configureServiceManager($pluginManager); return $pluginManager; } diff --git a/src/Translator/Placeholder/PlaceholderInterface.php b/src/Translator/Placeholder/PlaceholderInterface.php deleted file mode 100644 index 5c653f53..00000000 --- a/src/Translator/Placeholder/PlaceholderInterface.php +++ /dev/null @@ -1,13 +0,0 @@ - $placeholders - */ - public function compile(string $locale, string $message, iterable $placeholders = []): string; -} diff --git a/src/Translator/Translator.php b/src/Translator/Translator.php index 9625c273..f3f9545b 100644 --- a/src/Translator/Translator.php +++ b/src/Translator/Translator.php @@ -11,14 +11,12 @@ use Laminas\I18n\Exception; use Laminas\I18n\Translator\Loader\FileLoaderInterface; use Laminas\I18n\Translator\Loader\RemoteLoaderInterface; -use Laminas\I18n\Translator\Placeholder\PlaceholderInterface; use Laminas\ServiceManager\ServiceManager; use Laminas\Stdlib\ArrayUtils; use Locale; use Traversable; use function array_shift; -use function ctype_digit; use function get_debug_type; use function is_array; use function is_file; @@ -30,7 +28,7 @@ /** * Translator. */ -class Translator implements TranslatorInterface, TranslatorWithParamsInterface +class Translator implements TranslatorInterface { /** * Event fired when the translation for a message is missing. @@ -112,8 +110,6 @@ class Translator implements TranslatorInterface, TranslatorWithParamsInterface */ protected $eventsEnabled = false; - protected ?PlaceholderInterface $placeholder = null; - /** * Instantiate a translator * @@ -419,49 +415,6 @@ public function translatePlural( return $index === 0 ? $singular : $plural; } - /** - * @param iterable $params - */ - public function translateWithParams( - string $message, - iterable $params = [], - string $textDomain = 'default', - ?string $locale = null - ): string { - $locale ??= $this->getLocale(); - - return $this->compileMessage($this->translate($message, $textDomain, $locale), $params, $locale); - } - - /** - * The first number in params is used to determine the plural form. - * - * @param iterable $params - */ - public function translatePluralWithParams( - string $singular, - string $plural, - iterable $params = [], - string $textDomain = 'default', - ?string $locale = null - ): string { - $locale ??= $this->getLocale(); - - $number = 1; - foreach ($params as $param) { - if (ctype_digit($param)) { - $number = (int) $param; - break; - } - } - - return $this->compileMessage( - $this->translatePlural($singular, $plural, $number, $textDomain, $locale), - $params, - $locale - ); - } - /** * Get a translated message. * @@ -866,11 +819,6 @@ public function disableEventManager() return $this; } - public function setPlaceholder(PlaceholderInterface $placeholder): void - { - $this->placeholder = $placeholder; - } - protected function storeTextDomain(string $textDomain, string $locale, ?TextDomain $loaded): void { if (! $loaded instanceof TextDomain) { @@ -883,18 +831,4 @@ protected function storeTextDomain(string $textDomain, string $locale, ?TextDoma $this->messages[$textDomain][$locale] = $loaded; } } - - /** - * @param iterable $placeholders - */ - protected function compileMessage(?string $message, iterable $placeholders, string $locale): string - { - return $this->placeholder && $message !== '' && $message !== null ? - $this->placeholder->compile( - $locale, - $message, - $placeholders - ) : - ($message ?? ''); - } } diff --git a/src/Translator/TranslatorFormatterDecorator.php b/src/Translator/TranslatorFormatterDecorator.php new file mode 100644 index 00000000..3663fc25 --- /dev/null +++ b/src/Translator/TranslatorFormatterDecorator.php @@ -0,0 +1,64 @@ + $params + */ + public function translate( + $message, + $textDomain = 'default', + $locale = null, + iterable $params = [] + ): string { + $locale ??= $this->translator->getLocale(); + + return $this->formatMessage($this->translator->translate($message, $textDomain, $locale), $params, $locale); + } + + /** + * @param string $singular + * @param string $plural + * @param int $number + * @param string $textDomain + * @param string $locale + * @param iterable $params + */ + public function translatePlural( + $singular, + $plural, + $number, + $textDomain = 'default', + $locale = null, + iterable $params = [] + ): string { + $locale ??= $this->translator->getLocale(); + + return $this->formatMessage( + $this->translatePlural($singular, $plural, $number, $textDomain, $locale), + $params, + $locale + ); + } + + /** + * @param iterable $placeholders + */ + protected function formatMessage(string $message, iterable $placeholders, string $locale): string + { + return $message !== '' ? $this->formatter->format($locale, $message, $placeholders) : $message; + } +} diff --git a/src/Translator/TranslatorFormatterDecoratorFactory.php b/src/Translator/TranslatorFormatterDecoratorFactory.php new file mode 100644 index 00000000..f906786d --- /dev/null +++ b/src/Translator/TranslatorFormatterDecoratorFactory.php @@ -0,0 +1,65 @@ + $config */ + $config = $container->get('config'); + $trConfig = $config['translator'] ?? []; + $translator = $container->get(TranslatorInterface::class); + + /** @var FormatterPluginManager $formatterPluginManager */ + $formatterPluginManager = $container->get(FormatterPluginManager::class); + /** @var string|FormatterInterface|mixed $formatterName */ + $formatterName = $trConfig['message_format'] ?? 'handlebars'; + if ($formatterName instanceof FormatterInterface) { + $formatter = $formatterName; + } elseif (is_string($formatterName)) { + if (! $formatterPluginManager->has($formatterName)) { + throw new ServiceNotCreatedException( + sprintf('Could not find a placeholder format with the name "%s"', $formatterName) + ); + } + + $formatter = $formatterPluginManager->get($formatterName); + } else { + throw new InvalidServiceException(sprintf( + '\'message_format\' of type %s is invalid; must be a string or object that implements %s', + is_object($formatterName) ? $formatterName::class : gettype($formatterName), + FormatterInterface::class + )); + } + + return new TranslatorFormatterDecorator($translator, $formatter); + } +} diff --git a/src/Translator/TranslatorServiceFactory.php b/src/Translator/TranslatorServiceFactory.php index 3830bb1e..0c45e223 100644 --- a/src/Translator/TranslatorServiceFactory.php +++ b/src/Translator/TranslatorServiceFactory.php @@ -2,18 +2,11 @@ namespace Laminas\I18n\Translator; -use Laminas\ServiceManager\Exception\InvalidServiceException; -use Laminas\ServiceManager\Exception\ServiceNotCreatedException; use Laminas\ServiceManager\Factory\FactoryInterface; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; -use function gettype; -use function is_object; -use function is_string; -use function sprintf; - /** * Translator. */ @@ -37,30 +30,6 @@ public function __invoke(ContainerInterface $container, $requestedName, ?array $ $translator->setPluginManager($container->get('TranslatorPluginManager')); } - /** @var PlaceholderPluginManager $placeholderManager */ - $placeholderManager = $container->get(PlaceholderPluginManager::class); - /** @var mixed $placeholderName */ - $placeholderName = $trConfig['placeholder_format'] ?? 'handlebars'; - if ($placeholderName instanceof Placeholder\PlaceholderInterface) { - $placeholder = $placeholderName; - } elseif (is_string($placeholderName)) { - if (! $placeholderManager->has($placeholderName)) { - throw new ServiceNotCreatedException( - sprintf('Could not find a placeholder format with the name "%s"', $placeholderName) - ); - } - - $placeholder = $placeholderManager->get($placeholderName); - } else { - throw new InvalidServiceException(sprintf( - '\'placeholder_format\' of type %s is invalid; must be a string or object that implements %s', - is_object($placeholderName) ? $placeholderName::class : gettype($placeholderName), - Placeholder\PlaceholderInterface::class - )); - } - - $translator->setPlaceholder($placeholder); - return $translator; } } diff --git a/src/Translator/TranslatorWithParamsInterface.php b/src/Translator/TranslatorWithParamsInterface.php deleted file mode 100644 index eb806507..00000000 --- a/src/Translator/TranslatorWithParamsInterface.php +++ /dev/null @@ -1,31 +0,0 @@ - $params - */ - public function translateWithParams( - string $message, - iterable $params = [], - string $textDomain = 'default', - ?string $locale = null - ): string; - - /** - * Translate a plural message. - * - * @param iterable $params - */ - public function translatePluralWithParams( - string $singular, - string $plural, - iterable $params = [], - string $textDomain = 'default', - ?string $locale = null - ): string; -} diff --git a/src/View/Helper/TranslatePluralWithParams.php b/src/View/Helper/TranslatePluralWithParams.php index 8d3feecf..88cf5e20 100644 --- a/src/View/Helper/TranslatePluralWithParams.php +++ b/src/View/Helper/TranslatePluralWithParams.php @@ -3,6 +3,7 @@ namespace Laminas\I18n\View\Helper; use Laminas\I18n\Exception; +use Laminas\I18n\Translator\TranslatorFormatterDecorator; use Laminas\I18n\Translator\TranslatorWithParamsInterface; /** @@ -14,19 +15,21 @@ class TranslatePluralWithParams extends AbstractTranslatorHelper * Translate a message * * @param iterable $params + * @noinspection PhpTooManyParametersInspection */ public function __invoke( string $singular, string $plural, - iterable $params = [], + int $number, ?string $textDomain = null, - ?string $locale = null + ?string $locale = null, + iterable $params = [], ): string { $translator = $this->getTranslator(); if (null === $translator) { throw new Exception\RuntimeException('Translator has not been set'); } - if (! $translator instanceof TranslatorWithParamsInterface) { + if (! $translator instanceof TranslatorFormatterDecorator) { throw new Exception\RuntimeException( 'No param support, the translator does not implement TranslatorWithParamsInterface' ); @@ -35,6 +38,6 @@ public function __invoke( $textDomain = $this->getTranslatorTextDomain(); } - return $translator->translatePluralWithParams($singular, $plural, $params, $textDomain, $locale); + return $translator->translatePlural($singular, $plural, $number, $textDomain, $locale, $params); } } diff --git a/src/View/Helper/TranslateWithParams.php b/src/View/Helper/TranslateWithParams.php index 42e26cfd..c7a18d80 100644 --- a/src/View/Helper/TranslateWithParams.php +++ b/src/View/Helper/TranslateWithParams.php @@ -3,6 +3,7 @@ namespace Laminas\I18n\View\Helper; use Laminas\I18n\Exception; +use Laminas\I18n\Translator\TranslatorFormatterDecorator; use Laminas\I18n\Translator\TranslatorWithParamsInterface; /** @@ -17,23 +18,23 @@ class TranslateWithParams extends AbstractTranslatorHelper */ public function __invoke( string $message, - iterable $params = [], ?string $textDomain = null, - ?string $locale = null + ?string $locale = null, + iterable $params = [] ): string { $translator = $this->getTranslator(); if (null === $translator) { throw new Exception\RuntimeException('Translator has not been set'); } - if (! $translator instanceof TranslatorWithParamsInterface) { + if (! $translator instanceof TranslatorFormatterDecorator) { throw new Exception\RuntimeException( - 'No param support, the translator does not implement TranslatorWithParamsInterface' + 'No param support, the translator must be wrapped with TranslatorFormatterDecorator' ); } if (null === $textDomain) { $textDomain = $this->getTranslatorTextDomain(); } - return $translator->translateWithParams($message, $params, $textDomain, $locale); + return $translator->translate($message, $textDomain, $locale, $params); } } diff --git a/test/Translator/TranslatorServiceFactoryTest.php b/test/Translator/TranslatorServiceFactoryTest.php index dd165953..a60681df 100644 --- a/test/Translator/TranslatorServiceFactoryTest.php +++ b/test/Translator/TranslatorServiceFactoryTest.php @@ -5,8 +5,6 @@ namespace LaminasTest\I18n\Translator; use Laminas\I18n\Translator\LoaderPluginManager; -use Laminas\I18n\Translator\Placeholder\HandlebarPlaceholder; -use Laminas\I18n\Translator\PlaceholderPluginManager; use Laminas\I18n\Translator\Translator; use Laminas\I18n\Translator\TranslatorServiceFactory; use LaminasTest\I18n\TestCase; @@ -17,7 +15,6 @@ class TranslatorServiceFactoryTest extends TestCase public function testCreateServiceWithNoTranslatorKeyDefined(): void { $pluginManagerMock = $this->createMock(LoaderPluginManager::class); - $placeholderManagerMock = $this->createMock(PlaceholderPluginManager::class); $serviceLocator = $this->createMock(ContainerInterface::class); $serviceLocator->expects(self::once()) @@ -25,21 +22,10 @@ public function testCreateServiceWithNoTranslatorKeyDefined(): void ->with('TranslatorPluginManager') ->willReturn(true); - $placeholderManagerMock->expects(self::once()) - ->method('has') - ->with('handlebars') - ->willReturn(true); - - $placeholderManagerMock->expects(self::once()) - ->method('get') - ->with('handlebars') - ->willReturn(new HandlebarPlaceholder()); - - $serviceLocator->expects(self::exactly(3)) + $serviceLocator->expects(self::exactly(2)) ->method('get') ->willReturnMap([ ['TranslatorPluginManager', $pluginManagerMock], - [PlaceholderPluginManager::class, $placeholderManagerMock], ['config', []], ]); @@ -57,23 +43,10 @@ public function testCreateServiceWithNoTranslatorPluginManagerDefined(): void ->with('TranslatorPluginManager') ->willReturn(false); - $placeholderManagerMock = $this->createMock(PlaceholderPluginManager::class); - $serviceLocator->expects(self::exactly(2)) - ->method('get') - ->willReturnMap([ - [PlaceholderPluginManager::class, $placeholderManagerMock], - ['config', []], - ]); - - $placeholderManagerMock->expects(self::once()) - ->method('has') - ->with('handlebars') - ->willReturn(true); - - $placeholderManagerMock->expects(self::once()) + $serviceLocator->expects(self::once()) ->method('get') - ->with('handlebars') - ->willReturn(new HandlebarPlaceholder()); + ->with('config') + ->willReturn([]); $factory = new TranslatorServiceFactory(); $translator = $factory($serviceLocator, Translator::class);