vm5 / entity-translations-bundle
Requires
- php: ^7.2
Requires (Dev)
- doctrine/doctrine-bundle: ~1.8 | ~2.0
- doctrine/orm: ~2.5
- doctrine/persistence: ~2.0
- phpunit/phpunit: ^8.0 | ^9.0
- symfony/symfony: ~4.4 | ~5.0
Suggests
- doctrine/doctrine-bundle: Needed if you want to use forms to translate entities.
- doctrine/orm: Autoload translations with Doctrine ORM
- symfony/form: Needed if you want to use forms to translate entities.
- symfony/property-access: Needed for Twig extension to translate
- symfony/symfony: Needed for easy integration into Symfony
- symfony/translation: Needed if you want to use Symfony Translation's configuration. Otherwise this bundle should be setup separately.
- twig/twig: Needed to use Twig Extension to translate in twig.
README
一个非常简单的包,允许您翻译实体。
安装
建议安装 X.Y.* 版本 - 此项目遵循 semver - 补丁版本将始终与彼此兼容。次要版本可能包含向后不兼容的更改。
- composer require arxy/entity-translations-bundle
- 在 AppKernel.php 中注册包:
new Arxy\EntityTranslationsBundle\ArxyEntityTranslationsBundle()
- 可翻译必须
实现 \Arxy\EntityTranslationsBundle\Model\Translatable
- 翻译必须
实现 \Arxy\EntityTranslationsBundle\Model\Translation
- 您必须有一个包含所有语言的实体,它必须
实现 \Arxy\EntityTranslationsBundle\Language
- 在 config.yml 中包含 services.xml
imports:
- { resource: "@ArxyEntityTranslationsBundle/Resources/config/services.xml" }
无需配置。当前和备用区域设置来自 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 可以是字符串区域设置或 Language 实体。
您可以取消实体与经理的关联
$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 可以是字符串区域设置或 Language 实体。
您也可以使用翻译器来翻译对象,而不是使用 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
可翻译应该具有 addTranslation
,removeTranslation
(见 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, ] ], ] )
在主表单中。
对于特定区域,将required
包含在entry_language_options
中非常重要,因为只有在语言不为空或为必填时才会触发验证。
当至少有一个字段填写时,假定语言不为空。