Last active
November 27, 2019 08:41
-
-
Save tyx/3c2695e15b67652145e64a5523397329 to your computer and use it in GitHub Desktop.
symfony runtime translator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Oxatis\Internationalization\Ui; | |
use Oxatis\Internationalization\Infra\RuntimeTranslator; | |
use Oxatis\SharedKernel\Common\Domain\Lang; | |
use Oxatis\ShopSettings\Infra\ShopConfigurationReader; | |
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |
use Symfony\Component\HttpKernel\Event\RequestEvent; | |
use Symfony\Component\HttpKernel\KernelEvents; | |
class CustomTranslationListener implements EventSubscriberInterface | |
{ | |
private $translator; | |
private $shopConfigurationReader; | |
public function __construct(RuntimeTranslator $translator, ShopConfigurationReader $shopConfigurationReader) | |
{ | |
$this->translator = $translator; | |
$this->shopConfigurationReader = $shopConfigurationReader; | |
} | |
public static function getSubscribedEvents() | |
{ | |
return [ | |
KernelEvents::REQUEST => [ | |
['loadCustomTranslations', 17], // Should be before LocaleListener but After SymfonyShopConfigurationListener | |
], | |
]; | |
} | |
public function loadCustomTranslations(RequestEvent $event) | |
{ | |
if (false === $event->isMasterRequest()) { | |
return; | |
} | |
$shopConfiguration = $this->shopConfigurationReader->readShopConfiguration($event->getRequest()); | |
if (null === $shopConfiguration) { | |
return; | |
} | |
$lang = Lang::fromLangId($shopConfiguration->langIdOfTenant()); | |
$this->translator->addRuntimeResource('db', $shopConfiguration->accountIdOfTenant(), $lang->toString(), 'PBFAQ'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Oxatis\Internationalization\Infra; | |
use Oxatis\Internationalization\Domain\TranslationRepository; | |
use Oxatis\SharedKernel\Common\Domain\Lang; | |
use Oxatis\SharedKernel\LegacyUri\Domain\Component; | |
use Symfony\Component\Translation\Loader\LoaderInterface; | |
use Symfony\Component\Translation\MessageCatalogue; | |
class DbalTranslationLoader implements LoaderInterface | |
{ | |
private $translationRepository; | |
private $keyMapper; | |
public function __construct(TranslationRepository $translationRepository, TranslationKeyMapper $keyMapper) | |
{ | |
$this->translationRepository = $translationRepository; | |
$this->keyMapper = $keyMapper; | |
} | |
public function load($resource, $locale, $domain = 'messages') | |
{ | |
$accountId = is_int($resource) && 0 < $resource ? $resource : 0; | |
$lang = new Lang($locale); | |
$component = Component::ofScript($domain); | |
$data = $this->translationRepository->ofAccountAndComponent($accountId, $component->componentId(), $lang->id()); | |
$keyMapping = array_flip($this->keyMapper->mappingOf($component->script())); | |
$messages = array_reduce( | |
$data, | |
function ($carry, $item) use ($keyMapping) { | |
if (false === array_key_exists($item['IDS'], $keyMapping)) { | |
return $carry; | |
} | |
$carry[$keyMapping[$item['IDS']]] = trim($item['String'], '[]'); // Deal with legacy IDS | |
return $carry; | |
}, | |
[] | |
); | |
return new MessageCatalogue($locale, [$domain => $messages]); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Oxatis\Internationalization\Infra; | |
use Symfony\Component\Translation\Formatter\MessageFormatterInterface; | |
use Symfony\Component\Translation\MessageCatalogue; | |
use Symfony\Component\Translation\TranslatorBagInterface; | |
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; | |
use Symfony\Contracts\Cache\CacheInterface; | |
use Symfony\Contracts\Cache\ItemInterface; | |
use Symfony\Contracts\Translation\LocaleAwareInterface; | |
use Symfony\Contracts\Translation\TranslatorInterface; | |
class RuntimeTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface | |
{ | |
private $innerTranslator; | |
private $loader; | |
private $runtimeResources = []; | |
private $cache; | |
private $formatter; | |
public function __construct($translator, DbalTranslationLoader $loader, CacheInterface $cache, MessageFormatterInterface $formatter) | |
{ | |
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { | |
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator))); | |
} | |
if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { | |
throw new \InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', \get_class($translator))); | |
} | |
$this->innerTranslator = $translator; | |
$this->loader = $loader; | |
$this->cache = $cache; | |
$this->formatter = $formatter; | |
} | |
/** | |
* Passes through all unknown calls onto the translator object. | |
* | |
* @param mixed $method | |
* @param mixed $args | |
*/ | |
public function __call($method, $args) | |
{ | |
return $this->innerTranslator->{$method}(...$args); | |
} | |
public function addRuntimeResource($format, $resource, $locale, $domain = null) | |
{ | |
if ('db' !== $format) { | |
return; | |
} | |
$this->runtimeResources[] = [$format, $resource, $locale, $domain]; | |
} | |
public function getCatalogue($locale = null) | |
{ | |
return $this->innerTranslator->getCatalogue($locale); | |
} | |
public function trans($id, array $parameters = [], $domain = null, $locale = null) | |
{ | |
if (null === $locale) { | |
$locale = $this->getLocale(); | |
} | |
$runtimeCatalogue = $this->getRuntimeCatalogue($locale); | |
if (false === $runtimeCatalogue->defines($id, $domain)) { | |
return $this->innerTranslator->trans(...func_get_args()); | |
} | |
return $this->formatter->format($runtimeCatalogue->get($id, $domain), $locale, $parameters); | |
} | |
public function setLocale($locale) | |
{ | |
return $this->innerTranslator->setLocale($locale); | |
} | |
public function getLocale() | |
{ | |
return $this->innerTranslator->getLocale(); | |
} | |
private function getRuntimeCatalogue($locale) | |
{ | |
$catalogue = new MessageCatalogue($locale); | |
$runtimeResources = $this->getRuntimeResourcesOfLocale($locale); | |
foreach ($runtimeResources as [$format, $resource, $locale, $domain]) { | |
$cacheKey = implode('', [$resource, $locale, $domain]); | |
$runtimeCatalogue = $this->cache->get($cacheKey, function (ItemInterface $item) use ($resource, $locale, $domain) { | |
return $this->loader->load($resource, $locale, $domain); | |
}); | |
$catalogue->addCatalogue($runtimeCatalogue); | |
} | |
return $catalogue; | |
} | |
private function getRuntimeResourcesOfLocale(string $locale): array | |
{ | |
return array_filter( | |
$this->runtimeResources, | |
function ($item) use ($locale) { | |
return $item[2] === $locale; | |
} | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
Oxatis\Internationalization\Infra\DbalTranslationLoader: | |
tags: | |
- { name: "translation.loader", alias: "db" } | |
Oxatis\Internationalization\Infra\RuntimeTranslator: | |
decorates: 'translator' | |
decoration_priority: 5 | |
arguments: | |
$translator: '@Oxatis\Internationalization\Infra\RuntimeTranslator.inner' | |
$cache: '@cache.runtime_translations' | |
$formatter: '@translator.formatter.default' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment