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 Bundle Laravel Package

lexik/translation-bundle

Symfony bundle to manage translations in a database: import from xliff/yml/php, edit via a web GUI, track missing domain translations, add new keys, and export back to files. Database loader overrides file-based translations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle:

    composer require lexik/translation-bundle
    

    Ensure doctrine/doctrine-bundle and symfony/security-csrf, symfony/form, symfony/twig-bundle, and symfony/asset are installed (required for the UI).

  2. Configure the Bundle: Add to config/packages/lexik_translation.yaml:

    lexik_translation:
        locales: ['en', 'fr', 'de']
        fallback_locales: ['en']
        loaded_locales: ['en', 'fr']
        sources:
            - 'translations'
        default_locale: 'en'
    
  3. Create a Migration: Run the bundle’s migration command to set up the database tables:

    php bin/console lexik:translation:import --source=translations --locale=en
    
  4. First Use Case: Import existing translation files (e.g., translations/messages.en.yml) into the database:

    php bin/console lexik:translation:import --source=translations --locale=en
    

    Access the GUI at /translation to edit translations dynamically.


Where to Look First

  • Documentation: Start with index.md for installation and configuration.
  • GUI Interface: /translation route provides a grid-based editor for translations.
  • Commands:
    • lexik:translation:import: Load translations from files into the database.
    • lexik:translation:export: Export database translations back to files.
    • lexik:translation:purge: Clear translations for a locale/domain.

Implementation Patterns

Workflows

1. Initial Setup

  • Import Translations: Use the import command to migrate existing .yml, .xliff, or .php files into the database. Example:

    php bin/console lexik:translation:import --source=translations --locale=en --domain=messages
    
    • Tip: Run this in a CI pipeline during deployment to keep translations in sync with code.
  • Configure Fallback Locales: Set fallback_locales in lexik_translation.yaml to ensure untranslated strings fall back to a default (e.g., English).

2. Daily Development

  • Edit Translations via GUI: Non-technical team members (e.g., translators, content editors) use the /translation interface to update strings. The GUI supports:

    • Bulk edits.
    • Search/filter by domain, locale, or translation key.
    • Column toggling (e.g., hide "Original" or "Context" columns).
  • Override File-Based Translations: Database translations take precedence over file-based ones. Use this to:

    • A/B test translations by toggling entries in the database.
    • Patch translations without redeploying files (e.g., fix typos in production).
  • Export for Version Control: Periodically export translations back to files for backup or collaboration:

    php bin/console lexik:translation:export --source=translations --locale=fr --domain=validation
    

3. Integration with Symfony

  • Customize the Translator: Extend the DatabaseLoader to add logic (e.g., logging translation access or caching strategies). Example:

    // config/services.yaml
    services:
        App\Translation\CustomDatabaseLoader:
            decorates: 'lexik_translation.database_loader'
            arguments: ['@lexik_translation.database_loader.inner']
    
  • Add Translation Domains Dynamically: Use Doctrine events to auto-create domains for new bundles. Example listener:

    use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
    
    public function loadClassMetadata(LoadClassMetadataEventArgs $event): void
    {
        $classMetadata = $event->getClassMetadata();
        if ($classMetadata->getReflectionClass()->getNamespace() === 'App\Translation') {
            $this->translationManager->addDomain('app');
        }
    }
    
  • Localize Routes/Entities: Use Symfony’s translator service with the bundle’s loader:

    {{ 'app.welcome'|trans({ '%name%': user.name }) }}
    

    The bundle ensures database translations override file-based ones.

4. Advanced Patterns

  • Translation Workflows: Use Doctrine lifecycle events to trigger actions (e.g., notify Slack when a translation is updated):

    use Doctrine\ORM\Event\OnFlushEventArgs;
    
    public function onFlush(OnFlushEventArgs $event): void
    {
        $entityManager = $event->getEntityManager();
        $changes = $entityManager->getUnitOfWork()->getScheduledEntityUpdates();
    
        foreach ($changes as $entity) {
            if ($entity instanceof Translation) {
                $this->slackClient->sendMessage("Translation updated: {$entity->getId()}");
            }
        }
    }
    
  • Multi-Tenant Translations: Extend the Translation entity to include a tenant_id field and filter queries accordingly:

    // src/Entity/Translation.php
    /**
     * @ORM\Column(type="integer")
     */
    private ?int $tenantId = null;
    
  • Translation Validation: Add constraints to the Translation entity to enforce rules (e.g., max length):

    use Symfony\Component\Validator\Constraints as Assert;
    
    /**
     * @Assert\Length(max=255)
     */
    private ?string $content = null;
    

Integration Tips

  1. Symfony Flex Recipes: Use the bundle’s Symfony Flex recipe to auto-configure routes and services.

  2. Translation Domains:

    • Default Domains: The bundle auto-detects domains from file paths (e.g., translations/messages.en.ymlmessages domain).
    • Custom Domains: Add domains programmatically:
      # config/packages/lexik_translation.yaml
      lexik_translation:
          domains:
              - 'app'
              - 'validation'
      
  3. Caching:

    • Enable Symfony’s translator cache to improve performance:
      # config/packages/framework.yaml
      framework:
          translator:
              paths: ['%kernel.project_dir%/translations']
              caching: true
      
  4. Testing:

    • Mock the DatabaseLoader in tests to avoid hitting the database:
      $this->container->set('lexik_translation.database_loader', $this->createMock(DatabaseLoader::class));
      
  5. Deployment:

    • Blue-Green Deployments: Use the export command to sync translations between environments:
      # Export from production
      php bin/console lexik:translation:export --source=translations --locale=fr --domain=messages --output-dir=backups/prod
      
      # Import into staging
      php bin/console lexik:translation:import --source=backups/prod/messages.fr.yml --locale=fr --domain=messages
      

Gotchas and Tips

Pitfalls

  1. Database vs. File Precedence:

    • Issue: Database translations override file-based ones, which can cause unexpected behavior if not managed.
    • Fix: Use the export command to sync files with the database periodically, or document the precedence rules for your team.
  2. Locale Loading:

    • Issue: The loaded_locales setting must include all locales you want to edit via the GUI. Missing locales won’t appear in the UI.
    • Fix: Ensure loaded_locales matches your locales setting:
      lexik_translation:
          locales: ['en', 'fr', 'de']
          loaded_locales: ['en', 'fr', 'de']  # Must match
      
  3. Doctrine Events:

    • Issue: Custom Doctrine events (e.g., preUpdate) on the Translation entity may conflict with the bundle’s internal logic.
    • Fix: Use postUpdate or postPersist instead to avoid race conditions.
  4. GUI Performance:

    • Issue: The /translation route can be slow for large translation sets (>10,000 entries).
    • Fix:
      • Paginate results using Doctrine’s setMaxResults().
      • Add an indexBy hint to queries to avoid N+1 issues:
        $query->setHint('indexBy', ['locale', 'domain', 'id']);
        
  5. Symfony 6+ Deprecations:

    • Issue: Some older versions of the bundle may not support Symfony 6’s new configuration system.
    • Fix: Use v8.0+ for Symfony 6/7/8 compatibility. Check the changelog for breaking changes.
  6. **Translation Keys

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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky