kunstmaan/translator-bundle
A Symfony bundle for managing translations across your project with a web interface for editing, importing, and exporting language files. Supports multiple translation backends and integrates with the Kunstmaan CMS ecosystem.
First, the reality check for a Laravel developer: this is not a Laravel package. It's a Symfony 2-era bundle from the Kunstmaan CMS stack (last release 2014-08-01, PHP 5.x, AppKernel registration, Sonata-style admin). There is no service provider, no config/ publish tag, and zero dependents. You cannot composer require it into a Laravel app. Evaluate it as a reference implementation of a pattern — DB-backed, admin-editable translations with a cached read path — not as a dependency.
If you are on a Kunstmaan CMS install (the only place it actually runs):
composer require kunstmaan/translator-bundle (pin to a Symfony 2.x-compatible tag).AppKernel.php after KunstmaanAdminBundle, and import the bundle's admin routing.doctrine:schema:update (or the bundle's migration) to create the translation table.Where to look first, in this order:
Resources/config/services.yml — the bundle's whole trick lives here: it decorates/overrides the translator service with its own implementation.Entity/Translation.php + Repository/TranslationRepository.php — the storage model (locale, domain, key, value).Translator/ — the decorator that reads from the repository rather than only from translations/*.yml.Command/ — import/export commands (check bin/console list for the exact names).First use case: replace a hardcoded key. In Twig, {{ 'checkout.vat_note'|trans }} still works unchanged; the string now resolves from the DB row an editor creates in the admin, with the file catalogue as fallback. That drop-in compatibility is the reason to consider the pattern at all.
Laravel equivalent you'd actually ship:
composer require spatie/laravel-translation-loader
php artisan vendor:publish --provider="Spatie\TranslationLoader\TranslationServiceProvider"
php artisan migrate
Then add a Filament/Livewire resource over the language_lines table. Same architecture, modern runtime.
Decorate, don't replace. The bundle's design keeps |trans untouched by swapping the translator service; nothing in templates or PHP changes. Replicate this by registering a DB-backed loader before the file loader, not by rewriting your call sites.
File-first, DB-second migration. Don't point the DB at an empty table. Seed from your existing YAML so every current key resolves before editors start adding new ones. The import command does this; in Laravel, iterate lang/**/*.php into language_lines.
Export is your release gate. The bundle ships an export command that writes DB content back to files. Do this in CI (or at minimum before a deploy) so:
Limit the blast radius with manage_domain. Configure only your application domain (e.g. messages) as editable; leave vendor/bundle strings in files. Otherwise editors can silently break third-party UI text and you'll never get it back.
# Kunstmaan-era config shape (verify against your pinned version)
kunstmaan_translator:
enabled: true
manage_domain: [messages]
cache: true
Deployment workflow. Migrate the schema → import/seed content → warm the translator cache → run debug:translation-style checks for missing keys. The DB is content, so treat it like you'd treat CMS pages: seedable, exportable, never the source of truth for a code review.
Laravel-side pattern:
// config/translation-loader.php
'translation_loaders' => [
DatabaseTranslationLoader::class,
FileLoader::class, // fallback order matters
],
Plus a translations:import / translations:export artisan pair, and cache busting in the model's saved/deleted events.
debug:container translator and by running your missing-key check in the prod environment.doctrine:schema:update/migrate:fresh silently wipe editorial content in staging.:count or {name}. Add a placeholder validator on save — this is the single most common production bug in DB-backed translation systems.updated_by/updated_at audit column, a "missing keys" report generated from a static scan of templates, and per-key context notes. The 2014 bundle predates all of this; a modern Laravel port should bake it in.spatie/laravel-translation-loader plus a Filament translation resource gives you 90% of this bundle's value on a supported stack, and lets you own the cache-invalidation story instead of inheriting a Symfony 2 one.How can I help you explore Laravel packages today?