Skip to content

[Feature suggestion/example] Nested translatable objects #41882

@leflings

Description

@leflings

Description
As a mostly inexperience Symfony developer, I was happy to find the addition of translatable objects in Symfony 5.2.

I was eager to see if this construction allowed nesting such objects within one another, something like this:

$msg = new TranslatableMessage('order.delivery.between', [
    '%begin%' => self::getTranslatableMessage($dateTime1), // returns a TranslatableMessage/Interface
    '%end%' => self::getTranslatableMessage($dateTime2),
]);

Sadly this is not the case.

Enabling such a construct would greatly increase the flexibility of translatable objects and allow for composing these things into bigger parts. The great about thing about translatable objects, from my perspective, is that it liberates you from being context aware when providing some mapping from object/structure -> string. But that liberation is shallow if it's not turtles all the way down :)

Example
For my own use case, I solved this problem by creating a NestedTranslatableMessage as follows

<?php

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

class NestedTranslatableMessage extends TranslatableMessage
{
    public function trans(TranslatorInterface $translator, string $locale = null): string
    {
        $params = $this->translateParams($translator, $this->getParameters(), $locale);

        return $translator->trans($this->getMessage(), $params, $this->getDomain(), $locale);
    }

    private function translateParams(TranslatorInterface $translator, array $params, ?string $locale): array
    {
        $transformed = [];

        /** @var string|TranslatableInterface $value */
        foreach ($params as $key => $value) {
            if ($value instanceof TranslatableInterface) {
                $transformed[$key] = $value->trans($translator, $locale);
            } else {
                $transformed[$key] = $value;
            }
        }

        return $transformed;
    }
}

It works like a charm for my use case. Aside from the (very slight?) performance impact of recreating a, potentially deeply nested, parameter array, I don't see any drawbacks from this solution.

So my suggestion is for either:

  1. Including this "mapping/translating" functionality to the existing TranslatableMessage
  2. Adding a NestedTranslatableMessage class like the one above to the framework

However - I'm quite inexperienced with the Symfony framework, and allowing this construct might have implications/complications that I'm not aware of, hence why I'm adding this as a feature suggestion.

If the suggestion garners support, I would be happy to provide a PR, given that somebody could point me in the direction of other areas of the framework that this feature might influence and that would require consideration.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions