arxy/entity-translations-bundle

本插件提供项目实体翻译。这是一个插件,但也可以独立使用。

3.1.0 2021-01-22 10:16 UTC

This package is auto-updated.

Last update: 2024-09-12 03:05:13 UTC


README

Build Status

codecov

非常简单的插件,允许您翻译实体。

安装

建议安装 X.Y.* 版本 - 此项目遵循 semver - 补丁版本将始终相互兼容。小版本可能包含小的BC-breaks。
  • composer require arxy/entity-translations-bundle
  • 在 AppKernel.php 中注册插件:new Arxy\EntityTranslationsBundle\ArxyEntityTranslationsBundle()
  • 可翻译必须 implements \Arxy\EntityTranslationsBundle\Model\Translatable
  • 翻译必须 implements \Arxy\EntityTranslationsBundle\Model\Translation
  • 您必须有一个包含所有语言的实体,它必须 implements \Arxy\EntityTranslationsBundle\Language
  • 在 config.yml 中包含 services.xml
imports:
    - { resource: "@ArxyEntityTranslationsBundle/Resources/config/services.xml" }

不需要配置。当前和备用区域设置来自 Symfony

Symfony 翻译
如何处理用户的区域设置

framework:
    translator:      { fallbacks: ["bg", "de"] }

示例实体

语言

<?php

namespace Example;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="languages")
 */
class Language implements \Arxy\EntityTranslationsBundle\Model\Language
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", length=11)
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(name="locale", type="string", length=5)
     */
    protected $locale;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     * @return Language
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getLocale(): string
    {
        return $this->locale;
    }

    /**
     * @param mixed $locale
     * @return Language
     */
    public function setLocale($locale)
    {
        $this->locale = $locale;

        return $this;
    }
}

News.php

<?php

namespace Example;

use Doctrine\ORM\Mapping as ORM;
use Arxy\EntityTranslationsBundle\Model\Translatable;
use Arxy\EntityTranslationsBundle\Model\Translation;

/**
 * @ORM\Entity()
 * @ORM\Table(name="news")
 */
class News implements Translatable
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;


    /**
     * @ORM\OneToMany(targetEntity="NewsTranslation", mappedBy="translatable", cascade={"ALL"}, orphanRemoval=true)
     */
    protected $translations;

    /**
     * @var NewsTranslation
     */
    private $currentTranslation;
    
    public function getTranslations() 
    {
        return $this->translations;
    }
    
    /**
     * This is important, as form has default option: by_reference = false
     * so here we set the mapped side entity. 
     * @param NewsTranslation|null $translation
     */
    public function addTranslation(NewsTranslation $translation) 
    {
        $this->getTranslations()->add($translation);
        $translation->setTranslatable($this);
    }
    
    /**
     * This is also used by form.
     * @param NewsTranslation|null $translation
     */
    public function removeTranslation(NewsTranslation $translation)
    {
        $this->getTranslations()->removeElement($translation);
    }

    /**
    * This method is used by bundle to inject current translation.
    */
    public function setCurrentTranslation(Translation $translation = null): void
    {
        $this->currentTranslation = $translation;
    }
    
    /**
     * @return string|null 
     */
    public function getTitle()
    {
        return !$this->currentTranslation ?: $this->currentTranslation->getTitle();
    }
}

NewsTranslations.php

<?php

namespace Example;

use Arxy\EntityTranslationsBundle\Model\Language;use Doctrine\ORM\Mapping as ORM;
use Arxy\EntityTranslationsBundle\Model\Translation;

/**
 * @ORM\Entity
 * @ORM\Table(name="news_translations")
 */
class NewsTranslation implements Translation
{

    /**
     * @var News
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="News", inversedBy="translations")
     */
    protected $translatable;

    /**
     * @var Language
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Language")
     */
    protected $language;

    /**
     * @var string
     * @ORM\Column(type="string")
     */
    protected $title;

    /**
     * @return News
     */
    public function getTranslatable()
    {
        return $this->translatable;
    }

    /**
     * @param News $translatable
     */
    public function setTranslatable(News $translatable = null)
    {
        $this->translatable = $translatable;
    }

    /**
     * @return Language
     */
    public function getLanguage(): Language
    {
        return $this->language;
    }

    /**
     * @param Language $language
     */
    public function setLanguage(Language $language)
    {
        $this->language = $language;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }
}

然后您可以在自己身上进行翻译

$news = new News();

$englishTranslation = new NewsTranslation();
$englishTranslation->setLanguage($englishLanguage);
$englishTranslation->setTitle('Title on english');
$news->addTranslation($englishTranslation);

$em->persist($news);
$em->flush();

内部API

如果您希望更改所有管理实体的语言

$this->get('arxy.entity_translations.translator')->setLocale('bg');

您可以更改单个实体的语言

$initializedLocale = $this->get('arxy.entity_translations.translator')->initializeTranslation($entity, 'bg');

$initializedLocale 是在实体中初始化的实际区域设置 - 它不一定是 bg,它可以是备用区域设置之一。参数 #2 可以是字符串区域设置或语言实体。

您可以将实体从管理器中分离

$this->get('arxy.entity_translations.translator')->detach($entity);

因此它不会受到区域设置更改的影响。

如果您希望获取单个翻译而不初始化它,则可以使用

/** @var $translation \Arxy\EntityTranslationBundle\Model\Translation */
$translation = $this->get('arxy_entity_translations.translator')->getTranslation($entity, 'bg');

参数 #2 可以是字符串区域设置或语言实体。

您还可以使用翻译器来翻译对象而不是使用 setCurrentTranslation。

$translation = $this->get('arxy_entity_translations.translator')->translate($entity, 'field', 'bg');

参数 #3 是可选的。如果省略,则假定当前区域设置。

您还可以使用类而不是键来访问服务

... $this->get(\Arxy\EntityTranslationsBundle\Translator::class) ...

您还可以使用嵌入式Twig过滤器在twig中进行翻译

{{ news|translate('title')|lower }}
{{ news|translate('title', 'en')|lower }}

或获取整个翻译

{% set translation = news|translation('en') %}
{% if translation %}
  {{ translation.title }}
{% endif %}

使用表单轻松翻译实体。

doctrine:
   orm:
        # search for the "ResolveTargetEntityListener" class for an article about this
        resolve_target_entities: 
            Arxy\EntityTranslationsBundle\Model\Language: Example\Language

可翻译应具有 addTranslationremoveTranslation(请参阅 by-reference如何处理 Doctrine 关联/关系

    public function addTranslation(NewsTranslation $translation)
    {
        if (!$this->translations->contains($translation)) {
            $this->translations->add($translation);
            $translation->setTranslatable($this);
        }
    }


    public function removeTranslation(NewsTranslation $translation)
    {
        $this->translations->removeElement($translation);
        $translation->setTranslatable(null);
    }

翻译应实现 EditableTranslation 而不是简单的 Translation

use Arxy\EntityTranslationsBundle\Model\EditableTranslation;

class NewsTranslation implements EditableTranslation

加载表单主题(可选)

twig:
    form_themes:
        - '@ArxyEntityTranslations/bootstrap_4_tab_layout.html.twig'

使用 '@ArxyEntityTranslations/bootstrap_3_tab_layout.html.twig' 以支持 Bootstrap 3。

您需要创建翻译的表单。

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class NewsTranslationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add(
            'title',
            TextType::class,
            [
                'required' => false,
                'constraints' => [
                    new NotBlank(),
                    new SomeBulgarianSymbolConstraint([
                        'groups'=> ['bg']
                    ]) // This will be validated only on bg locale
                    new SomeChineseSymbolConstraint([
                        'groups'=> ['zh']
                    ])  // This will be validated only on zh locale
                ],
            ]
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('data_class', NewsTranslation::class); // this is important
        $resolver->setDefault('constraints', [
            new NotNull(
                [
                    'groups' => ['en'], // make only english required
                ]
            ),
        ]);
    }
}

然后您可以在

->add(
    'translations',
    \Arxy\EntityTranslationsBundle\Form\Type\TranslationsType::class,
    [
        'entry_type' => NewsTranslationType::class,
        'em' => 'manager_name', // optional
        'query_builder' => function(EntityRepository $repo) {
            return $repo->createQueryBuilder('languages');
        }, // optional
        'entry_language_options' => [
            'en' => [
                'required' => true,
            ]
        ],
    ]
)

主表单中。

对于特定区域设置,在 entry_language_options 中包含 required 是很重要的,因为验证仅在语言不为空或为必填时触发。

当至少有一个字段被填写时,假定语言不为空。