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

Translation Bundle Laravel Package

lordjancso/translation-bundle

Symfony bundle that centralizes translation management, letting you edit, organize, and maintain multilingual strings through a database-backed workflow instead of hand-editing language files. Integrates into existing projects to keep translations in sync.

View on GitHub
Deep Wiki
Context7

Getting Started

Stack reality check first. This is a Symfony bundle, not a Laravel package. There is no service provider, no config/translation.php, no Facade, and the TranslatorInterface decoration targets Symfony's DI container. Day-to-day leverage from a Laravel seat is one of three things: (a) you're maintaining a Symfony app in a mixed fleet and this is a candidate for that app, (b) you're evaluating it as a reference pattern to port into Laravel, or (c) it doesn't apply to your work. Be honest with yourself about which of those is true before installing anything.

Minimal install (Symfony only):

composer require lordjancso/translation-bundle
  1. Register the bundle manually in config/bundles.php — don't rely on Flex recipes for an unmaintained bundle.
  2. Configure a database connection explicitly. Prefer a dedicated entity manager or connection so translation tables don't live alongside application data.
  3. Run the bundle's migration/import step to create locale and message tables.
  4. Import existing YAML/XLIFF catalogs so you start from a known-good baseline rather than an empty table.
  5. Clear the translation cache (bin/console cache:clear). Every subsequent write path needs the same treatment — see Gotchas.
  6. Wire the bundle's admin routes behind your security.yaml firewall before exposing them.

Where to look first. Read the bundle's Doctrine entities and the TranslationLoader / translator decoration layer — that's roughly 80% of the day-to-day behavior. Then read the admin controller and routes for auth and input validation, because you will own securing them.

First use case to prove. Import messages.en.yaml plus one non-English locale, edit a single string in the admin UI, hit a page that renders that key, confirm the new value appears without a deploy. This exercises the full loop — DB write → cache → translator → view — in an afternoon and surfaces most integration problems immediately.

If you're porting to Laravel instead: the pattern to replicate is (1) locales and translations tables keyed on (locale, domain, key), (2) a custom LoaderInterface implementation registered against Laravel's translator singleton, (3) an artisan import/export command, (4) a Filament/Nova CRUD screen behind auth and a policy. That's roughly a day of work and preserves your existing auth, middleware, and deployment model.

Implementation Patterns

Keep application call sites unchanged. The whole point is that $translator->trans('messages.welcome', [], 'messages', 'fr') keeps working — the bundle swaps the loader underneath. Do not import bundle classes into your controllers or services. If you find yourself doing that outside the admin surface, you've drifted.

Import → edit → export is the round-trip cycle. Pick a direction for "source of truth" and be dogmatic about it:

  • Import on setup or deploy (idempotent, safe to re-run).
  • Edit in the admin UI or via a bulk CSV/XLSX import command.
  • Export to YAML/XLIFF and commit it.

Treating the DB as authoring state and files as publishable state avoids the merge-conflict and "which copy is right" class of problem. Mixing both directions ad hoc is how catalogs get corrupted.

Locale list is a first-class lookup. Drive your language switcher, fallback chain, and "what needs translating" report off the bundle's locale entity rather than hardcoding locales in config. Adding a locale becomes: create locale → import or author its messages → verify fallback behavior.

Cache invalidation is a workflow step, not an implementation detail. Symfony compiles translator catalogs. Every write path — admin save, import command, manual DB edit — needs a corresponding cache clear. Wrap it in the save action if the bundle doesn't already, and verify the wrapping actually happens, because a stale cache is the #1 "it's broken" report you'll hear from translators.

Secure the admin surface explicitly. Import the bundle routes behind a firewall prefix (e.g. /admin/translations) with a role check such as ROLE_TRANSLATOR or ROLE_ADMIN. In regulated or multi-tenant environments, add IP allowlisting as well. A web-facing translation editor is a stored-XSS and content-tampering surface; the bundle is unlikely to ship hardened defaults.

Pair with translation:extract and lint:translations in CI. Export to files in your pipeline, run extract to catch keys added in code but missing from the catalog, and run lint to catch malformed/duplicate entries. If you skip this, you lose the checks you get for free with file-based translations.

Decorate, don't modify. If you need tenant scoping, audit logging, or a different cache strategy, decorate the bundle's loader/translator service via services.yaml. Keeping vendor code untouched preserves your ability to pull patches and makes a future fork a merge rather than a rewrite.

Gotchas and Tips

The stack mismatch never stops being a gotcha. Every Laravel-side "how do I…" question resolves to "you don't" — you either run a Symfony sidecar against the same DB or you port the pattern. Budget evaluations as a Symfony platform task, not a Composer install.

Zero community signal is a hard operational constraint. 0 stars, 0 dependents, single maintainer. Before writing code: check the last commit date, skim open issues, and verify the symfony/* and php constraints in composer.json against your LTS target. If there's no compatible release, a compatibility fork costs more than the Laravel port. The honest answer in that case is "no."

The cache is your debugging trap. When an edited translation "doesn't show up," check in this order: (1) clear the cache, (2) verify the (locale, domain, key) row exists in the DB, (3) verify the domain argument in your template matches — trans('messages.welcome', [], 'admin') will not find a row stored under messages. Domain mismatches are the most common silent failure here.

Concurrency is on you. Two editors saving the same key will race; the bundle likely has no optimistic locking. Mitigations, from cheapest: restrict editing to one or two named roles; add an updated_at check in your own save wrapper; or move to a branch-and-PR workflow where the DB is authoring-only and files are the artifact.

Auth is your job, not the bundle's. Symfony convention is to leave firewall configuration to the app. Assume the routes ship unprotected and assume input validation on message values is minimal. Review the controller before exposing it beyond a trusted group.

Test against a real database. Because the load path is Doctrine queries plus a warmed cache, mocked unit tests won't catch the failures that matter (wrong domain, stale cache, wrong locale fallback). Wire up an ephemeral SQLite or MySQL in CI and exercise the full translator path at least once.

Keep the DB out of the request path if you can. Translations are read on every request. If a Doctrine fetch is on the hot path for a high-traffic app, measure it — a translator warm cache should be fine, but if it isn't, your options are a Redis-backed loader or exporting to files for production with the DB used only in staging/editing.

Document the exit plan now, not when it breaks. Pin the commit SHA (or vendored source), record which files you'd modify in a fork, and name an owner. MIT licensing makes this legally clean; the engineering cost is what you're booking at adoption time, not something you should discover later.

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