Autocomplete choice labels don't translate
Platform is Symfony 6.3, with UX Autocomplete 2.9
My issue
My issue: I have a Symfony UX Autocomplete form field, the choice_labels are stored in translated form in the database. I cannot get the choice_label translation to work. It always defaults to English (my default locale).
I have KnpLabs Translatable installed & working.
My current setup:
- FunctionProfile Entity
- FunctionProfileTranslation Entity -> contains a translated name field.
- TrainingPickerType Form -> includes FunctionProfileAutocompleteField
- FunctionProfileAutocompleteField -> included in TrainingPickerType
Just to make sure, the entities and the forms (removed unneccessary parts of the code):
<?php
//App\Entity\FunctionProfile.php
namespace App\Entity;
use App\Repository\FunctionProfileRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Contract\Entity\TranslatableInterface;
use Knp\DoctrineBehaviors\Model\Translatable\TranslatableTrait;
#[ORM\Entity(repositoryClass: FunctionProfileRepository::class)]
class FunctionProfile implements TranslatableInterface
{
use TranslatableTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
//etc.
public function __toString(): string
{
return $this->translate(null, false)->getName();
}
//etc.
And it's friend:
<?php
namespace App\Entity;
//App\Entity\FunctionProfileTranslation.php
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Contract\Entity\TranslationInterface;
use Knp\DoctrineBehaviors\Model\Translatable\TranslationTrait;
#[ORM\Entity]
class FunctionProfileTranslation implements TranslationInterface
{
use TranslationTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(length: 255)]
private ?string $name = null;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}
Now for the form part, this main form includes the child form field that's not doing what I want it to do:
<?php
//App\Form\TrainingPickerType.php
namespace App\Form;
use App\Form\Field\FunctionProfileAutocompleteField;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class TrainingPickerType extends AbstractType
{
private TranslatorInterface $translator;
private UrlGeneratorInterface $router;
public function __construct(TranslatorInterface $translator, UrlGeneratorInterface $router)
{
$this->translator = $translator;
$this->router = $router;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$locale = $options['locale'];
$builder
->setAction($this->router->generate('app_api_get_training_pick_dialog'))
->add('functionProfile', FunctionProfileAutocompleteField::class, [
'label' => $this->translator->trans('Function Profiles', locale: $locale),
'attr' => ['class' => 'none', 'placeholder' => $this->translator->trans('Start typing or select an option...', locale: $locale),],
'label_attr' => ['class' => 'block text-sm font-medium leading-6 text-white'],
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'locale' => null
]);
}
}
The form hereabove behaves as it should, the locale is set to whatever it needs to be, labels are translated nicely, etc.
This included form field is the issue:
<?php
namespace App\Form\Field;
use App\Entity\FunctionProfile;
use App\Repository\FunctionProfileRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\UX\Autocomplete\Form\AsEntityAutocompleteField;
use Symfony\UX\Autocomplete\Form\ParentEntityAutocompleteType;
#[AsEntityAutocompleteField]
class FunctionProfileAutocompleteField extends AbstractType
{
private RequestStack $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function configureOptions(OptionsResolver $resolver)
{
$request = $this->requestStack->getCurrentRequest();
$query = $request?->query->get('query');
$locale = $request ? $request->getLocale() : 'nl';
$resolver->setDefaults([
'class' => FunctionProfile::class,
'multiple' => true,
'choice_translation_domain' => true,
'choice_label' => function (FunctionProfile $functionProfile) use ($locale) {
$functionProfile->getTranslations();
return $functionProfile->translate($locale)->getName();
},
'query_builder' => function(FunctionProfileRepository $functionProfileRepository) use ($locale, $query) {
$qb = $functionProfileRepository->createQueryBuilder('functionProfile')
->join('functionProfile.translations', 't', 'WITH', 't.locale = :locale')
->setParameter('locale', $locale);
if (!empty($query)) {
$qb->andWhere('t.name LIKE :search')
->setParameter('search', '%' . $query . '%');
}
return $qb;
},
]);
}
public function buildView(FormView|\Symfony\Component\Form\FormView $view, FormInterface|\Symfony\Component\Form\FormInterface $form, array $options): void
{
$view->vars['attr']['class'] = ''; // Remove any existing classes
}
public function getParent(): string
{
return ParentEntityAutocompleteType::class;
}
}
When I enter a query, the search happens. The autocomplete options are presented. But they're always in English, even if I manually set a different locale like "nl", the outcome remains the same: all choice_labels are in English.
Any guidance or help you may be able to provide would be super welcome!
What I have tried
I have searched the KnpLabs translatable docs for solutions, but couldn't find any solutions.
I have verified that (outside of the form field), the translated versions of the entity appear; as an example;
Neatly returns Banana when I run:
$test = $functionProfileRepository->findOneBy(["id" => 187]);
dd($test->translate('en')->getName());
And Banaan when I run:
$test = $functionProfileRepository->findOneBy(["id" => 187]);
dd($test->translate('nl')->getName());
I tried retrieving the choice_labels in a separate function and then add those to the choice_label option, but to no avail.
public function getTranslatedLabel(FunctionProfile $functionProfile)
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request ? $request->getLocale() : 'nl';
return $functionProfile->translate($locale)->getName();
}
I'm sorta out of idea's now.
I know about https://github.com/a2lix/TranslationFormBundle but my colleagues indicated not wanting to use it unless absolutely needed, citing bad experiences with earlier versions of the bundle. But if we must, we will use it.