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

Backend Translations Tool Bundle Laravel Package

modera/backend-translations-tool-bundle

Modera Backend Translations Tool Bundle provides a backend interface for managing translations in PHP applications. Browse, edit, and organize translation messages from one place, helping teams streamline localization workflows and keep multilingual content consistent.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the reality check: despite the "php package" cataloguing, modera/backend-translations-tool-bundle is a Symfony 2/3-era bundle built for MJR (Modera Junior Runtime), Modera's in-house admin framework. It has no service provider, no config publishing, no Blade/Livewire views, and no Eloquent models — there is nothing to composer require into a Laravel app. It has been read-only since 2016-06-17, with 0 stars, 0 dependents, 0 releases since 2016. As a Laravel developer, you "leverage" this package almost exclusively as prior art: a reference implementation of a translation-editing admin screen you will rebuild natively.

Where to look first (read-only, on GitHub, not in your vendor/):

  1. ModeraBackendTranslationsToolBundle.php — the bundle class; shows which MJR sections it registers into the backend menu.
  2. Resources/config/services.xml — the services that actually read and write translation catalogues. This is where the real logic lives; everything else is UI plumbing.
  3. Resources/config/routing.yml — the JSON-RPC endpoints the ExtJS grid hits (list, filter, save, import/export).
  4. Resources/public/js/... — the ExtJS grid/editor. Skim for the field set and workflow; ignore the implementation — it is not portable to Livewire/Inertia/React and is hostile to mobile.

If you are inheriting a legacy MJR/Symfony app (the only scenario where you install it), the minimal steps are:

composer require modera/backend-translations-tool-bundle

Register it in AppKernel::registerBundles(), after the MJR core and the sibling translations bundle it depends on:

new Modera\BackendTranslationsToolBundle\ModeraBackendTranslationsToolBundle(),

Clear the Symfony cache, log into the MJR backend (/backend), and look for Tools → Translations in the left nav. If the menu item is missing, the sibling ModeraBackendTranslationsBundle (the actual storage/extraction logic) is not installed — this bundle alone is presentation only.

First use case for a Laravel developer: treat the screens as a requirements checklist for a small in-house tool. The realistic first use is answering "what should our translation admin contain?" — scoping by bundle/domain, per-locale coverage views, missing-key detection, inline edit, import/export, cache-bust on save. Then budget a one- to two-sprint build over spatie/laravel-translation-loader (DB-backed) or a thin CRUD over your lang/ files.

Implementation Patterns

Since you cannot install this on Laravel, the useful "patterns" are the contract and UX the bundle encodes, which you reimplement natively.

1. The catalogue grid contract. The bundle organises translations by the tuple (domain, locale, key). That three-part composite key is the right shape for your own translations table:

Schema::create('translations', function (Blueprint $t) {
    $t->id();
    $t->string('domain')->default('messages'); // bundle's "domain" / namespace
    $t->string('locale', 8);
    $t->string('key');
    $t->text('value')->nullable();
    $t->timestamps();
    $t->unique(['domain', 'locale', 'key']);
    $t->index(['locale', 'domain']);
});

This mirrors the bundle's filter-by-domain-and-locale UI, and it is the shape the missing-key detection and coverage views run against.

2. List → filter → edit → save → publish/clear-cache. The bundle's workflow is exactly this five-step loop, driven over MJR's JSON-RPC endpoints. In Laravel this maps cleanly to a Livewire or Inertia screen backed by a thin JSON controller. The "publish/clear cache" step is the one people forget — in Symfony the bundle leans on the framework cache warmer; in Laravel you must explicitly bust cache on save (see Gotchas).

3. Missing-key detection by scanning source files. The bundle scans templates and source files for translation keys and flags the ones absent from the catalogue. Reimplement directly with a queued job or Artisan command:

// Rough shape: scan app/ and resources/views for __('...') / @lang('...')
$found = collect(File::allFiles(resource_path('views')))
    ->flatMap(fn ($f) => preg_match_all("/@lang\\(['\"]([\w.\-]+)['\"]/", $f->getContents(), $m) ? $m[1] : []);
$missing = $found->diff(Translation::forLocale($locale)->pluck('key'));

Run this on a schedule, not on page load — the scan cost grows with the source tree and belongs out of the request cycle.

4. Per-locale coverage views. The bundle's "unified multi-locale overview" is the single most useful thing it ships: a matrix of keys × locales with present/missing cells. This is what makes "can we ship locale #4?" answerable without a developer. Build it as a query over the table above (a COUNT of expected vs. present per locale), not as an in-memory ExtJS store.

5. Import/export. The bundle supports exchanging catalogue files. On Laravel, wire this to php artisan lang:import / lang:export operating on YAML or PHP-array files from lang/, or CSV for translators. Always round-trip through the same key normalisation as the grid, or import/export will drift from what the UI shows.

6. Integration tip — pick one source of truth. The bundle assumes the Symfony catalogue is authoritative and writes back to it. If you build natively, decide up front: files in lang/ (simple, git-reviewable, but no edit-without-deploy) or a translations table (edit-without-deploy, but you need cache-busting and a sync story). Do not run both as writable sources.

Gotchas and Tips

  • It will not install on PHP 8 / Symfony 5–7 / Laravel. 2016 vintage means PHP 5.6–7.0-era code and Symfony 2.x/3.x service definitions. Do not composer install --ignore-platform-reqs into a production image to "try it" — you will pull in unpatched transitive dependencies into an authenticated write path. If you must spike it, do it in a throwaway container and expect failure.
  • The bundle is presentation-only. It depends on sibling Modera bundles (ModeraBackendTranslationsBundle, MJR itself) that are not pulled in by this repository alone. If you register it and see no Translations menu, the siblings are missing — and those siblings may no longer resolve on Packagist. The read-only split means issues and PRs are not accepted here.
  • Zero maintenance, zero security feed. Read-only mirror, no issue tracker, no advisories. Any fix you make is a permanent local fork you must patch and re-audit on every PHP/framework bump. Weigh this against a 1–3 sprint native build.
  • Cache staleness is the #1 failure mode for any homegrown translation admin (this bundle included). Editing a translation without invalidating the compiled catalogue lets editors "save" changes that never appear in production. On the Laravel side, bust the cache explicitly on save:
DB::transaction(fn () => $t->update($data));
Cache::forget("translations.{$locale}.{$domain}");
Artisan::call('cache:clear'); // or a targeted forget, on the write path
  • Missing-key fallback hides gaps. Laravel renders the raw key when a translation is absent — so an incomplete locale looks "fine" until a user hits an untranslated screen. Do not rely on runtime fallback; surface the missing-key report in CI or on a scheduled job.
  • Split-brain source of truth. Locale/key drift between DB rows and file-based catalogues produces two competing answers. If you adopt spatie/laravel-translation-loader or a translations table, make the DB authoritative and keep files as seed/export only.
  • Pluralisation and TMS features are absent. The bundle has no pluralisation rules, no translation memory, no Crowdin/Lokalise/Phrase integration. If you need those — and at scale you will — go to a hosted TMS; do not extend this design.
  • Ramp-up is non-transferable. ExtJS + MJR RPC + Symfony 2.x bundle wiring has near-zero residual value on a Laravel team. Budget the sunk investigation (roughly 2–3 days to reach "build it ourselves") and skip straight to the native build if the team is already Laravel-fluent.
  • Scale is not the concern — coherence is. Catalogues are small (thousands to low tens of thousands of keys); the hard part is keeping editor saves, compiled caches, and file-based fallbacks in agreement. Design the cache-invalidation path first, then the CRUD.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource