Problem/Motivation
In #1987398: field.module - Convert theme_ functions to Twig a bug was introduced that incorrectly translates the label of multi-value fields twice:
$header = array(
array(
- 'data' => '<h4 class="label">' . t('!title !required', array('!title' => $element['#title'], '!required' => $required)) . "</h4>",
+ 'data' => array(
+ '#prefix' => '<h4 class="label">',
+ 'title' => array(
+ '#markup' => t($element['#title']),
+ ),
+ '#suffix' => '</h4>',
+ ),
'colspan' => 2,
'class' => array('field-label'),
),
The $element['#title']
value is already translated at this stage:
- As translated string, in the case of config fields
- As
TranslatableMarkup
in the case of base fields
This provides a wrong translation in the first case and throw an InvalidArgumentException
in the 2nd case.
Proposed resolution
- Remove the
t()
that wraps$element['#title']
. - Remove also the 'title' wrapping of #markup item. That seems superfluous.
- Add test.
Remaining tasks
None.
User interface changes
None.
API changes
None.
Data model changes
None.
Original report, by @ChristianAdamski
Hey,
the issue described here is probaby more widespread than just the scenario. I therefor assume there already is an issue for this, I just couldn't find any
Reproduce Problem:
- define an entity reference BaseFieldDefinition in a custom entity
- Use entity_reference_autocomplete
- use setLabel(t("Hello World")); as done across core
- allow more than one entry
- WSOD when trying to edit
Reason:
In template_preprocess_field_multiple_value_form() in line 1580 you'll find
'#markup' => t($element['#title']),
but $element['#title'] already contains translatableMarkup. I do not know what happens afterwards, as the result is also translatableMarkup, but it is different and results in WSOD.
Fix:
Remove the t(), the field label is already translated at this point.
Comment | File | Size | Author |
---|---|---|---|
#26 | interdiff.txt | 680 bytes | joelpittet |
#26 | double_translation_in-2584837-26.patch | 4.14 KB | joelpittet |
#21 | interdiff.txt | 4.35 KB | claudiu.cristea |
#21 | 2584837-21.patch | 4.17 KB | claudiu.cristea |
Comments
Comment #2
joelpittetThank you @ChristianAdamski, that shouldn't be there for sure.
Comment #3
joelpittetOh and this is RTBC
Comment #4
swentel CreditAttribution: swentel commentedHmm, we should definitely have a test for this, because we've been running around in circles with t() in those methods.
Comment #5
BerdirHere's a quick test for this. Name and location is bad, copied it of an existing test that dealt with that entity type. Was hoping we'd also have an existing web test for that but we don't. And multiple fun bugs prevented that from happening actually, like the fact that that entity type shared the same base table, which doesn't give you an error but then isn't the table structure you expect when you save ;)
Comment #6
BerdirBy the way, this bug got introduces with #1987398: field.module - Convert theme_ functions to Twig, which incorrectly converted the previous code:
So this was never intended to be translatable like this.
Comment #8
joelpittetYeah that was wrong before and after the twig conversion for different reasons. We shouldn't be doing
t('!title !required')
either.But that h4 should really be in the template.
Comment #9
joelpittetThis seems to do the trick, a couple nit picks. @Berdir is there more you'd like to do here? New name/location for the tests?
Otherwise it seems to be testing what it needs to test.
nit: excess whitespace.
nit: weights likely not needed?
Comment #10
slashrsm CreditAttribution: slashrsm as a volunteer commentedFixed. I kept weights as all other fields defined there have it.
Comment #11
star-szrIf possible let's try to combine efforts with what I think might be a duplicate and filed as critical: #2585483: Fatal error when generating form for multivalued base field
Comment #12
Berdir#8: It wasn't actually as stupid as you'd think ;) Think right to left languages, like russion. They want to have the label first and then the required marker.
And yes, definitely a duplicate of that other one.
Comment #13
claudiu.cristea@Cottser, the patch provided here seems to me more compact. Also this issue is older (with few hours!) than the other one. Let's go with this one by:
Review:
Let's drop also the 'title' wrapper. Is there a good reason for wrapping the #markup?
Is this test belonging to Field UI module? As far as I know, field_ui is providing administrative UI for managing fields, display modes and displays. This bug exists even if Field UI is disabled. Moreover, the crash is revealed by a base field that has nothing to do with field or field_ui modules. I propose to move it under
Drupal\system\Tests\Entity
. Also the name of the class sounds unrelated to the issue. How aboutMultipleCardinalityFieldTest
? Or something similar?Some of them are not used, some of them are already installed upstream. It should work only with 'entity_test' module in the list :-)
testLabelWithMultipleCardinality()? If you agree, adapt also the docblock.
Comment #14
claudiu.cristeaFixed IS.
Comment #15
dawehnerYes, at least in core #title is coming from
$this->fieldDefinition->getLabel()
, see\Drupal\Core\Field\WidgetBase::formMultipleElements
What about adding some
<script>alert(123)</script>
to ensure we escape the result or at least xss filter it somewhere?Comment #16
claudiu.cristeaFixed points from #13 and #15.
Comment #17
BerdirBase fields didn't have this problem, configurable fields. So to test this, you need to additionally add a configurable field.
Comment #18
dawehnerYeah totally agree with @Berdir, we need a test with a configurable field.
Comment #19
claudiu.cristeaOK. Moved to configurable field.
Comment #20
effulgentsia CreditAttribution: effulgentsia at Acquia commentedWhat about moving this test to
Drupal\field\Tests\FormTest
? Also, since a configurable field is now also tested, perhaps "Base" should be removed from the method name? Or should we split into 2 test methods: one for base, one for configurable?Comment #21
claudiu.cristeaYes, I think it's a good idea.
Renamed to
testLabelOnMultiValueFields()
Comment #22
joelpittetGreat back to RTBC, thanks for all the test help!
Comment #23
ChristianAdamski CreditAttribution: ChristianAdamski as a volunteer commentedJust asking:
The patch is replacing the 'title' directly with '#markup'. The 'title' is not referenced anywhere?
If not: thumbs up.
Comment #24
joelpittet@ChristianAdamski good question, though this is in preprocess, so unless someone in contrib is overriding this template or preprocess and trying to deconstruct the built up table on this admin field. It's highly unlikely this would be referenced somewhere else. If they were overriding they would likely build up that table(or other structure) using the original value in
$element['#title']
Comment #25
alexpottI think removing the
title
level here is unnecessary. Since we're in RC we should not be making unnecessary change - even in the service of a critical.Comment #26
joelpittetChanged that back as it's unnessasary change for RC. I think it's an improvement but not a necessity.
RTBC because it doesn't change the output and result whatsoever.
Comment #27
alexpottThanks, one less t() to worry about :)
Committed 26d5a5f and pushed to 8.0.x. Thanks!
Comment #29
effulgentsia CreditAttribution: effulgentsia at Acquia commentedI think it would make for a fine 8.1 issue if someone feels like opening that.
Comment #30
joelpittet@effulgentsia done #2592025: template_preprocess_field_multiple_value_form() remove nested render arrays