【问题标题】:How to load translations from a database in Symfony4?如何从 Symfony4 中的数据库加载翻译?
【发布时间】:2018-05-01 14:01:01
【问题描述】:

根据this symfony documentation article 应该可以加载您自己的翻译格式。所以我正在尝试从数据库中加载它们。

但无论我试图使这项工作。它只是没有。

使用数据库加载器是正确的方法还是我应该做其他事情来从数据库加载翻译?

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()()
            );
        }
    }
}

config/services.yaml:

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

我什至尝试通过内核请求的事件侦听器手动将加载程序添加到翻译器。我不想使用完整的捆绑包,因为我已经是一个充满翻译的数据库

【问题讨论】:

  • symfony2和symfony4有区别
  • 这种情况下是哪一种?回复前请点击链接。 ;)
  • 必须是你的翻译文件夹中的一个文件 {domain}.{locale}.{alias} 即使你的翻译是从数据库加载的,Symfony 也在寻找这样的文件

标签: symfony internationalization translation


【解决方案1】:

使用 Symfony 4.2.4 测试也许这个答案来的有点晚,但我想帮助其他和我一样绝望的有同样问题的访客。

  1. 您的类 DatabaseLoader 中有一个小错误。您必须在函数 load() 中返回 $catalogue

    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中设置“alias:database”,意思是翻译文件的后缀必须是.database)

  3. 如果旧的竞争翻译文件存在于文件夹 translation/ 中,您必须删除它们。因此,例如,如果还有文件 translations/messages.en.yaml,则必须将其删除。

【讨论】:

    【解决方案2】:

    我扩展了 Translator 类以避免必须为应用程序中的每个域创建一个虚拟翻译文件。

    要覆盖标准的 Translator 组件,需要加载 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);
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 2012-11-01
      • 1970-01-01
      • 2020-10-31
      • 2020-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多