ibrows/sonata-translation-bundle
A Symfony bundle that integrates translation management into Sonata Admin, giving editors an admin interface to view and edit application translations directly. It streamlines multilingual content workflows and reduces manual edits to translation files.
This bundle is a thin Sonata Admin layer over lexik/translation-bundle: it exposes Lexik’s TransUnit, Translation, File, and FileVersion entities as Sonata admins so editors can manage translation keys and values from /admin instead of editing YAML/XLIFF files. Treat it as a UI bundle, not a translation engine.
Verify compatibility before installing. The package has 1 star, 0 dependents, and no asserted license. Check its composer.json constraints against your Symfony, SonataAdminBundle, and LexikTranslationBundle versions. On modern Symfony/Sonata it may not install without a fork or version pin.
Install and configure Lexik first. The bundle depends on Lexik’s ORM storage being active:
# config/packages/lexik_translation.yaml
lexik_translation:
fallback_locale: en
managed_locales: [en, de, fr]
storage:
type: orm
object_manager: doctrine.orm.default_entity_manager
Then create Lexik’s tables:
php bin/console doctrine:schema:update --force
# or generate/run a migration for the lexik_translation tables
Register the bundles and routing. Enable LexikTranslationBundle and IbrowsSonataTranslationBundle in your kernel/bundles config, then ensure Sonata’s admin routes are available. Most Sonata admin routes are generated from the sonata.admin service tag, but check the bundle’s Resources/config/routing.* for any additional routes.
Expose the admins in the Sonata menu. The bundle registers admin services (commonly under IDs such as ibrows_sonata_translation.admin.trans_unit). Confirm the exact IDs in the bundle’s Resources/config/admin.xml, then add them to a dashboard group:
sonata_admin:
dashboard:
groups:
translations:
label: Translations
items:
- ibrows_sonata_translation.admin.trans_unit
First use case: log into Sonata Admin, open the translation-unit admin, filter by domain and key, edit the value for a locale, save, clear the translator cache, and verify the string changes on the frontend.
Use Lexik’s entities as the source of truth. The admin edits TransUnit records and their child Translation records. TransUnit holds the key/domain; each Translation holds a locale and value. If your form does not include the translations collection, you will create keys with no values.
Extending the provided admins is the normal customization path. Subclass the bundle’s admin and override configureFormFields(), configureListFields(), configureDatagridFilters(), or configureRoutes():
class TransUnitAdmin extends \Ibrows\Bundle\SonataTranslationBundle\Admin\TransUnitAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('domain')
->add('key')
->add('translations', 'sonata_type_collection', [
'by_reference' => false,
'required' => false,
], [
'edit' => 'inline',
'inline' => 'table',
]);
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('domain')
->add('key');
}
}
Register it as a replacement for the bundle’s service ID, or define your own sonata.admin-tagged service and remove/disable the original if you need full control.
Make locale editing explicit. Editors usually think in terms of “the German value for key X.” Build list/filter views around domain, key, and locale, and use Lexik’s managed_locales as the allowed set. Avoid free-text locale fields; they create orphan Translation rows.
Integrate with Lexik’s import/export workflow. Decide early whether the database or the files are canonical:
lexik:translations:export to write files for deployment.auto_import disabled or run lexik:translations:import --force deliberately; otherwise admin edits can be overwritten on cache warmup or deploy.Use Lexik’s managers for bulk/programmatic operations. For fixtures, migrations, or custom admin actions, prefer TransUnitManager over manually constructing entities:
$transUnit = $transUnitManager->createTransUnit('checkout.title', 'messages');
$transUnitManager->addTranslation($transUnit, 'de', 'Kasse', false);
$transUnitManager->flush();
This avoids unique-constraint violations from duplicate key/domain pairs.
Secure and scope the admin. Translation editing is effectively application configuration editing: a bad value can break the admin UI itself. Restrict these admins to a dedicated role and consider read-only or super-admin-only access for production.
Override presentation with Sonata’s template config rather than editing the bundle. Set templates on the admin service or in sonata_admin configuration. This is more upgrade-safe than modifying vendor templates.
Maintenance risk is the biggest gotcha. With 1 star, 0 dependents, no asserted license, and a very low health score, expect stale Sonata APIs and no upstream fixes. Do a legal/license review, pin exact versions, and be prepared to fork. The bundle is thin enough that replacing it with 2–3 custom Sonata admins over Lexik entities is often cheaper than fighting compatibility.
Sonata Admin API drift. Sonata 2.x and 3.x differ in Admin base classes, form types (sonata_type_collection vs. newer alternatives), template paths (SonataAdminBundle:CRUD:... vs. @SonataAdmin/CRUD/...), and route generation. An old bundle version will likely need template and form-type overrides.
Do not duplicate Lexik’s Doctrine mapping. The Lexik entities are mapped by Lexik; your admin should reference Lexik\Bundle\TranslationBundle\Entity\TransUnit and friends. Duplicate mappings or a mismatched entity manager cause “table not found” and “unknown entity” errors.
ORM storage must actually be enabled. If lexik_translation.storage.type is not orm, the Sonata admins will have nothing to manage. Confirm the configured object_manager matches the admin’s manager_type: orm.
Caches hide edits. Changes may not appear until the translator cache is cleared. Use php bin/console cache:clear in the affected environment, and remember that Lexik may maintain its own translation cache.
auto_import can silently discard admin edits. If Lexik is configured to import files on cache warmup or deploy, database edits made in Sonata may be overwritten. Align this setting with your chosen source of truth.
Unique constraints surface as 500s. Creating a duplicate key in the same domain triggers a database exception. Catch it in a custom admin action or route creation through TransUnitManager, which handles lookups safely.
Avoid managing File and FileVersion casually. These records describe Lexik’s import/export state. Editing or deleting them through Sonata can corrupt import metadata and produce confusing “translation missing” behaviour.
Beware of editing the admin’s own labels. Translation keys used by Sonata itself can be edited into broken values, locking or confusing the UI. Scope access tightly, and keep a database backup or export before large edits.
Batch actions need review. Default Sonata batch delete on a TransUnit cascades its translations; on large tables this can be slow and destructive. Disable or constrain batch actions for non-super-admins.
Filter by domain before browsing. Translation tables grow quickly. Without domain filters and pagination tuning, the admin list becomes unusable. Add a default sort on domain, then key.
Extension points that work well: custom admin classes, custom datagrid filters, custom CRUD templates, extra routes for export/import, and a dedicated security role. Extension points that are fragile: patching vendor templates, overriding Doctrine mappings, and relying on undocumented service IDs. Verify service IDs against the installed version’s Resources/config, since documentation is sparse.
How can I help you explore Laravel packages today?