Skip to content

translation problem - cannot handle TranslatableInterface #43

@kor3k

Description

@kor3k

liform cannot handle instances of Symfony\Contracts\Translation\TranslatableInterface for label , help and choice_label.

Symfony\Component\Translation\DataCollectorTranslator::trans(): Argument #1 ($id) must be of type ?string, Symfony\Component\Translation\TranslatableMessage given, called in /app/vendor/survos/liform/src/Limenius/Liform/Transformer/ChoiceTransformer.php on line 39

also ignores form options like help_translation_parameters, label_translation_parameters, choice_translation_parameters, choice_translation_domain.


it calls $translator->trans() on few places in Limenius\Liform\Transformer\AbstractTransformer and \Limenius\Liform\Transformer\ChoiceTransformer.

imho it would be better to remove the translator & it's calls completely, and leave the translation to an extension. that way one does not have to override the transformers.


abstract class AbstractTransformer implements TransformerInterface
{
    public function __construct(protected ?FormTypeGuesserInterface $validatorGuesser = null)   // remove translator
    {
    }

    protected function addLabel(FormInterface $form, array $schema): array
    {
        if ($label = $form->getConfig()->getOption('label')) {
            $schema['title'] = $label; // remove $translator->trans()
        } else {
            $schema['title'] = $form->getName(); // remove $translator->trans()
        }

        return $schema;
    }

    protected function addDescription(FormInterface $form, array $schema): array
    {
        $formConfig = $form->getConfig();
        if ($help = $formConfig->getOption('help', '')) {
            $schema['description'] = $help; // remove $translator->trans()
        }

        if ($liform = $formConfig->getOption('liform')) {
            if (isset($liform['description']) && $description = $liform['description']) {
                $schema['description'] = $description; // remove $translator->trans()
            }
        }

        return $schema;
    }
}
class ChoiceTransformer extends AbstractTransformer
{
    public function transform(FormInterface $form, array $extensions = [], $widget = null): array
    {
        $formView = $form->createView();

        $choices = [];
        $titles = [];
        foreach ($formView->vars['choices'] as $choiceView) {
            if ($choiceView instanceof ChoiceGroupView) {
                foreach ($choiceView->choices as $choiceItem) {
                    $choices[] = $choiceItem->value;
                    $titles[] = $choiceItem->label; // remove $translator->trans()
                }
            } else {
                $choices[] = $choiceView->value;
                $titles[] = $choiceView->label; // remove $translator->trans()
            }
        }

        if ($formView->vars['multiple']) {
            $schema = $this->transformMultiple($form, $choices, $titles);
        } else {
            $schema = $this->transformSingle($form, $choices, $titles);
        }

        $schema = $this->addCommonSpecs($form, $schema, $extensions, $widget);

        return $schema;
    }
}
// do translation in dedicated extension & cover TranslatableInterface and form options
class FormTranslationExtension implements ExtensionInterface
{
    public function __construct(private TranslatorInterface $translator)
    {
    }

    public function apply(FormInterface $form, array $schema): array
    {
        $schema = $this->addLabel($form, $schema);
        $schema = $this->addDescription($form, $schema);
        $schema = $this->addChoices($form, $schema);

        return $schema;
    }

    protected function addChoices(FormInterface $form, array $schema): array
    {
        if (!FormUtil::isTypeInAncestry($form, 'choice')) {
            return $schema;
        }

        $getChoiceDomain = static function ($choiceView) use ($form): null|false|string {
            $domain = $form->getConfig()->getOption('choice_translation_domain');

            if (false === $domain) {
                return false;
            }

            if (null === $domain) {
                return $form->getConfig()->getOption('translation_domain');
            }

            return $domain;
        };

        $trans = $this->trans(...);
        $transChoiceView = static function ($choiceView) use ($getChoiceDomain, $trans): string {
            $domain = $getChoiceDomain($choiceView);

            if (false === $domain) {
                return (string) $choiceView->label;
            } else {
                return $trans(
                    $choiceView->label,
                    $choiceView->labelTranslationParameters,
                    $domain,
                );
            }
        };


        $titles = [];
        foreach ($form->createView()->vars['choices'] as $choiceView) {
            if ($choiceView instanceof ChoiceGroupView) {
                foreach ($choiceView->choices as $choiceItem) {
                    $titles[] = $transChoiceView($choiceItem);
                }
            } else {
                $titles[] = $transChoiceView($choiceView);
            }
        }

        $schema['enum_titles'] = $titles;
        $schema['options']['enum_titles'] = $titles;

        return $schema;
    }

    protected function addLabel(FormInterface $form, array $schema): array
    {
        $label = $form->getConfig()->getOption('label') ?: $form->getName();
        $schema['title'] = $this->trans(
            $label,
            $form->getConfig()->getOption('label_translation_parameters', []),
            $form->getConfig()->getOption('translation_domain'),
        );

        return $schema;
    }

    protected function addDescription(FormInterface $form, array $schema): array
    {
        $formConfig = $form->getConfig();

        if ($liform = $formConfig->getOption('liform')) {
            if (isset($liform['description']) && $description = $liform['description']) {
                $schema['description'] = $this->trans(
                    $description,
                    [],
                    $form->getConfig()->getOption('translation_domain'),
                );
            }
        } elseif ($help = $formConfig->getOption('help')) {
            $schema['description'] = $this->trans(
                $help,
                $form->getConfig()->getOption('help_translation_parameters', []),
                $form->getConfig()->getOption('translation_domain'),
            );
        }

        return $schema;
    }

    protected function trans(string|\Stringable|TranslatableInterface $item, array $parameters = [], ?string $domain = null): string
    {
        if ($item instanceof TranslatableInterface) {
            return $item->trans($this->translator);
        }

        $item = (string) $item;
        if (empty($item)) {
            return '';
        }

        return $this->translator->trans($item, $parameters, $domain);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions