Как загрузить переводы из базы данных в Symfony4? - PullRequest
0 голосов
/ 01 мая 2018

Согласно этой статье документации Symfony должна быть возможность загрузить свой собственный формат переводов. Поэтому я пытаюсь загрузить их из базы данных.

Но все, что я пытаюсь сделать эту работу. Это просто не так.

Правильно ли использовать загрузчик базы данных или я должен сделать что-то еще для загрузки переводов из базы данных?

App \ Translation \ Loader \ DatabaseLoader.php:

namespace App\Translation\Loader;

use App\Entity\Translation;
use App\Domain\TranslationManagerInterface;
use Symfony\Component\Translation\Loader\LoaderInterface;
use Symfony\Component\Translation\MessageCatalogue;

/**
 * Database Loader
 */
class DatabaseLoader implements LoaderInterface
{
    /**
     * Translation Manager
     *
     * @var TranslationManagerInterface
     */
    private $_translationManager;

    /**
     * Constructor
     *
     * @param TranslationManagerInterface $translationManager
     */
    public function __construct(TranslationManagerInterface $translationManager)
    {
        $this->_translationManager = $translationManager;
    }

    /**
     * {@inheritDoc}
     */
    public function load($resource, $locale, $domain = 'general')
    {
        $translations = $this->_translationManager->findByLocaleAndDomain($locale, $domain);

        $catalogue = new MessageCatalogue($locale);

        /* @var Translation $translation */
        foreach($translations as $translation)
        {
            $catalogue->set(
                $translation->getToken(),
                $translation->getContent(),
                $translation->getDomain()()
            );
        }
    }
}

конфиг / services.yaml:

# database loader
    translation.loader.database:
        class: 'App\Translation\Loader\DatabaseLoader'
        arguments: [ 'App\Domain\TranslationManager' ]
        tags:
            - { name: translation.loader, alias: database, priority: 100 }

Я даже пытался вручную добавить загрузчик в транслятор с помощью прослушивателя событий по запросу ядра. Я не хочу использовать полный пакет, так как у меня уже есть база данных, заполненная переводами

Ответы [ 2 ]

0 голосов
/ 16 мая 2019

Я расширил класс Translator, чтобы не создавать фиктивный файл перевода для каждого домена в приложении.

Чтобы переопределить стандартный компонент Translator, необходимо загрузить Compiler Pass.

Pass Transiler Compiler Pass:

namespace App\DependencyInjection\Compiler;

use App\Domain\TranslationManagerInterface;
use App\Translation\Translator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class TranslatorCompilerPass implements CompilerPassInterface
{
    private $translatorServiceId;
    private $readerServiceId;
    private $loaderTag;
    private $debugCommandServiceId;
    private $updateCommandServiceId;

    /**
     * @param string $translatorServiceId
     * @param string $readerServiceId
     * @param string $loaderTag
     * @param string $debugCommandServiceId
     * @param string $updateCommandServiceId
     */
    public function __construct(
        string $translatorServiceId = 'translator.default',
        string $readerServiceId = 'translation.reader',
        string $loaderTag = 'translation.loader',
        string $debugCommandServiceId = 'console.command.translation_debug',
        string $updateCommandServiceId = 'console.command.translation_update'
    ) {
        $this->translatorServiceId = $translatorServiceId;
        $this->readerServiceId = $readerServiceId;
        $this->loaderTag = $loaderTag;
        $this->debugCommandServiceId = $debugCommandServiceId;
        $this->updateCommandServiceId = $updateCommandServiceId;
    }

    /**
     * {@inheritdoc}
     */
    public function process(ContainerBuilder $container)
    {
        $loaders = [];
        $loaderRefs = [];
        foreach ($container->findTaggedServiceIds($this->loaderTag, true) as $id => $attributes) {
            $loaderRefs[$id] = new Reference($id);
            $loaders[$id][] = $attributes[0]['alias'];
            if (isset($attributes[0]['legacy-alias'])) {
                $loaders[$id][] = $attributes[0]['legacy-alias'];
            }
        }

        if ($container->hasDefinition($this->readerServiceId)) {
            $definition = $container->getDefinition($this->readerServiceId);
            foreach ($loaders as $id => $formats) {
                foreach ($formats as $format) {
                    $definition->addMethodCall('addLoader', [$format, $loaderRefs[$id]]);
                }
            }
        }

        $definition = $container->findDefinition($this->translatorServiceId);

        $definition
            ->setClass(Translator::class)
            ->replaceArgument(0, null)
            ->replaceArgument(1, $definition->getArgument(1))
            ->replaceArgument(2, $definition->getArgument(4)["cache_dir"])
            ->replaceArgument(3, $definition->getArgument(4)["debug"])
            ->replaceArgument(4, $definition->getArgument(4)["resource_files"])
            ->addMethodCall("setTranslationManager", [new Reference(TranslationManagerInterface::class)])
        ;


        if (!$container->hasParameter('twig.default_path')) {
            return;
        }

        if ($container->hasDefinition($this->debugCommandServiceId)) {
            $container->getDefinition($this->debugCommandServiceId)->replaceArgument(4, $container->getParameter('twig.default_path'));
        }

        if ($container->hasDefinition($this->updateCommandServiceId)) {
            $container->getDefinition($this->updateCommandServiceId)->replaceArgument(5, $container->getParameter('twig.default_path'));
        }
    }
}

Класс переводчика:

namespace App\Translation;

use App\Domain\TranslationManagerInterface;
use App\Entity\Model\Translation\Translation;
use Symfony\Component\Translation\Translator as SymfonyTranslator;

class Translator extends SymfonyTranslator
{
    /**
     * @var TranslationManagerInterface
     */
    private $_translationManager;

    /**
     * @param TranslationManagerInterface $translationManager
     */
    public function setTranslationManager(TranslationManagerInterface $translationManager)
    {
        $this->_translationManager = $translationManager;
    }

    /**
     * {@inheritdoc}
     */
    public function trans($id, array $parameters = [], $domain = null, $locale = null)
    {
        if (null === $locale && null !== $this->getLocale()) {
            $locale = $this->getLocale();
        }

        if (null === $locale) {
            $locale = $this->getFallbackLocales()[0]; // fallback locale
        }

        // the translation manager automagically creates new translation entries if it doesn't exist yet
        $translation = $this->_translationManager->findOneByTokenLocaleAndDomain($id, $locale, $domain);

        // check if it exists
        if (isset($translation) && null !== $translation && $translation instanceof Translation) {
            return strtr($translation->getContent(), $parameters);
        }

        // fallback
        return parent::trans($id, $parameters, $domain, $locale);
    }
}

0 голосов
/ 02 апреля 2019

Протестировано с Symfony 4.2.4 : Возможно, этот ответ приходит немного поздно, но я хотел помочь другим посетителям с такой же проблемой, которые были в таком же отчаянии, как и я.

  1. В вашем классе DatabaseLoader есть небольшая ошибка. Вы должны вернуть $ catalog в функции load ().

    public function load($resource, $locale, $domain = 'general')
    {
        $translations = $this->_translationManager->findByLocaleAndDomain($locale, $domain);
    
        $catalogue = new MessageCatalogue($locale);
    
        /* @var Translation $translation */
        foreach($translations as $translation)
        {
            $catalogue->set(
                $translation->getToken(),
                $translation->getContent(),
                $translation->getDomain()()
            );
        }
    
        // you must return $catalogue here
        return $catalogue;
    }
    
  2. Вы должны создать «поддельные» файлы перевода, чтобы запустить ваш загрузчик. Посмотреть здесь: https://stackoverflow.com/a/33300593/6709953

    Пример: для домена перевода "messages" и локали "en" должен быть пустой файл translations / messages.en.database

    (Небольшая подсказка: в config / services.yaml вы задаете «псевдоним: база данных», это означает, что суффикс файла перевода должен быть .database)

  3. Вы должны удалить старые конкурирующие файлы переводов, если они существуют в папке translation / . Так, например, если есть также файл translations / messages.en.yaml , вы должны удалить его.

...