andyhobbs/gedmo-translation-form-bundle
Install the Bundle
composer require andyhobbs/gedmo-translation-form-bundle
Ensure StofDoctrineExtensionsBundle is also installed (required for Gedmo Translatable).
Enable the Bundle
Add to config/bundles.php:
return [
// ...
AndyHobbs\GedmoTranslationFormBundle\AndyHobbsGedmoTranslationFormBundle::class => ['all' => true],
];
Configure Translatable Entities
Use the Gedmo\Mapping\Annotation\Translation annotation on your entity fields:
use Gedmo\Mapping\Annotation as Gedmo;
/**
* @Gedmo\TranslationEntity(class="App\Entity\Translation")
*/
class Product
{
/**
* @Gedmo\Translatable
*/
private $name;
}
First Use Case: Basic Form Integration
In your form type, replace standard fields with GedmoTranslationsType:
use AndyHobbs\GedmoTranslationFormBundle\Form\Type\GedmoTranslationsType;
$builder->add('name', GedmoTranslationsType::class, [
'fields' => ['name'], // Fields to translate
'locales' => ['en', 'fr'], // Supported locales
]);
Entity Setup
@Gedmo\Translatable.Translation entity (e.g., App\Entity\Translation) with @Gedmo\TranslationEntity.Form Type Integration
GedmoTranslationsType for translatable fields.$builder->add('translatableFields', GedmoTranslationsType::class, [
'fields' => ['title', 'description'],
'locales' => ['en', 'es', 'de'],
'options' => [
'title' => ['label' => 'Product Title'],
'description' => ['attr' => ['rows' => 5]],
],
]);
Dynamic Locale Handling
getUser()->getLocale() or a service to fetch supported locales dynamically:
$locales = $this->localeService->getSupportedLocales();
$builder->add('name', GedmoTranslationsType::class, ['locales' => $locales]);
Validation and Defaults
$builder->add('name', GedmoTranslationsType::class, [
'defaults' => [
'en' => 'Default English Name',
'fr' => 'Nom par défaut',
],
]);
Submitting and Persisting
Translation entity. No extra logic needed for save().Symfony UX Turbo/Stimulus Use with Turbo to update translations via AJAX:
// Stimulus controller to submit partial translations
connect() {
this.element.addEventListener('turbo:submit-end', (event) => {
if (event.detail.success) {
Turbo.visit(event.target.action);
}
});
}
API Platform
Extend GedmoTranslationsType to support API input:
use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('translations', CollectionType::class, [
'entry_type' => TranslationType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
]);
}
Doctrine Lifecycle Events
Hook into prePersist/preUpdate to validate translations:
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
if ($entity instanceof TranslatableEntity) {
$this->validateTranslations($entity);
}
}
Locale Mismatch
InvalidArgumentException.Gedmo\Translatable\TranslatableListener:
$supportedLocales = $this->container->getParameter('gedmo_translatable.locales');
if (!in_array($locale, $supportedLocales)) {
throw new \InvalidArgumentException("Locale '$locale' not supported.");
}
Missing Translation Entity
Translation entity causes ClassNotFoundException.@Gedmo\TranslationEntity.Form Data Binding
data_class to enforce proper hydration:
$builder->add('name', GedmoTranslationsType::class, [
'data_class' => Product::class,
]);
Cascading Deletes
orphanRemoval: true to the OneToMany mapping in your Translation entity.Check Form Data Dump submitted data to verify structure:
$data = $request->request->all();
dump($data['product']['translatableFields']);
Enable Gedmo Logging
Add to config/packages/doctrine.yaml:
gedmo_listener:
translatable: true
log_enabled: true
Query Logging Enable Doctrine debug mode to inspect generated queries:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
profiling: true
Custom Translation Types
Extend GedmoTranslationsType for domain-specific logic:
class CustomTranslationsType extends GedmoTranslationsType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'custom_option' => true,
]);
}
}
Override Default Templates
Copy templates/form/fields.html.twig to templates/AndyHobbsGedmoTranslationForm/ to customize rendering.
Add Validation Constraints Dynamically add constraints per locale:
$builder->add('name', GedmoTranslationsType::class, [
'validation' => [
'en' => [new Length(['max' => 50])],
'fr' => [new NotBlank()],
],
]);
Event Subscribers
Listen for form.pre_set_data to modify translations before binding:
public function onPreSetData(FormEvent $event)
{
$data = $event->getData();
if ($data instanceof Product) {
$event->setData($this->hydrateTranslations($data));
}
}
How can I help you explore Laravel packages today?