Home > Back-end >  Symfony Translatable Enum
Symfony Translatable Enum

Time:12-02

My supplier entity has enum property notifyType. Any idea how translate the enum this way?

{{ supplier.notifyType|trans }}

Unfortunately, use __toString method in Enum is not possible.

// error - Enum may not include __toString
public function __toString(): string
{
    return 'supplier.notify.'.$this->name;
}

Then I just tried this:

use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

enum NotifyType: int implements TranslatableInterface
{
    case EMAIL = 1;
    case WEBHOOK = 2;
    case PUNCH_OUT = 4;

    public function trans(TranslatorInterface $translator, string $locale = null): string
    {
        return $translator->trans('supplier.notify.'.$this->name, locale: $locale);
    }
}

But it's not possible pass translatable object to trans method. String only accepted.

$this->translator->trans(NotifyType::EMAIL); // error: must be of type string

CodePudding user response:

TL;DR : NotifyType::EMAIL->trans($this->translator)


Your Enum is correct and should works like that thanks to TranslatableInterface implementation.

The only problem that I can find with that is the "auto discover" by translation:extract symfony's command will not correctly works, since your translations are dynamics.

You should avoid using concatenated trans id and use match expression instead
(assuming you are in PHP >= 8.1 because of the enum problem) :

enum NotifyType: int implements TranslatableInterface
{
    case EMAIL = 1;
    case WEBHOOK = 2;
    case PUNCH_OUT = 4;

    public function trans(TranslatorInterface $translator, string $locale = null): string
    {
        return match ($this) {
            self::EMAIL     => $translator->trans('supplier.notify.email'),
            self::WEBHOOK   => $translator->trans('supplier.notify.webhook'),
            self::PUNCH_OUT => $translator->trans('supplier.notify.punch_out'),
        };
    }
}

PHP usage

NotifyType::EMAIL->trans($this->translator)

Twig usage

{{ supplier.notifyType | trans }}

But definitely not like that :

  • {{ supplier.notifyType.value | trans }} => wrong
  • {{ supplier.notifyType.name | trans }} => wrong

CodePudding user response:

The |trans simply calls TranslatorExtension's trans function with the value it filters as a parameter. It only accepts the following types: string|\Stringable|TranslatableInterface|null

So then you have 2 (Edit: 3) solutions:

  1. Make your own |trans filter that overrides the one from TranslatorExtension (not ideal IMO)
  2. Create your own filters specifically for Enums.

EDIT There is a third and simpler solution: add a public function (for example getTransString) in your Enum that returns 'supplier.notify.'. $this->name and do this in twig: {{ supplier.notifyType.getTransString|trans }}

Here's a very simple example of the second solution that I tried and worked as expected:

class EnumTranslationService
{
    public function __construct(private readonly TranslatorInterface $translator)
    {
    }

    public function translateNotifyType(NotifyType $notifyType): string
    {
        return $this->translator->trans('supplier.notify.' . $notifyType->name);
    }
}

AppExtension:

class AppExtension extends AbstractExtension
{
    public function getFilters(): array
    {
        return [
            new TwigFilter('transNotifyType', [EnumTranslationService::class, 'translateNotifyType'])
        ];
    }
}

Twig:

{{ supplier.notifyType|transNotifyType }}
  • Related