{"id":21251291,"url":"https://github.com/secit-pl/entity-translation-bundle","last_synced_at":"2025-07-11T01:32:07.141Z","repository":{"id":62541721,"uuid":"139410100","full_name":"secit-pl/entity-translation-bundle","owner":"secit-pl","description":" Doctrine entity translations for Symfony 4.x.","archived":false,"fork":false,"pushed_at":"2023-02-16T12:56:00.000Z","size":25,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-15T20:37:00.093Z","etag":null,"topics":["doctrine","entity","symfony","translation","translation-entity"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/secit-pl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-02T07:57:30.000Z","updated_at":"2022-08-27T14:16:06.000Z","dependencies_parsed_at":"2024-11-15T20:28:15.760Z","dependency_job_id":"ab18fe17-c2d3-46ac-bf59-98bfcac3e05a","html_url":"https://github.com/secit-pl/entity-translation-bundle","commit_stats":{"total_commits":25,"total_committers":1,"mean_commits":25.0,"dds":0.0,"last_synced_commit":"01752fcea4a8f98de3c673d731a0467a08cb4954"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secit-pl%2Fentity-translation-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secit-pl%2Fentity-translation-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secit-pl%2Fentity-translation-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secit-pl%2Fentity-translation-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/secit-pl","download_url":"https://codeload.github.com/secit-pl/entity-translation-bundle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225669673,"owners_count":17505363,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["doctrine","entity","symfony","translation","translation-entity"],"created_at":"2024-11-21T03:41:27.477Z","updated_at":"2024-11-21T03:41:28.136Z","avatar_url":"https://github.com/secit-pl.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Entity Translation Bundle\n\nDoctrine entity translations Symfony 4.x.\n\n## Installation\n\nFrom the command line run\n\n```\n$ composer require secit-pl/entity-translation-bundle\n```\n\n## Usage\n\n#### Configuration\n\nOpen configuration file `./config/packages/entity_translation.yaml`. If file not exists create it.\n\nThe file content shoud looks somehting like this:\n\n```yaml\nentity_translation:\n    locales:\n        defined:\n          - pl\n          - en_GB\n          \n        default: '%kernel.default_locale%' # in this example equals `pl`\n\n```\n\n#### Entity\n\n###### Key rules\n\n* Translatable entity should implements `SecIT\\EntityTranslationBundle\\Translations\\TranslatableInterface`\n* Translation entity should be called `Translation` and be placed in namespace same as translatable class name.\n  For example, if translatable entity is `App\\Entity\\Shop` the translation class should be `App\\Entity\\Shop\\Translation`\n* Translation should extends `SecIT\\EntityTranslationBundle\\Entity\\AbstractTranslation`\n\n###### Example\n\nLet's say we have following entity and we want to translate the `name` and `description` fields.\nOther field should not be translated.\n\n./src/Entity/Shop.php\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Entity;\n\nuse Doctrine\\ORM\\Mapping as ORM;\n\n/**\n * Class Shop.\n *\n * @ORM\\Table(name=\"shops\")\n * @ORM\\Entity\n */\nclass Shop\n{\n    /**\n     * @var int|null\n     *\n     * @ORM\\Id\n     * @ORM\\GeneratedValue\n     * @ORM\\Column(type=\"integer\")\n     */\n    private $id;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $name;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $description;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $city;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $street;\n\n    /**\n     * Get id.\n     *\n     * @return int|null\n     */\n    public function getId(): ?int\n    {\n        return $this-\u003eid;\n    }\n\n    /**\n     * Get name.\n     *\n     * @return null|string\n     */\n    public function getName(): ?string\n    {\n        return $this-\u003ename;\n    }\n\n    /**\n     * Set name.\n     *\n     * @param null|string $name\n     *\n     * @return Shop\n     */\n    public function setName(?string $name): Shop\n    {\n        $this-\u003ename = $name;\n\n        return $this;\n    }\n\n    /**\n     * Get description.\n     *\n     * @return null|string\n     */\n    public function getDescription(): ?string\n    {\n        return $this-\u003edescription;\n    }\n\n    /**\n     * Set description.\n     *\n     * @param null|string $description\n     *\n     * @return Shop\n     */\n    public function setDescription(?string $description): Shop\n    {\n        $this-\u003edescription = $description;\n\n        return $this;\n    }\n\n    /**\n     * Get city.\n     * \n     * @return null|string\n     */\n    public function getCity(): ?string\n    {\n        return $this-\u003ecity;\n    }\n\n    /**\n     * Set city.\n     * \n     * @param null|string $city\n     *\n     * @return Shop\n     */\n    public function setCity(?string $city): Shop\n    {\n        $this-\u003ecity = $city;\n\n        return $this;\n    }\n\n    /**\n     * Get street.\n     * \n     * @return null|string\n     */\n    public function getStreet(): ?string\n    {\n        return $this-\u003estreet;\n    }\n\n    /**\n     * Set street.\n     * \n     * @param null|string $street\n     *\n     * @return Shop\n     */\n    public function setStreet(?string $street): Shop\n    {\n        $this-\u003estreet = $street;\n\n        return $this;\n    }\n}\n\n```\n\nWe need to split the file to two separeted files. One will contain the common part of each translation and one will contain the fields we want to translate.\n\nFirst we need to create a Shop Translation entity. The entity should be placed in namespace `App\\Entity\\Shop`.  \n\n./src/Entity/Shop/Translation.php\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Entity\\Shop;\n\nuse App\\Entity\\Shop;\nuse Doctrine\\ORM\\Mapping as ORM;\nuse SecIT\\EntityTranslationBundle\\Entity\\AbstractTranslation;\n\n/**\n * Class Translation.\n *\n * @ORM\\Table(name=\"shops_translations\")\n * @ORM\\Entity\n *\n * @method Shop getTranslatable()\n */\nclass Translation extends AbstractTranslation\n{\n    /**\n     * @var int|null\n     *\n     * @ORM\\Id\n     * @ORM\\GeneratedValue\n     * @ORM\\Column(type=\"integer\")\n     */\n    private $id;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $name;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $description;\n\n    /**\n     * Get id.\n     *\n     * @return int|null\n     */\n    public function getId(): ?int\n    {\n        return $this-\u003eid;\n    }\n\n    /**\n     * Get name.\n     *\n     * @return null|string\n     */\n    public function getName(): ?string\n    {\n        return $this-\u003ename;\n    }\n\n    /**\n     * Set name.\n     *\n     * @param null|string $name\n     *\n     * @return Translation\n     */\n    public function setName(?string $name): Translation\n    {\n        $this-\u003ename = $name;\n\n        return $this;\n    }\n\n    /**\n     * Get description.\n     *\n     * @return null|string\n     */\n    public function getDescription(): ?string\n    {\n        return $this-\u003edescription;\n    }\n\n    /**\n     * Set description.\n     *\n     * @param null|string $description\n     *\n     * @return Translation\n     */\n    public function setDescription(?string $description): Translation\n    {\n        $this-\u003edescription = $description;\n\n        return $this;\n    }\n}\n\n```\n\nWhat has been done:\n* We created a class `Translation` in namespace `App\\Entity\\Shop`\n* The class extends `SecIT\\EntityTranslationBundle\\Entity\\AbstractTranslation`\n* We created a standard entity with `name` and `description` fields copied from original entity\n* To improve type hinting we added `@method Shop getTranslatable()`\n\nNext it's time to change the base entity.\n\n./src/Entity/Shop.php\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Entity;\n\nuse App\\Entity\\Translation;\nuse Doctrine\\ORM\\Mapping as ORM;\nuse SecIT\\EntityTranslationBundle\\Translations\\TranslatableInterface;\nuse SecIT\\EntityTranslationBundle\\Translations\\TranslatableTrait;\n\n/**\n * Class Shop.\n *\n * @ORM\\Table(name=\"shops\")\n * @ORM\\Entity\n *\n * @method Translation getTranslation(?string $locale)\n * @method Collection|Translation[] getTranslations\n */\nclass Shop implements TranslatableInterface\n{\n    use TranslatableTrait  {\n        __construct as private initializeTranslationsCollection;\n    }\n    \n    /**\n     * @var int|null\n     *\n     * @ORM\\Id\n     * @ORM\\GeneratedValue\n     * @ORM\\Column(type=\"integer\")\n     */\n    private $id;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $city;\n\n    /**\n     * @var string|null\n     *\n     * @ORM\\Column(type=\"string\")\n     *\n     * @JMS\\Expose\n     */\n    private $street;\n\n    /**\n     * Shop constructor.\n     */\n    public function __construct()\n    {\n        $this-\u003einitializeTranslationsCollection();\n    }\n    \n    /**\n     * Get id.\n     *\n     * @return int|null\n     */\n    public function getId(): ?int\n    {\n        return $this-\u003eid;\n    }\n\n    /**\n     * Get name.\n     *\n     * @param null|string locale\n     *\n     * @return null|string\n     */\n    public function getName(?string $locale = null): ?string\n    {\n        return $this-\u003egetTranslation($locale)-\u003egetName();\n    }\n\n    /**\n     * Get description.\n     *\n     * @param null|string locale\n     *\n     * @return null|string\n     */\n    public function getDescription(?string $locale = null): ?string\n    {\n        return $this-\u003egetTranslation($locale)-\u003egetDescription();\n    }\n\n    /**\n     * Get city.\n     * \n     * @return null|string\n     */\n    public function getCity(): ?string\n    {\n        return $this-\u003ecity;\n    }\n\n    /**\n     * Set city.\n     * \n     * @param null|string $city\n     *\n     * @return Shop\n     */\n    public function setCity(?string $city): Shop\n    {\n        $this-\u003ecity = $city;\n\n        return $this;\n    }\n\n    /**\n     * Get street.\n     * \n     * @return null|string\n     */\n    public function getStreet(): ?string\n    {\n        return $this-\u003estreet;\n    }\n\n    /**\n     * Set street.\n     * \n     * @param null|string $street\n     *\n     * @return Shop\n     */\n    public function setStreet(?string $street): Shop\n    {\n        $this-\u003estreet = $street;\n\n        return $this;\n    }\n}\n\n```\n\nWhat has been done:\n* We added class implements `SecIT\\EntityTranslationBundle\\Translations\\TranslatableInterface`\n* We used default implementation of implemented interface using `SecIT\\EntityTranslationBundle\\Translations\\TranslatableTrait`\n* We added constructor to initialize translations collection\n* We removed `name` and `description` setters\n* `getName` and `getDescription` was changed to have easier way to get translated values and to be more backward compatible\n* Type hinting was added\n\nNow we need to update the database schema by `php bin/console doctrine:schema:update --force` and that's it. Now our entity is translatable.\n\n**Remember, if you had a data in database you should move it manually to the new database schema!**\n\n#### Usage\n\n```php\n\u003c?php\n\n// creating entity\n$shop = new Shop();\n$shop-\u003esetCity('city')\n    -\u003esetStreet('some street 1');\n\n// adding polish translation\n$shop-\u003egetTranslation('pl')\n    -\u003esetName('Nazwa')\n    -\u003esetDescription('Opis...');\n\n// adding english translation\n$shop-\u003egetTranslation('en_GB')\n    -\u003esetName('Name')\n    -\u003esetDescription('Description...');\n\n$doctrine-\u003egetManager()-\u003epersist($shop);\n$doctrine-\u003egetManager()-\u003eflush();\n\n// fetching current locale translation\n// let's say the default locale is en_GB\n$name = $shop-\u003egetName(); // Name\n\n// fetching defined locale translation\n$name = $shop-\u003egetName('pl'); // Nazwa\n\n// change the current locale\n$shop-\u003esetCurrentLocale('pl');\n$name = $shop-\u003egetName(); // Nazwa\n\n```\n\n#### Using translatable entity in forms\n\nYou need to create two classes. One for Translatable entity, and one for translation.\n\n./src/Form/ShopType.php\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Form;\n\nuse App\\Entity\\Shop;\nuse App\\Form\\Shop\\TranslationType;\nuse SecIT\\EntityTranslationBundle\\Form\\Type\\ResourceTranslationsType;\nuse Symfony\\Component\\Form\\AbstractType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\SubmitType;\nuse Symfony\\Component\\Form\\FormBuilderInterface;\nuse Symfony\\Component\\OptionsResolver\\OptionsResolver;\n\n/**\n * Class ShopType.\n */\nclass ShopType extends AbstractType\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function buildForm(FormBuilderInterface $builder, array $options)\n    {\n        $builder\n            -\u003eadd('translations', ResourceTranslationsType::class, [\n                'entry_type' =\u003e TranslationType::class,\n            ])\n            -\u003eadd('city')\n            -\u003eadd('street')\n            -\u003eadd('save', SubmitType::class);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function configureOptions(OptionsResolver $resolver)\n    {\n        $resolver-\u003esetDefaults([\n            'data_class' =\u003e Shop::class,\n        ]);\n    }\n}\n\n```\n\n./src/Form/Shop/TranslationType.php\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Form;\n\nuse App\\Entity\\Shop\\Translation;\nuse Symfony\\Component\\Form\\AbstractType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\SubmitType;\nuse Symfony\\Component\\Form\\FormBuilderInterface;\nuse Symfony\\Component\\OptionsResolver\\OptionsResolver;\n\n/**\n * Class TranslationType.\n */\nclass TranslationType extends AbstractType\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function buildForm(FormBuilderInterface $builder, array $options)\n    {\n        $builder\n            -\u003eadd('name')\n            -\u003eadd('description');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function configureOptions(OptionsResolver $resolver)\n    {\n        $resolver-\u003esetDefaults([\n            'data_class' =\u003e Translation::class,\n        ]);\n    }\n}\n\n```\n\nNow you can use `App\\Form\\ShopType` like a normal Symfony form. \nTranslations will be handled automatically.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecit-pl%2Fentity-translation-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecit-pl%2Fentity-translation-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecit-pl%2Fentity-translation-bundle/lists"}