secit-pl / entity-translation-bundle
.
1.6.3
2023-02-16 12:51 UTC
Requires
- php: >=7.1.0
- doctrine/doctrine-bundle: ^2.3
- doctrine/orm: ^2.9
- symfony/config: ^4.4 || ^5.0 || ^6.0
- symfony/dependency-injection: ^4.4 || ^5.0 || ^6.0
- symfony/form: ^4.4 || ^5.0 || ^6.0
- symfony/framework-bundle: ^4.4 || ^5.0 || ^6.0
- symfony/http-kernel: ^4.4 || ^5.0 || ^6.0
- symfony/intl: ^4.4 || ^5.0 || ^6.0
- symfony/options-resolver: ^4.4 || ^5.0 || ^6.0
- symfony/validator: ^4.4 || ^5.0 || ^6.0
Requires (Dev)
- phpunit/phpunit: @stable
README
Doctrine 实体翻译 Symfony 4.x。
安装
在命令行中运行
$ composer require secit-pl/entity-translation-bundle
用法
配置
打开配置文件 ./config/packages/entity_translation.yaml
。如果文件不存在,则创建它。
文件内容应类似于以下内容
entity_translation: locales: defined: - pl - en_GB default: '%kernel.default_locale%' # in this example equals `pl`
实体
键规则
- 可翻译实体应实现
SecIT\EntityTranslationBundle\Translations\TranslatableInterface
- 翻译实体应命名为
Translation
并放置在与可翻译类名相同的命名空间中。例如,如果可翻译实体是App\Entity\Shop
,则翻译类应命名为App\Entity\Shop\Translation
- 翻译应扩展
SecIT\EntityTranslationBundle\Entity\AbstractTranslation
示例
假设我们有一个以下实体,并且我们想翻译 name
和 description
字段。其他字段不应翻译。
./src/Entity/Shop.php
<?php declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** * Class Shop. * * @ORM\Table(name="shops") * @ORM\Entity */ class Shop { /** * @var int|null * * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $name; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $description; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $city; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $street; /** * Get id. * * @return int|null */ public function getId(): ?int { return $this->id; } /** * Get name. * * @return null|string */ public function getName(): ?string { return $this->name; } /** * Set name. * * @param null|string $name * * @return Shop */ public function setName(?string $name): Shop { $this->name = $name; return $this; } /** * Get description. * * @return null|string */ public function getDescription(): ?string { return $this->description; } /** * Set description. * * @param null|string $description * * @return Shop */ public function setDescription(?string $description): Shop { $this->description = $description; return $this; } /** * Get city. * * @return null|string */ public function getCity(): ?string { return $this->city; } /** * Set city. * * @param null|string $city * * @return Shop */ public function setCity(?string $city): Shop { $this->city = $city; return $this; } /** * Get street. * * @return null|string */ public function getStreet(): ?string { return $this->street; } /** * Set street. * * @param null|string $street * * @return Shop */ public function setStreet(?string $street): Shop { $this->street = $street; return $this; } }
我们需要将文件拆分为两个独立的文件。一个将包含每个翻译的公共部分,另一个将包含我们想要翻译的字段。
首先,我们需要创建一个 Shop Translation 实体。实体应放置在命名空间 App\Entity\Shop
中。
./src/Entity/Shop/Translation.php
<?php declare(strict_types=1); namespace App\Entity\Shop; use App\Entity\Shop; use Doctrine\ORM\Mapping as ORM; use SecIT\EntityTranslationBundle\Entity\AbstractTranslation; /** * Class Translation. * * @ORM\Table(name="shops_translations") * @ORM\Entity * * @method Shop getTranslatable() */ class Translation extends AbstractTranslation { /** * @var int|null * * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $name; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $description; /** * Get id. * * @return int|null */ public function getId(): ?int { return $this->id; } /** * Get name. * * @return null|string */ public function getName(): ?string { return $this->name; } /** * Set name. * * @param null|string $name * * @return Translation */ public function setName(?string $name): Translation { $this->name = $name; return $this; } /** * Get description. * * @return null|string */ public function getDescription(): ?string { return $this->description; } /** * Set description. * * @param null|string $description * * @return Translation */ public function setDescription(?string $description): Translation { $this->description = $description; return $this; } }
已完成的操作
- 我们在命名空间
App\Entity\Shop
中创建了一个名为Translation
的类 - 该类扩展了
SecIT\EntityTranslationBundle\Entity\AbstractTranslation
- 我们创建了一个标准实体,其中包含从原始实体复制的
name
和description
字段 - 为了改进类型提示,我们添加了
@method Shop getTranslatable()
现在,我们需要更改基础实体。
./src/Entity/Shop.php
<?php declare(strict_types=1); namespace App\Entity; use App\Entity\Translation; use Doctrine\ORM\Mapping as ORM; use SecIT\EntityTranslationBundle\Translations\TranslatableInterface; use SecIT\EntityTranslationBundle\Translations\TranslatableTrait; /** * Class Shop. * * @ORM\Table(name="shops") * @ORM\Entity * * @method Translation getTranslation(?string $locale) * @method Collection|Translation[] getTranslations */ class Shop implements TranslatableInterface { use TranslatableTrait { __construct as private initializeTranslationsCollection; } /** * @var int|null * * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $city; /** * @var string|null * * @ORM\Column(type="string") * * @JMS\Expose */ private $street; /** * Shop constructor. */ public function __construct() { $this->initializeTranslationsCollection(); } /** * Get id. * * @return int|null */ public function getId(): ?int { return $this->id; } /** * Get name. * * @param null|string locale * * @return null|string */ public function getName(?string $locale = null): ?string { return $this->getTranslation($locale)->getName(); } /** * Get description. * * @param null|string locale * * @return null|string */ public function getDescription(?string $locale = null): ?string { return $this->getTranslation($locale)->getDescription(); } /** * Get city. * * @return null|string */ public function getCity(): ?string { return $this->city; } /** * Set city. * * @param null|string $city * * @return Shop */ public function setCity(?string $city): Shop { $this->city = $city; return $this; } /** * Get street. * * @return null|string */ public function getStreet(): ?string { return $this->street; } /** * Set street. * * @param null|string $street * * @return Shop */ public function setStreet(?string $street): Shop { $this->street = $street; return $this; } }
已完成的操作
- 我们添加了类实现
SecIT\EntityTranslationBundle\Translations\TranslatableInterface
- 我们使用
SecIT\EntityTranslationBundle\Translations\TranslatableTrait
的默认实现来实现了接口 - 我们添加了构造函数来初始化翻译集合
- 我们移除了
name
和description
设置器 getName
和getDescription
被修改为更容易获取翻译值,并且与旧版本更兼容- 添加了类型提示
现在,我们需要通过 php bin/console doctrine:schema:update --force
更新数据库模式,这样就完成了。现在我们的实体是可翻译的。
请记住,如果您数据库中有数据,您应手动将其移动到新的数据库模式中!
用法
<?php // creating entity $shop = new Shop(); $shop->setCity('city') ->setStreet('some street 1'); // adding polish translation $shop->getTranslation('pl') ->setName('Nazwa') ->setDescription('Opis...'); // adding english translation $shop->getTranslation('en_GB') ->setName('Name') ->setDescription('Description...'); $doctrine->getManager()->persist($shop); $doctrine->getManager()->flush(); // fetching current locale translation // let's say the default locale is en_GB $name = $shop->getName(); // Name // fetching defined locale translation $name = $shop->getName('pl'); // Nazwa // change the current locale $shop->setCurrentLocale('pl'); $name = $shop->getName(); // Nazwa
在表单中使用可翻译实体
您需要创建两个类。一个用于可翻译实体,另一个用于翻译。
./src/Form/ShopType.php
<?php declare(strict_types=1); namespace App\Form; use App\Entity\Shop; use App\Form\Shop\TranslationType; use SecIT\EntityTranslationBundle\Form\Type\ResourceTranslationsType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * Class ShopType. */ class ShopType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('translations', ResourceTranslationsType::class, [ 'entry_type' => TranslationType::class, ]) ->add('city') ->add('street') ->add('save', SubmitType::class); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Shop::class, ]); } }
./src/Form/Shop/TranslationType.php
<?php declare(strict_types=1); namespace App\Form; use App\Entity\Shop\Translation; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; /** * Class TranslationType. */ class TranslationType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') ->add('description'); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Translation::class, ]); } }
现在您可以使用 App\Form\ShopType
作为正常的 Symfony 表单。翻译将自动处理。