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

Sulu Translated Media Bundle Laravel Package

alengo/sulu-translated-media-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation:

    composer require alengo/sulu-translated-media-bundle
    

    Add to config/bundles.php:

    Alengo\SuluTranslatedMediaBundle\TranslatedMediaBundle::class => ['all' => true],
    
  2. Route Configuration: Add to config/routes/sulu_admin.yaml:

    TranslatedMediaBundle:
        resource: "@TranslatedMediaBundle/Resources/config/routing_admin_api.yaml"
        prefix: /admin/api
    
  3. Database Migration:

    bin/adminconsole doctrine:schema:update --force
    
  4. First Media Translation:

    • Upload a media file in Sulu admin.
    • Navigate to the "Additional Data" tab (auto-registered).
    • Set seoFilename (e.g., red-shoes-de), title, and description for a locale (e.g., de).
    • Save.
  5. First Twig Usage:

    {{ sulu_translated_media_url(media, '800x', app.request.locale) }}
    

    Verify the URL reflects the translated filename (e.g., /uploads/red-shoes-de.jpg).


Where to Look First

  • Admin UI: The "Additional Data" tab under any media in Sulu’s admin is the primary interface for managing translations.
  • Twig Functions: sulu_translated_media_url() and sulu_translated_media_urls() are the core tools for frontend integration.
  • Entity Structure: Entity\Media and Entity\MediaTranslations define the data model. Extend these if custom logic is needed.
  • Compiler Pass: The TranslatedFormatManager replaces Sulu’s default FormatManager. Override this if you need custom format handling.

First Use Case: Localized Product Images

  1. Upload a product image (e.g., red-shoes.jpg) to Sulu.
  2. In the "Additional Data" tab:
    • Set seoFilename to red-shoes-de for German (de).
    • Set title to Rote Schuhe and description to Bequeme Herbstschuhe.
  3. In your product template:
    <img src="{{ sulu_translated_media_url(productImage, '600x', app.request.locale) }}"
         alt="{{ productImage.title[app.request.locale] }}">
    
    Result: /uploads/red-shoes-de.jpg is served for German users, with localized alt text.

Implementation Patterns

Core Workflow: Managing Translated Media

  1. Upload Media:

    • Use Sulu’s standard media upload workflow. The bundle adds no steps here.
  2. Translate Metadata:

    • Open the "Additional Data" tab for the media.
    • Add translations for each locale:
      • seoFilename: URL-safe filename (e.g., product-guide-fr).
      • title: Human-readable name (e.g., Guide du Produit).
      • description: SEO description (e.g., Découvrez les fonctionnalités de notre produit).
      • Flags: verifyDownload (for gated content), aiGenerated (for metadata).
  3. Generate URLs in Twig:

    • Single URL:
      {{ sulu_translated_media_url(media, '400x', 'de') }}
      
      Output: /uploads/guide-du-produit-de.jpg (if seoFilename is guide-du-produit for de).
    • Responsive Images:
      {% set urls = sulu_translated_media_urls(media, '800x', app.request.locale) %}
      <picture>
          <source srcset="{{ urls.webp }}" type="image/webp">
          <img src="{{ urls.default }}" alt="{{ media.title[app.request.locale] }}">
      </picture>
      
  4. Fallback Handling:

    • If a translation is missing, the bundle falls back to the original filename (e.g., product-guide.jpg).
    • Override fallback behavior by extending TranslatedFormatManager.

Integration Tips

1. Extending the Media Entity

If you need custom fields beyond the bundle’s seoFilename, title, description, verifyDownload, or aiGenerated:

// src/Entity/CustomMedia.php
use Alengo\SuluTranslatedMediaBundle\Model\MediaAdditionalDataTrait;
use Alengo\SuluTranslatedMediaBundle\Model\MediaTranslationsTrait;

class CustomMedia extends \Alengo\SuluTranslatedMediaBundle\Entity\Media
{
    use MediaTranslationsTrait;
    use MediaAdditionalDataTrait;

    // Add custom fields
    private ?string $customField = null;

    // Getters/setters for customField...
}

Update config/packages/sulu_media.yaml to point to your custom entity:

sulu_media:
    objects:
        media:
            model: App\Entity\CustomMedia

2. Customizing the Admin Tab

The "Additional Data" tab is auto-registered but can be customized:

# config/packages/sulu_admin.yaml
sulu_admin:
    navigation:
        main:
            media:
                children:
                    additional_data:
                        label: "Custom Tab Name"
                        route: "sulu_media.media.additional_data"
                        icon: "cog"

3. Overriding FormatManager

To customize how translated URLs are generated (e.g., add a hash for cache busting):

// src/DependencyInjection/Compiler/OverrideTranslatedFormatManagerPass.php
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Alengo\SuluTranslatedMediaBundle\Format\TranslatedFormatManager;

class OverrideTranslatedFormatManagerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $definition = $container->findDefinition(TranslatedFormatManager::class);
        $definition->setClass(CustomTranslatedFormatManager::class);
        $definition->setArguments([...]);
    }
}

Register the pass in src/Kernel.php:

protected function build(ContainerBuilder $container): void
{
    $container->addCompilerPass(new OverrideTranslatedFormatManagerPass());
}

4. Bulk Updating Translations

Use Sulu’s Data Importer to bulk-add translations:

# config/packages/sulu_data_importer.yaml
sulu_data_importer:
    importers:
        media_translations:
            class: App\Importer\MediaTranslationImporter
            label: "Media Translations"

Implement the importer to update me_media_translations in bulk.

5. Caching Translated URLs

Cache translated URLs to reduce database lookups:

// src/Service/CachedTranslatedMediaUrlGenerator.php
use Symfony\Contracts\Cache\CacheInterface;

class CachedTranslatedMediaUrlGenerator
{
    public function __construct(
        private TranslatedFormatManager $manager,
        private CacheInterface $cache
    ) {}

    public function generate(string $mediaId, string $format, string $locale): string
    {
        $key = "media_url_{$mediaId}_{$format}_{$locale}";
        return $this->cache->get($key, fn() => $this->manager->generate($mediaId, $format, $locale));
    }
}

Register as a Twig extension:

// src/Twig/CachedTranslatedMediaExtension.php
class CachedTranslatedMediaExtension extends \Twig\Extension\AbstractExtension
{
    public function getFunctions(): array
    {
        return [
            new \Twig\TwigFunction('sulu_cached_translated_media_url', [$this->generator, 'generate']),
        ];
    }
}

Common Patterns

Pattern Example
Locale-Aware URLs {{ sulu_translated_media_url(media, '400x', app.request.locale) }}
Responsive Images Use sulu_translated_media_urls() with <picture> tags.
Fallback Handling Missing translations fall back to original filenames.
Admin Metadata Edit seoFilename, title, description per locale in the UI.
Custom Entities Extend Entity\Media for project-specific fields.
Cache Optimization Cache translated URLs to reduce DB queries.

Gotchas and Tips

Pitfalls

  1. Missing Locale Translations:
    • If a locale’s seoFilename is empty, the bundle falls back to the original filename.
    • Fix: Always set seoFilename for all target locales in the admin UI.
    • Debug: Check `me_media_trans
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata