prezent/doctrine-translatable-bundle
A Symfony bundle that adds translatable behavior to Doctrine entities, letting you store and retrieve localized field values through Doctrine ORM. It simplifies multilingual content models and translation management in Symfony applications with minimal, flexible configuration.
composer require prezent/doctrine-translatable-bundle
This is a Symfony bundle, not a Laravel package — there is no service provider, facade, or config file in config/. If you are working in a Laravel codebase you will not be able to use it as-is; you would have to manually bootstrap its Doctrine event subscribers inside a custom service provider and register the TranslatableListener yourself. For a pure Laravel project, look at astrotomic/laravel-translatable or spatie/laravel-translatable instead.
If you are in a Symfony app (or a hybrid app where Doctrine is the ORM):
config/bundles.php:
Prezent\DoctrineTranslatableBundle\PrezentDoctrineTranslatableBundle::class => ['all' => true],
# config/packages/prezent_doctrine_translatable.yaml
prezent_doctrine_translatable:
fallback_locale: en
Prezent\Doctrine\Translatable\TranslatableInterface and using TranslatableTrait from the underlying prezent/doctrine-translatable library.*Translation entity (extends AbstractTranslation), run doctrine:schema:update or a migration to create the translation table.First use case: a Product entity whose name and description should exist per locale. You write the translatable entity once, the bundle wires the Doctrine listener that routes field reads/writes to the translation row matching the current locale.
Product (translatable) and ProductTranslation (holds the translated fields). The bundle relies on the naming convention from the extension — do not rename the translation class arbitrarily without overriding the mapping.TranslatableListener considers the current locale. In a Symfony app you typically set it from a request subscriber:
$listener->setCurrentLocale($request->getLocale());
$listener->setFallbackLocale('en');
From Laravel you would need an equivalent middleware that calls into the listener before any query hits the DB.$product->setName('Shirt') writes to the current-locale translation; $product->getName() reads current-locale with fallback. $product->translate('fr')->getName() forces a specific locale.translations collection, or explicitly $em->persist($product->translate('de')->setName('Hemd')) before flush(). Inconsistent handling here is the most common source of orphan rows.ProductTranslationType collections; on the Laravel side this maps to per-locale form sections that hydrate the translation relation.findAll(), so plan a repository base class that adds :locale = :currentLocale (with fallback in WHERE/CASE) if you need listing integrity.config/prezent.php, no facade, no artisan commands. Any integration into Laravel is custom glue around prezent/doctrine-translatable — expect to own that glue.prezent/doctrine-translatable; when debugging, look there — the bundle is a thin Symfony DI shim.doctrine:schema:validate failure usually means the translation entity mapping was not picked up — confirm both entities are under a scanned mapping path.$em->getEventManager()->getListeners('loadClassMetadata').setCurrentLocale must run before the entity is loaded, not after — once the proxy hydrates, the locale is baked into the field values. Set it in middleware/kernel request, never in a controller action.TranslatableTrait with Gedmo's Translatable on the same entity; both attach listeners to loadClassMetadata and will fight over the mapping.getName() returns the original-language string unexpectedly, dump $product->getTranslations() and $listener->getCurrentLocale() — the bug is almost always an unset locale or a missing translation row, not the bundle.How can I help you explore Laravel packages today?