benedicthelfer/translatable-form-field
Installation
composer require benedicthelfer/translatable-form-field
Register the bundle in AppKernel.php:
new Bnh\TranslatableFieldBundle\BnhTranslatableFieldBundle(),
Configuration
Add to config/packages/bnh_translatable_field.yaml:
bnh_translatable_field:
default_locale: en_GB
locales: ['en_GB', 'de_DE']
templating: 'BnhTranslatableFieldBundle:FormType:bnhtranslations.html.twig'
First Use Case Create a translatable entity with Gedmo/Translatable:
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Translatable\Translatable;
class Product implements Translatable
{
/** @Gedmo\Translatable */
private $name;
/** @Gedmo\Locale */
private $locale;
}
Then, in Sonata Admin, override the form type to use the translatable field:
$formMapper
->add('name', 'bnh_translatable_field', [
'locales' => ['en_GB', 'de_DE'],
]);
Entity Setup
@Gedmo\Translatable on fields requiring translations.Gedmo\Translatable\Translatable.Translation entity (e.g., ProductTranslation) with @Gedmo\TranslationEntity.Sonata Admin Integration
Replace standard form fields with bnh_translatable_field:
$formMapper
->add('description', 'bnh_translatable_field', [
'locales' => $this->getConfigurationPool()->getContainer()->getParameter('bnh_translatable_field.locales'),
'default_locale' => $this->getConfigurationPool()->getContainer()->getParameter('bnh_translatable_field.default_locale'),
]);
Dynamic Locale Handling Fetch locales dynamically from config:
$locales = $this->getConfigurationPool()->getContainer()->getParameter('bnh_translatable_field.locales');
Twig Template Overrides
Customize the translatable field template by overriding:
templates/bnh_translatable_field/bnhtranslations.html.twig
Extend the base template (BnhTranslatableFieldBundle:FormType:bnhtranslations.html.twig).
Validation & Localization Use Symfony’s validation constraints with locale-aware messages:
$builder->add('name', 'bnh_translatable_field')
->addConstraint(new NotBlank(), [
'message' => 'translatable_field.not_blank_{{ locale }}',
]);
Missing Gedmo Extensions
Ensure stof/doctrine-extensions-bundle is installed and configured for @Gedmo\Translatable to work:
# config/packages/doctrine.yaml
doctrine:
orm:
mappings:
gedmo_translatable:
type: attribute
prefix: Gedmo\Translatable\Entity\Mapping\Annotation\Legacy
dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Entity/Mapping/Annotation/Legacy"
alias: GedmoTranslatable
Locale Mismatch If translations aren’t saved, verify:
locale field is set in the entity (e.g., via setTranslatableLocale()).default_locale in config matches the entity’s default locale.Template Caching Clear Twig cache after overriding templates:
php bin/console cache:clear
Sonata Admin Field Conflicts If the field doesn’t render, ensure:
form_types config.translatable vs. bnh_translatable_field).Check Database
Verify translations are stored in the *_translation table (e.g., product_translation):
SELECT * FROM product_translation WHERE object_id = [ID];
Log Locale Switching
Add debug logs in the entity’s setTranslatableLocale() to confirm locale assignment:
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
error_log("Locale set to: {$locale}"); // Debug line
}
Form Data Inspection
Dump form data in Sonata’s prePersist() to verify translatable values:
public function prePersist($entity)
{
dump($entity->getName()); // Check if translations are attached
}
Custom Field Types Extend the base field type for specialized behavior:
class CustomTranslatableFieldType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'locales' => ['en_GB', 'de_DE'],
'custom_option' => false,
]);
}
}
Dynamic Locale Selection Fetch locales from a service or database:
# config/services.yaml
services:
App\Service\LocaleProvider:
arguments:
$locales: '%env(APP_TRANSLATABLE_LOCALES)%'
Then inject into the form type:
$formMapper->add('title', 'bnh_translatable_field', [
'locales' => $this->localeProvider->getLocales(),
]);
Translation Fallback
Implement fallback logic in the entity’s getTranslatedField():
public function getName()
{
if (null === $this->locale) {
$this->setTranslatableLocale($this->getDefaultLocale());
}
return $this->name;
}
How can I help you explore Laravel packages today?