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

Translation Form Bundle Laravel Package

a2lix/translation-form-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require a2lix/translation-form-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        A2lix\TranslationFormBundle\A2lixTranslationFormBundle::class => ['all' => true],
    ];
    
  2. Enable Translations: Configure your Doctrine entities with translation behavior (e.g., Gedmo\Translation or Knp\DoctrineBehaviors\Translatable). Example:

    use Gedmo\Mapping\Annotation as Gedmo;
    
    /**
     * @Gedmo\TranslationEntity(class="App\Entity\ProductTranslation")
     */
    class Product {}
    
  3. First Form Integration: Use TranslationsFormsType in your form builder:

    use A2lix\TranslationFormBundle\Form\Type\TranslationsFormsType;
    
    $builder->add('translations', TranslationsFormsType::class, [
        'entity' => $product,
        'fields' => ['name', 'description'], // Fields to translate
    ]);
    
  4. Twig Integration: Add to your Twig templates:

    {% form_theme form _self %}
    {% block a2lix_translation_form_widget %}
        {{ form_widget(form) }}
    {% endblock %}
    

First Use Case: Basic Translation Form

Create a form for a translatable entity (e.g., Product) with fields name and description:

use Symfony\Component\Form\FormBuilderInterface;

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('name')
        ->add('translations', TranslationsFormsType::class, [
            'entity' => $product,
            'fields' => ['name', 'description'],
            'locales' => ['en', 'fr'], // Optional: restrict locales
        ]);
}

Implementation Patterns

Workflow: Managing Translations

  1. Form Submission: Handle submission with validation:

    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $product = $form->getData();
        $em->persist($product);
        $em->flush();
    }
    
  2. Dynamic Locale Handling: Use TranslatedEntityType for choice fields with translated labels:

    $builder->add('category', TranslatedEntityType::class, [
        'class' => Category::class,
        'choice_label' => 'name', // Field to translate for labels
    ]);
    
  3. Partial Updates: Update only specific translations:

    $builder->add('translations', TranslationsFormsType::class, [
        'entity' => $product,
        'fields' => ['description'], // Only update 'description'
        'locales' => ['fr'], // Only French translations
    ]);
    

Integration Tips

  1. Symfony UX: Combine with Symfony UX for reactive forms:

    use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
    
    #[AsLiveComponent('translation_form')]
    class TranslationForm extends AbstractType {}
    
  2. API Platform: Use with API Platform for RESTful translation endpoints:

    # config/packages/api_platform.yaml
    api_platform:
        formats:
            jsonld:
                mime_types: ['application/ld+json']
                translation_form: true
    
  3. Custom Validation: Add constraints to translation fields:

    use Symfony\Component\Validator\Constraints as Assert;
    
    $builder->add('translations.name', null, [
        'constraints' => [
            new Assert\Length(['min' => 3]),
        ],
    ]);
    

Gotchas and Tips

Pitfalls

  1. Locale Mismatch: Ensure locales in TranslationsFormsType match your app’s supported locales (from framework.default_locale or A2lixTranslationFormBundle config). Fix: Validate locales in config/packages/a2lix_translation_form.yaml:

    a2lix_translation_form:
        locales: ['en', 'fr', 'de']
    
  2. Circular References: Avoid circular references in translatable entities (e.g., Product translating Category which translates Product). Use @ORM\Transient or lazy loading. Fix: Add @ORM\Transient to the inverse side:

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
     * @ORM\Transient
     */
    private $category;
    
  3. Form Theme Conflicts: Override Twig blocks carefully. If a2lix_translation_form_widget breaks, check for conflicting form themes. Fix: Extend the base theme:

    {% extends 'A2lixTranslationFormBundle:Form:fields.html.twig' %}
    {% block a2lix_translation_form_widget %}
        {{ form_widget(form) }}
        {# Custom additions #}
    {% endblock %}
    

Debugging

  1. Missing Translations: If translations aren’t saved, verify:

    • Doctrine event listeners (prePersist, preUpdate) are registered.
    • Gedmo\Handler\TranslatableListener or Knp\DoctrineBehaviors\ORM\EventListener\TranslatableListener is enabled. Debug: Check Symfony profiler’s "Doctrine" tab for translation events.
  2. Form Field Not Rendering: Ensure the field exists in the entity’s translation mapping (e.g., @Gedmo\Translatable(fields={"name", "description"})). Debug: Dump the form’s children:

    dump($form->all());
    

Extension Points

  1. Custom Field Types: Extend TranslationsFormsType for custom logic:

    use A2lix\TranslationFormBundle\Form\Type\TranslationsFormsType;
    
    class CustomTranslationsType extends TranslationsFormsType {
        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults([
                'custom_option' => true,
            ]);
        }
    }
    
  2. Twig Extensions: Add custom Twig filters for translations:

    // src/Twig/AppExtension.php
    class AppExtension extends \Twig\Extension\AbstractExtension {
        public function getFilters() {
            return [
                new \Twig\TwigFilter('translate_field', [$this, 'translateField']),
            ];
        }
    
        public function translateField($entity, $field, $locale) {
            return $entity->getTranslation($field, $locale);
        }
    }
    
  3. Event Listeners: Hook into translation events for custom logic:

    // src/EventListener/TranslationListener.php
    class TranslationListener implements EventSubscriber {
        public static function getSubscribedEvents() {
            return [
                TranslatableListener::PRE_TRANSLATE => 'onPreTranslate',
            ];
        }
    
        public function onPreTranslate(TranslatableEvent $event) {
            // Modify translations before save
        }
    }
    

Configuration Quirks

  1. Default Locale Fallback: Configure fallback locales in config/packages/a2lix_translation_form.yaml:

    a2lix_translation_form:
        fallback_locale: 'en'
        locales: ['en', 'fr']
    
  2. Dynamic Locale Selection: Use locale_chooser to let users select locales dynamically:

    $builder->add('translations', TranslationsFormsType::class, [
        'locale_chooser' => true,
    ]);
    
  3. Excluded Fields: Exclude fields from translation forms:

    $builder->add('translations', TranslationsFormsType::class, [
        'exclude_fields' => ['createdAt', 'updatedAt'],
    ]);
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui