Mime Translatable
softspring/mime-translatable is a small component that helps you build translated emails on top of Symfony Mime and TemplatedEmail.
It is useful when your application mail classes need:
- translated subjects
- one locale per message
- Twig templates that receive translation params
- previewable example emails for admin tooling
This component is intentionally small. It does not create a mailer system by itself. It gives you the email object and renderer behavior that higher-level bundles can reuse.
Installation
composer require softspring/mime-translatable:^6.0
What The Component Adds
The package provides four pieces:
TranslatableEmailTranslatableBodyRendererExtendedContextEmailExampleEmailInterface
Together they cover the most common translation needs for application emails.
Use TranslatableEmail
TranslatableEmail extends Symfony's TemplatedEmail.
It adds two practical features:
- a locale attached to the message
- translation params stored in the email context
That makes it easy to build one email class that knows:
- which locale it should render in
- which placeholders should be used in the translated subject
- which values should be available to Twig templates
Build A Mail Class
The normal pattern is to extend TranslatableEmail in each concrete mail class:
use Softspring\Component\MimeTranslatable\TranslatableEmail;
use Symfony\Contracts\Translation\TranslatorInterface;
class WelcomeEmail extends TranslatableEmail
{
public function __construct(TranslatorInterface $translator, ?string $locale = null)
{
parent::__construct($translator, $locale);
$this->setTranslationParams([
'%name%' => 'Mery',
]);
$this->htmlTemplate('emails/welcome.html.twig');
$this->subject('welcome.email.subject', 'messages');
}
}
Translate The Subject
TranslatableEmail::subject() translates the subject key immediately through Symfony Translation.
It uses:
- the subject key you pass
- the translation params stored with
setTranslationParams() - the translation domain you pass
- the message locale, if one exists
That is enough for most real application emails:
$this->setTranslationParams([
'%name%' => $user->getName(),
]);
$this->subject('register.confirm.email.subject', 'sfs_user');
Important Note About Timing
Subject translation happens when you call subject(), not later during final body rendering.
So the practical rule is:
- set translation params first
- call
subject()after that
Pass Translation Params To Twig
setTranslationParams() stores the params in a dedicated context block.
That gives you one place to keep the placeholders used by the mail class.
The component stores them under:
__translation_params
This is useful when:
- the subject uses placeholders
- the Twig template also needs the same values
- you want the mail class to own the full translated message contract
Use The Message Locale During Body Rendering
TranslatableBodyRenderer decorates a normal Symfony body renderer and temporarily switches the translator locale while rendering one TranslatableEmail.
That means the subject and the Twig rendering can follow the same message locale.
Without this, the email body would depend only on the global translator locale at render time.
How To Wire The Renderer
This component is a library, so the application or bundle must wire the service.
The common pattern is to decorate Symfony's twig.mime_body_renderer:
Softspring\Component\MimeTranslatable\TranslatableBodyRenderer:
decorates: twig.mime_body_renderer
arguments:
- '@Softspring\Component\MimeTranslatable\TranslatableBodyRenderer.inner'
- '@translator.default'
This is the same idea used later by mailer-bundle.
Use ExampleEmailInterface
ExampleEmailInterface is a contract for email classes that can build a standalone example message.
It is especially useful for:
- previews in admin tools
- sending test emails from a back office
- documenting a mail class with a renderable sample
The contract is simple:
public static function generateExample(TranslatorInterface $translator, ?string $locale = null): TranslatableEmail;
Real Usage In Other Bundles
The best examples in this repository are in user-bundle.
There, mail classes such as:
ConfirmationEmailInvitationEmailResetPasswordEmail
extend TranslatableEmail and implement ExampleEmailInterface.
They all follow the same pattern:
- receive the translator and optional locale
- put domain data into the email context
- set translation params
- choose the Twig template
- translate the subject key
This is the recommended usage model for your own application emails.
Extend The Component
The component is meant to be extended through your own mail classes, not through a large inheritance tree inside the library.
The main extension points are:
- extend
TranslatableEmailfor your concrete email classes - implement
ExampleEmailInterfacewhen previews matter - decorate the renderer in your application or bundle
That keeps the component small while still making it easy to integrate in real projects.
Recommended Usage Pattern
For most projects, the clean pattern is:
- create one mail class per email type
- extend
TranslatableEmail - set all context values in the constructor
- set translation params there too
- call
subject()after the params are ready - implement
ExampleEmailInterfacewhen the mail should be previewable
Limits And Current Notes
There are a few practical limits to know:
- the component does not auto-register services
- the renderer logic must be wired by the application or a higher-level bundle
- subject translation is eager, not lazy
ExampleEmailInterfaceis only a contract; preview UIs belong to higher-level bundles such asmailer-bundle