Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Translatable Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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):

  1. Register the bundle in config/bundles.php:
    Prezent\DoctrineTranslatableBundle\PrezentDoctrineTranslatableBundle::class => ['all' => true],
    
  2. Configure it (minimal):
    # config/packages/prezent_doctrine_translatable.yaml
    prezent_doctrine_translatable:
        fallback_locale: en
    
  3. Make a translatable entity by implementing Prezent\Doctrine\Translatable\TranslatableInterface and using TranslatableTrait from the underlying prezent/doctrine-translatable library.
  4. Generate the companion *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.

Implementation Patterns

  • Entity + translation entity pair. Define 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.
  • Current locale is the driver. Everything hinges on what the 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.
  • Read/write through the proxy. $product->setName('Shirt') writes to the current-locale translation; $product->getName() reads current-locale with fallback. $product->translate('fr')->getName() forces a specific locale.
  • Persisting translations. Use cascade persist on the translations collection, or explicitly $em->persist($product->translate('de')->setName('Hemd')) before flush(). Inconsistent handling here is the most common source of orphan rows.
  • Form/admin layer. Expose one tab per locale in your Symfony form by embedding ProductTranslationType collections; on the Laravel side this maps to per-locale form sections that hydrate the translation relation.
  • Querying per locale. Filters and repository methods must join the translation table and constrain by locale — the extension does not auto-filter findAll(), so plan a repository base class that adds :locale = :currentLocale (with fallback in WHERE/CASE) if you need listing integrity.
  • Cache invalidation. In Symfony wrap mutations in a transaction and clear the relevant cache pools after flush; translated fields are hydrated lazily and stale second-level caches will serve the wrong locale.

Gotchas and Tips

  • It is not a Laravel package. No config/prezent.php, no facade, no artisan commands. Any integration into Laravel is custom glue around prezent/doctrine-translatable — expect to own that glue.
  • 14 stars and 0 dependents means effectively unmaintained in practice. Pin the version, read every line of the listener, and be prepared to fork. Check compatibility with your Doctrine ORM/PHP version before committing.
  • The bundle only registers services. All actual behavior lives in prezent/doctrine-translatable; when debugging, look there — the bundle is a thin Symfony DI shim.
  • Fallback is not automatic on writes. Reading a missing translation falls back; writing only occurs in the current locale, so a partially translated product will silently serve fallback text until someone edits that locale. Add a "translation completeness" check in your admin.
  • Schema tool drift. Because translations are stored in a separate table, a doctrine:schema:validate failure usually means the translation entity mapping was not picked up — confirm both entities are under a scanned mapping path.
  • Listener registration order. If the translatable listener is not registered before your query filters run, locale filtering appears to "randomly" stop working. Verify with $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.
  • Do not mix TranslatableTrait with Gedmo's Translatable on the same entity; both attach listeners to loadClassMetadata and will fight over the mapping.
  • Debugging tip: when 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.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo