Skip to content

[Autocomplete] Translate the optgroup labels returned by the AJAX endpoint - #3763

Open
kira0269 wants to merge 1 commit into
symfony:2.xfrom
kira0269:fix/autocomplete-translate-optgroup-labels
Open

[Autocomplete] Translate the optgroup labels returned by the AJAX endpoint#3763
kira0269 wants to merge 1 commit into
symfony:2.xfrom
kira0269:fix/autocomplete-translate-optgroup-labels

Conversation

@kira0269

Copy link
Copy Markdown
Q A
Bug fix? yes
New feature? no
Issues -
License MIT

The group_by option of an autocomplete field produces the <optgroup> labels. When the <select> is rendered by the form theme, those labels go through |trans:

<optgroup label="{{ choice_translation_domain is same as(false) ? group_label : group_label|trans({}, choice_translation_domain) }}">

But the labels sent as JSON by the autocomplete endpoint are emitted verbatim by AutocompleteResultsExecutor:

$optgroups = array_map(static fn (string $label) => ['value' => $label, 'label' => $label], array_unique($optgroupLabels));

For an AJAX autocompleter this is the path that matters: the server-rendered <select> only holds the preselected option(s), so every group the user sees while typing comes from that JSON. Using a translation key in group_by therefore shows the raw key. It also makes the labels disagree with the server-rendered ones, which the Stimulus controller looks up by label:

const optgroupElement = parentElement.querySelector(`optgroup[label="${optgroupData.label}"]`);

What this PR does

  • AutocompleteResultsExecutor takes an optional TranslatorInterface and translates the optgroup labels. Values returned by group_by that implement TranslatableInterface are no longer cast to string either (casting a TranslatableMessage is a fatal error).
  • The domain comes from a new optional getTranslationDomain(): string|false|null method on the autocompleter — null uses the default domain, false disables the translation. It is declared as a @method on EntityAutocompleterInterface and commented out in the interface body, like getGroupBy(), and detected with method_exists(), so existing autocompleters keep working untouched.
  • WrappedEntityTypeAutocompleter implements it by reading the field's choice_translation_domain option, which is exactly what the form theme uses. So the AJAX results and the rendered <select> now agree.
  • The optgroup value keeps the untranslated label, so it still ties a result to its group whatever the locale is. Only the label is translated.

BC

The translator is an optional constructor argument wired with NULL_ON_INVALID_REFERENCE, and without it the previous behavior is kept. Autocompleters that do not implement getTranslationDomain() translate in the default domain, which matches what the form theme already does for the same labels.

…point

The labels produced by the "group_by" option are translated by the form
theme when the <select> is rendered, but the ones sent as JSON by the
autocomplete endpoint were emitted verbatim. For an AJAX autocompleter,
every group the user sees while typing comes from that JSON, so the
labels stayed untranslated, and they no longer matched the server
rendered <optgroup> the Stimulus controller looks up by label.

The executor now translates them, using the domain returned by the new
optional getTranslationDomain() method of the autocompleter, which the
entity autocomplete fields read from their "choice_translation_domain"
option. The optgroup "value" keeps the untranslated label so that it
still ties the results to their group whatever the locale is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@carsonbot carsonbot added Autocomplete Bug Bug Fix Status: Needs Review Needs to be reviewed labels Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants