PHPackages                             sandstorm/gedmotranslatableconnector - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. sandstorm/gedmotranslatableconnector

ActiveNeos-package[Database &amp; ORM](/categories/database)

sandstorm/gedmotranslatableconnector
====================================

Connector to make Gedmo Translatable work with Neos Flow

4.3.0(11mo ago)614.9k5PHP

Since Jul 4Pushed 11mo ago9 watchersCompare

[ Source](https://github.com/sandstorm/GedmoTranslatableConnector)[ Packagist](https://packagist.org/packages/sandstorm/gedmotranslatableconnector)[ RSS](/packages/sandstorm-gedmotranslatableconnector/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (10)Dependencies (2)Versions (19)Used By (0)

Flow Framework Connector to Gedmo Translatable
==============================================

[](#flow-framework-connector-to-gedmo-translatable)

by Sebastian Kurfürst, sandstorm|media. Thanks to Web Essentials for sponsoring this work initially. Currently maintained by [@onivaevents](https://github.com/onivaevents)

Using [Gedmo.Translatable](https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/translatable.md) in the Neos Flow framework proved a little harder than originally anticipated. This small package wraps up the necessary steps.

Getting started
---------------

[](#getting-started)

Just include this package, and then use Gedmo Translatable as explained in their documentation (e.g. using the @Gedmo\\Translatable annotation):

Make sure to clear the code cache completely in Data/Temporary after installing this package!

Furthermore, make sure to create a *doctrine migration* which creates the ext\_translations SQL table; e.g. run `./flow doctrine:migrationgenerate`

**Check out the example package at **.

This connector supports all the advanced options provided by Gedmo Translatable.

### Model Annotations

[](#model-annotations)

Just annotate your model properties which shall be localized with `Gedmo\Mapping\Annotation\Translatable`.

```
    /**
     * @var string
     * @Gedmo\Translatable
     */
    protected $title;

```

### Translating a model (low-level)

[](#translating-a-model-low-level)

```
    /**
     * Doctrine's Entity Manager. Note that "ObjectManager" is the name of the related interface.
     *
     * @Flow\Inject
     * @var ObjectManager
     */
    protected $entityManager;

    public function updateAction(Event $event) {
        /* @var $repository TranslationRepository */
        $repository = $this->entityManager->getRepository('Gedmo\\Translatable\\Entity\\Translation');
        $repository->translate($event, 'name', 'de', 'Deutscher Titel');
    }

```

### Set current language

[](#set-current-language)

In order to set the current language for *viewing*, inject the `Gedmo\Translatable\TranslatableListener` class and set the current language on it: `$translatableListener->setTranslatableLocale('de');`.

Translation management
----------------------

[](#translation-management)

### Editing multiple languages at the same time

[](#editing-multiple-languages-at-the-same-time)

- Mix-in the Trait `Sandstorm\GedmoTranslatableConnector\TranslatableTrait` and implement `\Sandstorm\GedmoTranslatableConnector\Translatable` into your model, e.g. by doing:

```
/**
 * @Flow\Entity
 */
class MyModel implements \Sandstorm\GedmoTranslatableConnector\Translatable {
  use \Sandstorm\GedmoTranslatableConnector\TranslatableTrait;

  // make sure some properties have Gedmo\Translatable annotations
}

```

- This trait adds a `getTranslations()` and `setTranslations()` method, allowing to get and set other translations of a model.
- Now, you can easily edit multiple languages by binding the form element to `translations.[language].[fieldname]`, e.g. this works like the following:

```
Name (default):
Name (de):
Name (en):

```

### Persist edited translations

[](#persist-edited-translations)

With the by default enabled `instantTranslation` setting, the translations are updated and persisted through the `Gedmo\Translatable\Entity\Repository\TranslationRepository` immediately when calling the `setTranslation` method. Often, this might not be ideal because it persists the entity right away. Disable the setting and call the `flush()` method of the `TranslatableManager` to persist the changes according to your needs.

### Fetching an object in another locale

[](#fetching-an-object-in-another-locale)

If you have loaded an object in a specific locale, but later on need to change the object to be in another locale, the method `reloadInLocale($locale)` (which is defined inside the trait `Sandstorm\GedmoTranslatableConnector\TranslatableTrait`) can be called:

```
$myModel->getName(); // will return the language which was set at the time where $myModel was fetched

$myModel->reloadInLocale('de');
$myModel->getName(); // will return *german*

```

Translating associations
------------------------

[](#translating-associations)

**Warning: this feature is not yet 100% stable; please test it and give feedback!**

Normally, associations towards other domain models such as images or assets are not translation-aware; but Translatable only works for simple properties.

The TranslatableConnector however contains some functionality to make translation of associations work; by using a little workaround: **We store the identifier of the target object in the domain model, and manually load/store from this identifier**.

This works as follows:

1. Makes sure you have the `TranslatableTrait` added to your domain class
2. e.g. to make an `Asset` reference translatable, create a new property `assetIdentifer` which is a string and will contain the asset identifier. This property should be marked as `Gedmo\Translatable`.
3. Then, you need to configure the `translationAssociationMapping`, which tells the system that the (virtual) property should `asset` should internally be stored as `assetIdentifier`.
4. Furthermore, create `assetOnSave` and `assetOnLoad` methods as outlined below, which convert the different representations

See the full example below:

```
class Event {
    use TranslatableTrait;

    /**
     * @var array
     * @Flow\Transient
     */
    protected $translationAssociationMapping = array(
        'assetIdentifier' => 'asset'
    );

    /**
     * @Gedmo\Translatable
     * @var string
     */
    protected $assetIdentifier;

    /**
     * @Flow\Inject
     * @var AssetRepository
     */
    protected $assetRepository;

    /**
     * @Flow\Inject
     * @var PersistenceManagerInterface
     */
    protected $persistenceManager;

    /**
     * @Flow\Inject
     * @var PropertyMapper
     */
    protected $propertyMapper;

    /**
     * @return \Neos\Media\Domain\Model\Asset
     */
    public function getAsset() {
        return $this->assetOnLoad($this->assetIdentifier);
    }

    /**
     * !!! This accepts the raw array as the user uploaded it; as we need to trigger the property mapper inside
     *     assetOnSave manually.
     *
     * @param array $asset
     */
    public function setAsset($asset) {
        $this->assetIdentifier = $this->assetOnSave($asset);
    }

    /**
     * This method is called in two places:
     * - inside setAsset()
     * - automatically by the TranslatableTrait
     *
     * @param array $asset
     */
    public function assetOnSave($asset) {
        $asset = $this->propertyMapper->convert($asset, 'Neos\Media\Domain\Model\AssetInterface');
        if ($asset === NULL) {
            $this->assetRepository->remove($asset);
            return NULL;
        } elseif ($this->persistenceManager->isNewObject($asset)) {
            $this->assetRepository->add($asset);
            return $this->persistenceManager->getIdentifierByObject($asset);
        } else {
            $this->assetRepository->update($asset);
            return $this->persistenceManager->getIdentifierByObject($asset);
        }
    }

    /**
     * This method is called in two places:
     * - inside getAsset()
     * - automatically by the TranslatableTrait
     *
     * @param array $asset
     */
    public function assetOnLoad($assetIdentifier) {
        return $this->assetRepository->findByIdentifier($assetIdentifier);
    }
}

```

Inner Workings
--------------

[](#inner-workings)

(as a further reference -- could also be reduced if we change Flow Framework a little on the relevant parts)

- Settings.yaml: Ignore Gedmo namespace from Reflection, adds the Translatable Listener as Doctrine Event listener. This part is pretty standard for using other Gedmo Doctrine extensions as well.
- Objects.yaml: Mark the `TranslatableListener` as singleton, such that you can inject it into your classes and set the current language. This part was straightforward as well.
- Package.php: Make the entities of Gedmo Translatable known to Doctrine and in Reflection. This was quite tricky to archive, see the inline docs in the class how this was done.

Further recommendation
----------------------

[](#further-recommendation)

- Use [ORM query hints](https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#using-orm-query-hint) when working with Gedmo Translatable to speed up queries.
- Use [translation entities](https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#translation-entity) if you have large datasets with many translations.

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance50

Moderate activity, may be stable

Popularity28

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 68.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~157 days

Recently: every ~233 days

Total

17

Last Release

354d ago

Major Versions

1.0.0 → 2.0.02019-07-02

2.4.4 → 3.0.02020-10-09

3.0.1 → 4.0.02022-11-04

### Community

Maintainers

![](https://www.gravatar.com/avatar/2ced0d63cfdae881c32128c7f66451a013d3e24d9eed210d6a846b6d8e95fa3b?d=identicon)[sandstorm](/maintainers/sandstorm)

---

Top Contributors

[![simstern](https://avatars.githubusercontent.com/u/2580285?v=4)](https://github.com/simstern "simstern (28 commits)")[![skurfuerst](https://avatars.githubusercontent.com/u/190777?v=4)](https://github.com/skurfuerst "skurfuerst (13 commits)")

---

Tags

doctrineflowphp

### Embed Badge

![Health badge](/badges/sandstorm-gedmotranslatableconnector/health.svg)

```
[![Health](https://phpackages.com/badges/sandstorm-gedmotranslatableconnector/health.svg)](https://phpackages.com/packages/sandstorm-gedmotranslatableconnector)
```

###  Alternatives

[stof/doctrine-extensions-bundle

Integration of the gedmo/doctrine-extensions with Symfony

1.9k85.3M381](/packages/stof-doctrine-extensions-bundle)[kimai/kimai

Kimai - Time Tracking

4.6k7.4k1](/packages/kimai-kimai)[sylius/resource

Basic resource interfaces for PHP applications.

252.7M65](/packages/sylius-resource)[nettrine/extensions-atlantic18

Doctrine2 behavioral extensions for Nette Framework

12922.2k3](/packages/nettrine-extensions-atlantic18)[mediamonks/doctrine-extensions

Doctrine2 behavioral extensions which allows to transform (encrypt, decrypt, hash) your data automatically

14280.9k](/packages/mediamonks-doctrine-extensions)[rixxi/gedmo

Gedmo Doctrine Extensions integration into Nette Framework using Kdyby/Doctrine

1368.2k1](/packages/rixxi-gedmo)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
