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

Translatable Bundle Laravel Package

softspring/translatable-bundle

A Symfony bundle for building translatable Doctrine entities, letting you store and manage per-locale field values with locale fallback, so the same content can be served in multiple languages without duplicating your models or templates.

View on GitHub
Deep Wiki
Context7

Getting Started

First, resolve the identity mismatch. This is a Symfony bundle built on Doctrine ORM — not a Laravel/Eloquent package. It adds entity listeners and per-locale translation tables to Doctrine entities. There is no Eloquent analogue, no service provider, no HasTranslations trait. If the target is a pure Laravel app, stop here; the day-to-day workflow below does not transfer. If your portfolio includes Symfony services (or you maintain one inside a Laravel-heavy org), treat it as a service-level dependency and read on.

Minimal steps (Symfony):

  1. composer require softspring/translatable-bundle:^5.6
  2. Register in config/bundles.php (Symfony 5.4+/6).
  3. Configure locales and fallback chain in config/packages/softspring_translatable.yaml — this file is the whole surface area; there is no large config tree.
  4. Mark translatable fields on an entity (attributes on modern Symfony, annotations on older) and let the bundle's listener persist translations.
  5. php bin/console doctrine:schema:update --dump-sql → review → migrate.

Where to look first. The docs are thin and the v5.6.0 release body is an empty diff link, so:

  • vendor/softspring/translatable-bundle/src/ — the event subscriber/listener, the mapping driver, and DependencyInjection/Configuration.php. The Configuration class is the authoritative spec for locale/fallback semantics.
  • vendor/softspring/translatable-bundle/tests/ — the bundle's own test entities are the working examples. Read these before the README.
  • https://github.com/softspring/translatable-bundle/compare/v5.5.10...v5.6.0 — the only real release content for 5.6.0.

First use case: a single Article entity with title, slug, body translatable, two locales, fallback to default. Write in the current request locale, render in the requested locale, verify the fallback fires when a translation row is missing. That vertical slice exercises mapping, listener, persistence, and locale resolution — the four things that can go wrong.

Implementation Patterns

Read/write in the request locale. Set _locale via Symfony routing or a LocaleListener; the bundle resolves against that. For admin/forms, use per-locale tabs and switch the translator locale before form binding, or you will bind into the wrong translation row.

Fallback chains are config, not code. Define an ordered list (e.g. requested → regional parent → default). Because fallback is silent by design, you need tests that assert which locale's value came back, not just that a value came back.

Querying without N+1. Translations are a collection; listing pages will explode into one query per row. Join-fetch the translation for the active locale in DQL, or accept a locale-filtered repository method. Index (translatable_id, locale) — the bundle's schema may or may not generate this; check the --dump-sql output.

Migration patterns, by starting state:

  • Greenfield: install at ^5.6, define translatable entities, generate the schema, backfill default-locale rows in a fixture or data migration.
  • Existing columns/JSON: this is a data migration plus a dual-read window, not a library swap. Scope it as the expensive path it is.
  • Already on 5.5.x: bump constrained to ^5.5.10|^5.6, then require an empty doctrine:schema:update --dump-sql. Make that a CI gate, not a manual step.

Serialization/API. Normalise per Accept-Language, and key any cache by locale. Emit Vary: Accept-Language on HTTP responses or CDNs will serve the wrong language.

Testing pattern. Functional tests that (a) assert fallback ordering, (b) run doctrine:schema:validate, (c) load fixtures with the locale explicitly set rather than inherited from the test's environment.

Gotchas and Tips

  • Not a Laravel package. The single biggest pitfall. Bolting Doctrine into Laravel just for this is weeks of ramp-up (unit of work, entity listeners, migrations) against a one-day job in Eloquent. The bundle is not the cost — Doctrine is.
  • AGPL-3.0. Copyleft with a network-use clause. If you are distributing or SaaS-hosting, get legal review before adopting. This alone is a stop sign for many Laravel shops accustomed to MIT.
  • v5.6.0 has no changelog. The release body is an auto-generated diff link. Read the actual compare diff and the composer.json constraint changes before upgrading. A minor bump touching entity persistence can change fallback order, proxy handling, or hydration — and those surface as data bugs, not exceptions.
  • Silent fallback regression is the primary failure mode. Content renders in the wrong language, tests pass, users see it. Always assert the resolved locale in tests.
  • Schema drift. A minor release can alter column types, indexes, or association mappings. A non-empty --dump-sql that "looks benign" is the thing to review hardest.
  • Locale leakage in long-running workers. RoadRunner/Swoole-style workers keep state between requests. Reset the translator locale per request or one user's language bleeds into the next.
  • Cascade/orphan removal on the translation collection must be explicit; missing orphanRemoval leaves orphaned rows across locales.
  • null vs empty string. Decide what "untranslated" means and test it. Fallback triggering depends on this and the bundle's answer may not be yours.
  • Extension points are the locale resolver and the translation entity mapping — check src/ for the resolvable service ID and override in services.yaml rather than forking. Forking an AGPL package has licensing consequences.
  • Debugging: debug:event-dispatcher to confirm the listener is registered; the Doctrine SQL logger to count queries per locale; doctrine:schema:validate in CI.
  • Pin ~5.5.10 on existing consumers until you have read the 5.6.0 diff. High cadence plus no changelog discipline is how dependency management becomes archaeology.
  • No SLA, no confirmed security advisory channel, single vendor. Record it on the risk register rather than assuming a small package will be maintained.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
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