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

symfony/translation-contracts

Symfony Translation Contracts provides lightweight interfaces and abstractions for translation in PHP, extracted from Symfony components. Use it to build interoperable, battle‑tested translation integrations while staying framework-agnostic and compatible with Symfony implementations.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Installation: Add the package via Composer:

    composer require symfony/translation-contracts
    

    This provides only interfaces (TranslatorInterface, TranslatableInterface, MessageCatalogueInterface)—no runtime code.

  2. First Use Case: Leverage it to decouple Laravel’s native translation system from Symfony’s implementation. For example, replace Symfony\Component\Translation\Translator with a custom adapter implementing TranslatorInterface for third-party services (e.g., AWS Translate).

  3. Key Files:

    • src/Translation/TranslatorInterface.php: Core contract for translation logic.
    • src/Translation/TranslatableInterface.php: For deferred translation (e.g., in Livewire components).
    • src/Translation/MessageCatalogueInterface.php: For managing locale/message domains.
  4. Quick Integration: Bind your custom translator in Laravel’s container:

    $app->bind(
        TranslatorInterface::class,
        CustomAwsTranslator::class
    );
    

    Use it via dependency injection:

    public function __construct(private TranslatorInterface $translator) {}
    

Implementation Patterns

1. Custom Translator Adapter

  • Implement TranslatorInterface to wrap non-Symfony providers (e.g., Google Cloud Translation):
    class GoogleTranslateAdapter implements TranslatorInterface {
        public function trans(string $id, array $parameters = [], string $domain = 'messages', string $locale = null): string {
            // Call Google API, return translated string.
        }
    }
    
  • Laravel-Specific: Extend Illuminate\Translation\FileLoader to use your adapter via TranslatorInterface.

2. Deferred Translation with TranslatableInterface

  • Use Symfony\Contracts\Translation\TranslatableMessage in Livewire/Blade:
    $message = new TranslatableMessage('welcome', ['name' => 'John'], 'messages');
    return view('page', ['message' => $message]);
    
  • Translate lazily in the view:
    {{ $message->trans($this->translator) }}
    

3. Locale-Aware Services

  • Inject TranslatorInterface into services to handle dynamic locales:
    public function getPaginatedResults(TranslatorInterface $translator) {
        $translator->setLocale(request()->locale);
        return $this->model->paginate(10)->map(fn ($item) =>
            $translator->trans($item->title)
        );
    }
    

4. Testing

  • Mock TranslatorInterface in unit tests:
    $mockTranslator = Mockery::mock(TranslatorInterface::class);
    $mockTranslator->shouldReceive('trans')
        ->with('greeting', ['name' => 'John'])
        ->andReturn('Hola, John!');
    

5. Fallback Logic

  • Use TranslatorTrait for built-in fallback behavior:
    class FallbackTranslator implements TranslatorInterface {
        use TranslatorTrait;
    
        public function trans($id, array $parameters = [], $domain = 'messages', $locale = null) {
            return $this->doTrans($id, $parameters, $domain, $locale);
        }
    }
    

Gotchas and Tips

Critical Pitfalls

  1. No Implementation: This package only defines contracts. You must pair it with a concrete translator (e.g., symfony/translation or a custom adapter).
  2. Parameter Syntax Mismatch: Laravel’s trans() uses :placeholder, but Symfony’s TranslatorInterface expects ICU syntax ({var}). Validate your implementation’s format.
  3. Missing Pluralization: The contract lacks transChoice()—implementations (like Symfony’s) add it separately. Document your adapter’s pluralization support.
  4. Locale Context: Always set the locale before translating. Silent failures occur if setLocale() isn’t called in multi-tenant apps.

🔧 Debugging Tips

  • Strict Mocking: When testing, enforce locale/domain in mock expectations:
    $mock->shouldReceive('trans')
         ->withArgs(function ($id, $params, $domain, $locale) {
             return $locale === 'es' && $domain === 'validation';
         });
    
  • Log Fallbacks: Add debug logs in TranslatorTrait to trace fallback chains:
    protected function doTrans($id, array $parameters, $domain, $locale) {
        logger()->debug("Translating [$id] for locale [$locale], domain [$domain]");
        // ...
    }
    

🛠️ Extension Points

  1. Custom MessageCatalogue: Implement MessageCatalogueInterface to load translations from a database or API:
    class ApiMessageCatalogue implements MessageCatalogueInterface {
        public function get($id, $locale = null, $domain = 'messages') {
            return Http::get("https://api.example.com/translate/{$id}?locale={$locale}");
        }
    }
    
  2. Parameter Interpolation: Override TranslatorTrait::trans() to support custom interpolation (e.g., for HTML-safe escaping):
    protected function trans($id, array $parameters = [], $domain = 'messages', $locale = null) {
        $message = $this->getCatalogue()->get($id, $locale, $domain);
        return strtr($message, $parameters); // Custom logic here
    }
    
  3. Locale Resolution: Bind a custom locale resolver to TranslatorInterface:
    $app->bind(TranslatorInterface::class, function ($app) {
        $translator = new CustomTranslator();
        $translator->setLocaleResolver(function () {
            return session()->get('locale', config('app.locale'));
        });
        return $translator;
    });
    

🌟 Pro Tips

  • Laravel Integration: Use Illuminate\Support\Facades\Trans with a wrapper:
    Trans::setTranslator($app->make(TranslatorInterface::class));
    
  • Performance: Cache MessageCatalogue responses if using remote APIs.
  • Validation: Combine with symfony/translation for validation messages:
    use Symfony\Contracts\Translation\TranslatorInterface;
    $validator->setTranslator($translator);
    
  • Livewire: Defer translation in components:
    public function render() {
        $message = new TranslatableMessage('livewire.welcome');
        return view('livewire.component', ['message' => $message]);
    }
    

```markdown
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