Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

I18N Doctrine Bundle Laravel Package

a2lix/i18n-doctrine-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require a2lix/i18n-doctrine-bundle

Add to config/bundles.php:

A2lix\I18nDoctrineBundle\A2lixI18nDoctrineBundle::class => ['all' => true],
  1. Configure Locales: Update config/packages/a2lix_i18n_doctrine.yaml:

    a2lix_i18n_doctrine:
        default_locale: en
        supported_locales: en, fr, es
    
  2. Enable Translatable Entities: Annotate an entity (e.g., Product):

    use A2lix\I18nDoctrineBundle\Model\I18n;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="products")
     * @I18n
     */
    class Product
    {
        // ...
    }
    
  3. First Use Case: Translate a field (e.g., name):

    $product = new Product();
    $product->setName('en', 'Laptop'); // Set English translation
    $product->setName('fr', 'Ordinateur portable'); // Set French translation
    

Implementation Patterns

Workflows

  1. Entity Translation: Use setField($locale, $value) and getField($locale) for dynamic translations.

    $product->setDescription('es', 'Descripción detallada');
    $currentLocale = app()->getLocale(); // e.g., 'fr'
    $description = $product->getDescription($currentLocale);
    
  2. Form Integration: Extend Symfony forms with locale-aware fields:

    $builder->add('name', TextType::class, [
        'i18n' => true, // Enable translation
        'locales' => ['en', 'fr'], // Supported locales
    ]);
    
  3. Repository Queries: Filter by locale in DQL:

    $qb = $entityManager->createQueryBuilder();
    $qb->select('p')
       ->from(Product::class, 'p')
       ->where('p.name LIKE :name')
       ->andWhere('p.locale = :locale')
       ->setParameter('locale', 'en');
    
  4. Fallback Logic: Configure fallback locales in config:

    a2lix_i18n_doctrine:
        fallback_locales: [en, fr]
    

    Automatically fall back if a translation is missing:

    $product->getName(); // Falls back to 'en' if 'fr' is missing
    
  5. Event Listeners: Use prePersist/preUpdate to validate translations:

    $entityManager->getEventManager()->addEventListener(
        I18n::class,
        new I18nEventListener($supportedLocales)
    );
    

Integration Tips

  • Symfony Translator: Combine with symfony/translation for dynamic locale switching:
    $translator->trans($product->getName($locale));
    
  • API Responses: Serialize translations with JsonSerializable:
    public function jsonSerialize() {
        return [
            'name' => $this->getName(app()->getLocale()),
            'translations' => [
                'en' => $this->getName('en'),
                'fr' => $this->getName('fr'),
            ],
        ];
    }
    
  • Admin Panels: Integrate with SonataAdmin or EasyAdmin for locale-aware CRUD:
    # EasyAdmin config
    fields:
        - { property: 'name', type: 'i18n', locales: ['en', 'fr'] }
    

Gotchas and Tips

Pitfalls

  1. Performance:

    • Avoid loading all translations for large datasets. Use DISTINCT in queries:
      $qb->select('DISTINCT p')
         ->from(Product::class, 'p');
      
    • Cache translations aggressively if using fallback locales.
  2. Locale Mismatches:

    • Ensure app()->getLocale() matches the expected locale in queries/forms.
    • Debug missing translations with:
      $product->hasTranslation('name', 'fr'); // Returns bool
      
  3. Database Schema:

    • The bundle creates a locale column and translation tables (e.g., product_translations).
    • Migration Gotcha: Run php bin/console doctrine:schema:update --force after installation to avoid schema conflicts.
  4. Symfony 4+:

    • The bundle is designed for Symfony 3.x. Test thoroughly in Symfony 4/5 (e.g., autowiring may require adjustments).
  5. Circular References:

    • Translatable relationships (e.g., @I18n on ManyToOne) can cause infinite loops. Use @ORM\Transient or lazy loading:
      /**
       * @ORM\Transient
       */
      public function getTranslatedName($locale) { ... }
      

Debugging

  • Enable SQL Logging:
    # config/packages/dev/doctrine.yaml
    doctrine:
        dbal:
            logging: true
            profiling: true
    
  • Check Event Subscribers: Verify I18n events are triggered:
    php bin/console debug:event-dispatcher
    
  • Validate Entities: Use the A2lix\I18nDoctrineBundle\Validator\Constraints\Locale validator to ensure locales are supported.

Tips

  1. Custom Fields: Extend the bundle for custom field types (e.g., rich text):

    use A2lix\I18nDoctrineBundle\Mapping\Annotation as I18n;
    
    /**
     * @I18n\TranslatableField(fieldName="description", type="text")
     */
    
  2. Bulk Updates: Use Doctrine batch processing for locale updates:

    $em = $entityManager;
    $products = $em->getRepository(Product::class)->findAll();
    foreach ($products as $product) {
        $product->setName('es', 'Updated Name');
        $em->persist($product);
        if ($i % 20 === 0) {
            $em->flush();
            $em->clear();
        }
        $i++;
    }
    
  3. Testing: Mock the locale service in PHPUnit:

    $this->container->set('translator.default_locale', 'test');
    $this->container->set('a2lix_i18n_doctrine.locale_provider', new TestLocaleProvider('test'));
    
  4. Fallback Priorities: Override fallback logic in a custom listener:

    public function onPreFlush(I18nEvent $event) {
        $entity = $event->getEntity();
        if (!$entity->hasTranslation('title', 'fr')) {
            $entity->setTitle('fr', $entity->getTitle('en'));
        }
    }
    
  5. Legacy Data: Migrate existing data with a custom migration:

    public function up(SchemaManagerInterface $manager) {
        $connection = $manager->getConnection();
        $connection->executeStatement('
            INSERT INTO product_translations (id, field, locale, value)
            SELECT id, "name", "en", name FROM products
        ');
    }
    

```markdown
## Extension Points
1. **Custom Storage**:
   Override the default translation storage (e.g., JSON column) by implementing `A2lix\I18nDoctrineBundle\Storage\TranslationStorageInterface`.

2. **Locale Providers**:
   Extend locale resolution with a custom provider:
   ```php
   class RequestLocaleProvider implements LocaleProviderInterface {
       public function getLocale() {
           return request()->getLocale();
       }
   }

Register in services:

services:
    App\Service\RequestLocaleProvider:
        tags: ['a2lix_i18n_doctrine.locale_provider']
  1. Event Subscribers: Hook into lifecycle events (e.g., onFlush) to enforce business rules:

    $subscriber = new class implements EventSubscriberInterface {
        public function getSubscribedEvents() {
            return [I18n::PRE_PERSIST];
        }
        public function prePersist(I18nEvent $event) {
            // Validate translations here
        }
    };
    
  2. Doctrine Filters: Combine with Doctrine filters for locale-specific queries:

    $filter = $entityManager->getFilters()->enable('i18n');
    $filter->setParameter('locale', 'fr');
    
  3. API Platform: Integrate with API Platform for automatic serialization:

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope