austral/entity-translate-bundle
Installation Add the bundle via Composer:
composer require austral/entity-translate-bundle
Enable it in config/bundles.php:
Austral\EntityTranslateBundle\EntityTranslateBundle::class => ['all' => true],
Configure Translatable Entities
Extend Austral\EntityBundle\Entity\AbstractEntity and implement Austral\EntityBundle\Interfaces\EntityInterface:
use Austral\EntityBundle\Entity\AbstractEntity;
use Austral\EntityBundle\Interfaces\EntityInterface;
use Austral\EntityTranslateBundle\Interfaces\TranslatableInterface;
class Product extends AbstractEntity implements EntityInterface, TranslatableInterface
{
// Your fields
}
Define Translatable Fields
Use the Translate annotation or attribute (PHP 8+):
use Austral\EntityTranslateBundle\Annotation\Translate;
#[Translate]
private ?string $name = null;
First Use Case: Basic Translation Create a translated entity via the repository:
$product = $productRepository->createTranslatedEntity(Product::class, 'en');
$product->setName('Laptop');
$productRepository->save($product);
Create/Update Translations Use the repository methods to handle translations:
// Create a new translation for an existing entity
$translatedEntity = $repository->createTranslation($entity, 'fr');
$translatedEntity->setName('Ordinateur portable');
$repository->save($translatedEntity);
// Update an existing translation
$frTranslation = $repository->findTranslation($entity, 'fr');
$frTranslation->setDescription('Détails en français...');
$repository->save($frTranslation);
Fetching Translations Retrieve translations dynamically:
// Get all translations for an entity
$translations = $repository->getTranslations($entity);
// Get a specific translation (e.g., fallback to 'en' if 'fr' doesn't exist)
$translation = $repository->getTranslation($entity, 'fr', 'en');
Form Integration Use Symfony Forms with translation-aware fields:
$builder->add('name', TextType::class, [
'attr' => ['data-translatable' => true],
'translation_locale' => $request->getLocale(), // e.g., 'fr'
]);
Doctrine Events
Listen for translation-related events (e.g., prePersist, preUpdate):
$entityManager->getEventManager()->addEventListener(
TranslatableEvents::PRE_TRANSLATE,
[$this, 'onPreTranslate']
);
Symfony Translation System
Integrate with Symfony's Translator for dynamic locale switching:
$this->translator->trans($entity->getTranslatedField('name'), [], null, 'fr');
API Responses Serialize translations in APIs using serializers:
# config/serializer/Entity.Product.yaml
Austral\EntityTranslateBundle\Serializer\TranslatableNormalizer:
format: json
Validation Validate translations per locale:
$validator->validate($entity, null, ['locale' => 'fr']);
Locale Fallback Logic
framework.default_locale). Ensure your fallback logic aligns with business requirements.$translation = $repository->getTranslation($entity, 'es', null); // No fallback
Circular References in Serialization
attributes:
ignore:
- translations
Doctrine Listener Conflicts
HttpRequestService in DoctrineListener might interfere with existing listeners.# config/packages/austral_entity_translate.yaml
austral_entity_translate:
doctrine_listener:
http_request_service: false
Annotation vs. Attribute
@Translate), while PHP 8+ supports attributes (#[Translate]).Missing Translations
Check if the TranslatableInterface is implemented and fields are annotated/attributed correctly. Enable Doctrine debugging:
doctrine:schema:update --dump-sql
Performance Issues Avoid loading all translations at once. Use DQL or QueryBuilder to fetch only needed locales:
$qb->leftJoin('entity.translations', 't', 'WITH', 't.locale IN (:locales)')
->setParameter('locales', ['en', 'fr']);
Custom Translation Storage
Extend Austral\EntityTranslateBundle\Repository\TranslatableRepository to use a custom storage backend (e.g., Redis for caching).
Translation Events Dispatch custom events for translation lifecycle:
$dispatcher->dispatch(new TranslatableEvent($entity, 'fr', TranslatableEvents::POST_TRANSLATE));
Dynamic Locale Detection
Override locale detection in Austral\EntityTranslateBundle\Service\LocaleDetector:
public function detectLocale(): string
{
return $this->requestStack->getCurrentRequest()->getPreferredLanguage();
}
Bulk Translation Updates Use batch processing for large-scale translations:
$entityManager->getConnection()->beginTransaction();
try {
foreach ($entities as $entity) {
$translation = $repository->createTranslation($entity, 'de');
// Update fields...
$repository->save($translation);
}
$entityManager->getConnection()->commit();
} catch (\Exception $e) {
$entityManager->getConnection()->rollBack();
}
Default Locale
Ensure framework.default_locale in config/packages/framework.yaml matches your primary locale to avoid unexpected fallbacks.
Translation Field Naming
The bundle assumes translated fields follow the pattern {field}__{locale} (e.g., name__en). Customize this in your entity mapping if needed:
# config/doctrine/mapping/Product.yaml
Austral\EntityTranslateBundle\Mapping\TranslatableDriver:
translation_field_suffix: '_translated'
Symfony 6.4+ Compatibility The bundle requires Symfony 6.4 for full compatibility. Test thoroughly if using older versions.
How can I help you explore Laravel packages today?