Updated: Comment #1

Commit message:

Issue #2074509 by tim.plunkett, falcon03, mgifford, Xano: Fixed Add missing #title property to ensure form accessibility.

Problem/Motivation

#933004: Test that all form elements have a title for accessibility proposed a new FAPI property to force #title properties on certain element.
That led us to finding dozens of form elements with missing #titles.

However, it might be too late to add that API, but we can still salvage the form additions.

Proposed resolution

Add in #title in missing places, using '#title_display' => 'invisible', when the title is not visually appropriate.

Remaining tasks

N/A

User interface changes

Some form elements will have titles, but very few are visibly changed.

API changes

N/A

#933004: Test that all form elements have a title for accessibility

Files: 
CommentFileSizeAuthor
#15 title-2074509-15.patch56.84 KBtim.plunkett
PASSED: [[SimpleTest]]: [MySQL] 58,702 pass(es).
[ View ]
#11 form-title-2074509-11.patch56.84 KBtim.plunkett
PASSED: [[SimpleTest]]: [MySQL] 58,043 pass(es).
[ View ]
#9 title-2074509-9.patch56.72 KBtim.plunkett
PASSED: [[SimpleTest]]: [MySQL] 58,432 pass(es).
[ View ]
#9 interdiff.txt7.82 KBtim.plunkett
#1 title-2074509-1.patch51.04 KBtim.plunkett
PASSED: [[SimpleTest]]: [MySQL] 58,186 pass(es).
[ View ]

Comments

Status:Active» Needs review
StatusFileSize
new51.04 KB
PASSED: [[SimpleTest]]: [MySQL] 58,186 pass(es).
[ View ]

I added the proper commit message to the summary, that was based on what dreditor generated for the original issue.

Issue tags:+accessibility

Tagging.

Status:Needs review» Needs work

Ok, so I started reviewing the patch but I don't think I'm still awake enough (It's 5 past 1 AM here) to keep reviewing it. I'll complete the review tomorrow; if someone wants to review the remaining part, you can start from the update module files. Also, I think this is my first serious review; let me know if I did something wrong. And finally... Sorry in advance for eventual stupid questions contained in the review ;)

+++ b/core/modules/action/lib/Drupal/action/ActionFormControllerBase.php
@@ -72,7 +72,6 @@ public function form(array $form, array &$form_state) {
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine name'),
       '#default_value' => $this->entity->id(),
       '#disabled' => !$this->entity->isNew(),
       '#maxlength' => 64,
This makes me not really happy. What's the reason for doing this? The same applies to other "Machine name" label removals.
+++ b/core/modules/book/book.admin.inc
@@ -160,6 +160,8 @@ function _book_admin_table_tree($tree, &$form) {
       'depth' => array('#type' => 'value', '#value' => $data['link']['depth']),
       'href' => array('#type' => 'value', '#value' => $data['link']['href']),
       'title' => array(
+        '#title' => t('Title'),
+        '#title_display' => 'invisible',
         '#type' => 'textfield',
         '#default_value' => $data['link']['link_title'],
         '#maxlength' => 255,
OK maybe this is a stupid remark, but I don't really understand this syntax -- Why do we need to wrap #title and #title_display into another array ('title')? There are many other places in the patch where the same thing happens, so maybe I'm missing something..
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index 4360918..0d7f302 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -119,6 +119,7 @@ function comment_admin_overview($form, &$form_state, $arg) {
       '#account' => comment_prepare_author($comment),
     );
     $options[$comment->id()] = array(
+      'title' => array('data' => array('#title' => $comment->subject->value ?: $comment->id())),
       'subject' => array(
         'data' => array(
           '#type' => 'link',
Same as above, but this time there are two arrays before #title.
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -99,6 +100,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
             $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
               '#label' => $instance['label'],
               '#type' => 'checkbox',
+              '#title' => $instance['label'],
               '#default_value' => $field['translatable'],
             );
Not sure: do we need to t() or maybe check_plain() $instance['label'] before printing it out?
+++ b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
@@ -155,6 +155,8 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
         '#weight' => -100,
         '#multilingual' => TRUE,
         'source' => array(
+          '#title' => t('Select source language'),
+          '#title_display' => 'invisible',
           '#type' => 'select',
           '#default_value' => $source_langcode,
           '#options' => array(),
Same weird (to me) wrapping of #title and #title_display into another array.
+++ b/core/modules/entity/lib/Drupal/entity/Form/EntityDisplayModeFormBase.php
@@ -82,7 +82,6 @@ public function form(array $form, array &$form_state) {
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine-readable name'),
       '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
       '#disabled' => !$this->entity->isNew(),
       '#default_value' => $this->entity->id(),
Same as the previous "Machine name" removal -- I'm not really happy of it. But, in this case, maybe the text of the label should be standardized to "Machine name".
+++ b/core/modules/locale/css/locale.admin.css
@@ -85,9 +85,10 @@
   background: transparent url(../../../misc/menu-expanded.png) left .6em no-repeat;
}
-#locale-translation-status-form label {
+#locale-translation-status-form .label {
   color: #1d1d1d;
   font-size: 1.15em;
+  font-weight: bold;
}
Not sure what's going on here. :-)
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php
@@ -167,7 +167,7 @@ function testUpdateImportSourceRemote() {
     $this->drupalGet('admin/reports/translations/check');
     // Check the status on the Available translation status page.
-    $this->assertRaw('<label for="edit-langcodes-de" class="language-name">German</label>', 'German language found');
+    $this->assertRaw('<label class="visually-hidden" for="edit-langcodes-de">Update German</label>', 'German language found');
Is the "language-name" class removal intended?
+++ b/core/modules/locale/locale.pages.inc
@@ -527,12 +529,20 @@ function locale_translation_status_form($form, &$form_state) {
         }
       }
       $options[$langcode] = array(
-        'title' => check_plain($languages[$langcode]->name),
+        'title' => array(
+          'class' => array('label'),
+          'data' => array(
+            '#title' => $title,
+            '#markup' => $title
+          ),
+        ),
Same weird array-nesting here. Also:
- Why do we need to pass $title both as '#markup' and '#title'?
- Why are we adding a "label" class here?
     // Sort the table data on language name.
-    uasort($options, 'drupal_sort_title');
+    uasort($options, function ($a, $b) {
+      return strcasecmp($a['title']['data']['#title'], $b['title']['data']['#title']);
+    });
   }
Stupid question: why do we need this?
@@ -639,13 +649,6 @@ function locale_translation_status_form_submit($form, &$form_state) {
  * translation files could not be found.
  */
function locale_translation_language_table($form_element) {
-  // Add labels to Language names.
-  foreach ($form_element['#options'] as $langcode => $option) {
-    $id = $form_element[$langcode]['#id'];
-    $title = $option['title'];
-    $form_element['#options'][$langcode]['title'] = '<label for="' . $form_element[$langcode]['#id'] . '" class="language-name">' . $title . '</label>';
-  }
-
I guess this was useless code -- wasn't it?
+++ b/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php
@@ -125,7 +125,6 @@ public function form(array $form, array &$form_state) {
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine-readable name'),
       '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
       '#disabled' => !$this->entity->isNew(),
       '#default_value' => $this->entity->id(),
Same "Machine name" label removal that makes me not really happy. This also needs to be standardized on "Machine name", eventually.
diff --git a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
index 291f7bb..175d593 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
+++ b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
@@ -83,6 +84,7 @@ function ajax_forms_test_simple_form($form, &$form_state) {
   foreach ($invalid_callbacks as $key => $value) {
     $form['select_' . $key . '_callback'] = array(
       '#type' => 'select',
+      '#title' => t('Test %key callbacks', array('%key' => $key)),
       '#options' => array('red' => 'red'),
       '#ajax' => array('callback' => $value),
     );
Not a particular problem, but is there any standard on using % and/or @ to replace strings with variables in t()?
+++ b/core/modules/system/tests/modules/batch_test/batch_test.module
@@ -312,6 +312,7 @@ function _batch_test_nested_drupal_form_submit_callback($value) {
  */
function batch_test_mock_form($form, $form_state) {
   $form['test_value'] = array(
+    '#title' => t('Test value'),
     '#type' => 'textfield',
   );
This is not a problem for me, but can we use t() in this case?
+++ b/core/modules/system/tests/modules/database_test/database_test.module
@@ -233,6 +234,7 @@ function database_test_theme_tablesort($form, &$form_state) {
   foreach (user_load_multiple($uids) as $account) {
     $options[$account->id()] = array(
+      'title' => array('data' => array('#title' => String::checkPlain($account->getUsername()))),
       'username' => check_plain($account->getUsername()),
       'status' =>  $account->isActive() ? t('active') : t('blocked'),
     );
Same weird array nesting. If we really have to keep this kind of nesting, I would suggest splitting up the code in different lines to improve it's readability.
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -701,6 +701,7 @@ function _form_test_tableselect_get_data() {
   );
   $options['row1'] = array(
+    'title' => array('data' => array('#title' => t('row1'))),
     'one' => 'row1col1',
     'two' => t('row1col2'),
     'three' => t('row1col3'),
Exactly the same as above.
@@ -708,6 +709,7 @@ function _form_test_tableselect_get_data() {
   );
   $options['row2'] = array(
+    'title' => array('data' => array('#title' => t('row2'))),
     'one' => 'row2col1',
     'two' => t('row2col2'),
     'three' => t('row2col3'),
Exactly the same as above.
@@ -715,6 +717,7 @@ function _form_test_tableselect_get_data() {
   );
   $options['row3'] = array(
+    'title' => array('data' => array('#title' => t('row3'))),
     'one' => 'row3col1',
     'two' => t('row3col2'),
     'three' => t('row3col3'),
Exactly the same as above.

t('Machine name') is added as a default value for all #type => machine_name.
So that was all redundant, no need to worry about me removing it :)

I'll respond about the other feedback later, thanks for the review!

@tim.plunkett: thanks for clarifying that. I'm going to finish reviewing the patch: would you prefer me posting the whole review again or just the missing part?

Here's part 2 of the review. I reviewed the whole patch, but I didn't apply nor manually-tested it.

+++ b/core/modules/update/update.manager.inc
@@ -162,6 +162,11 @@ function update_manager_update_form($form, $form_state = array(), $context) {
         continue 2;
     }
+    // Use the project title for the tableselect checkboxes.
+    $entry['title'] = array('data' => array(
+      '#title' => $entry['title'],
+      '#markup' => $entry['title'],
+    ));
     $entry['#attributes'] = array('class' => array('update-' . $type));
Weird array nesting here as well. Plus, Maybe we'd better split the code into more lines (e.g. defining the data array in a new line). Plus, we're passing the label both as #title and #markup -- Why?
+++ b/core/modules/user/user.admin.inc
@@ -4,6 +4,7 @@
  * @file
  * Admin page callback file for the user module.
  */
+use Drupal\Component\Utility\String;
Looks like an useless use statement -- doesn't it? ;)
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/argument/ArgumentPluginBase.php
@@ -184,6 +184,8 @@ public function buildOptionsForm(&$form, &$form_state) {
       '#markup' => '<div class="clearfix"></div>',
     );
     $form['default_action'] = array(
+      '#title' => t('Default actions'),
+      '#title_display' => 'invisible',
       '#type' => 'radios',
       '#process' => array(array($this, 'processContainerRadios')),
       '#default_value' => $this->options['default_action'],
Not sure where this is used, but maybe "Default action" instead of "Default actions"?
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
@@ -745,6 +746,7 @@ public function groupForm(&$form, &$form_state) {
       $value = $this->options['group_info']['identifier'];
       $form[$value] = array(
+        '#title' => String::checkPlain($this->options['group_info']['label']),
         '#type' => $this->options['group_info']['widget'],
         '#default_value' => $this->group_info,
         '#options' => $groups,
Are we sure that $this->options['group_info']['widget'] contains a '#type' value that supports '#title'? I guess the answer is yes, but I thought it was worth asking this (eventually stupid) question. :-)
@@ -1012,6 +1010,8 @@ protected function buildExposedFiltersGroupForm(&$form, &$form_state) {
       // Per item group, we have a title that identifies it.
       $form['group_info']['group_items'][$item_id] = array(
         'title' => array(
+          '#title' => t('Label'),
+          '#title_display' => 'invisible',
           '#type' => 'textfield',
           '#size' => 20,
           '#default_value' => $default_title,
Weird array nesting here as well. But, this time it looks like the 'title' array contains the whole textfield definition.
@@ -1019,12 +1019,16 @@ protected function buildExposedFiltersGroupForm(&$form, &$form_state) {
         'operator' => $row['operator'],
         'value' => $row['value'],
         'remove' => array(
+          '#title' => t('Remove'),
+          '#title_display' => 'invisible',
           '#type' => 'checkbox',
           '#id' => 'views-removed-' . $item_id,
           '#attributes' => array('class' => array('views-remove-checkbox')),
           '#default_value' => 0,
         ),
What does this checkbox allow to remove? The label doesn't convey the information; not sure if the user knows what he/she is removing from the context, though (e.g. the checkbox is wrapped in a fieldset).
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/style/Table.php
@@ -378,6 +392,8 @@ public function buildOptionsForm(&$form, &$form_state) {
         ),
       );
       $form['info'][$field]['responsive'] = array(
+        '#title' => t('Responsive setting for @field', array('@field' => $field)),
+        '#title_display' => 'invisible',
         '#type' => 'select',
         '#default_value' => isset($this->options['info'][$field]['responsive']) ? $this->options['info'][$field]['responsive'] : '',
         '#options' => array('' => t('High'), RESPONSIVE_PRIORITY_MEDIUM => t('Medium'), RESPONSIVE_PRIORITY_LOW => t('Low')),
I need to think a little bit more about the most appropriate text for this label.
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
@@ -211,6 +211,7 @@ public function buildForm(array $form, array &$form_state) {
     $form['displays']['page'] = array(
       '#type' => 'fieldset',
+      '#title' => t('Page settings'),
       '#attributes' => array('class' => array('views-attachment', 'fieldset-no-legend')),
       '#tree' => TRUE,
     );
I'm remarking it here, but this statement is valid for views in general: after this patch gets in and [#504962] is fixed, we should consider cleaning up the views UI from useless fieldsets. In addition to this, the "fieldset-no-legend" css class is a lie -- we don't want a fieldset without a legend. If the purpose of this class is to hide the content of the legend, then it should be removed for consistency (#title_display should be used instead).
+++ b/core/modules/views/tests/modules/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php
@@ -108,10 +109,14 @@ public function buildForm(array $form, array &$form_state) {
         '#type' => 'textfield',
         '#default_value' => ++$count,
         '#attributes' => array('class' => array('weight')),
+        '#title_display' => 'invisible',
+        '#title' => t('Weight for @title', array('@title' => $name)),
       );
Nitpick: let's add #title before #title_display and let's move them before or after #type definition. :-) However, I don't care too much about it! :-)
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
@@ -98,6 +98,8 @@ public function buildForm(array $form, array &$form_state) {
       $form['displays'][$id]['removed'] = array(
         'checkbox' => array(
+          '#title' => t('Remove @id', array('@id' => $id)),
+          '#title_display' => 'invisible',
           '#type' => 'checkbox',
           '#id' => 'display-removed-' . $id,
           '#attributes' => array(
Famous weird array-nesting. :-)

@tim.plunkett: I've completed my first serious review. Maybe I outlined some non-existent issues; if so, let me know -- I'm always happy to learn! :D

I tried to be as short as possible in my notes in the review; if you need further details let me know! ;)

Assigned:Unassigned» tim.plunkett

Response to review in #3

Why do we need to wrap #title and #title_display into another array

The array wrapping it is the form element itself. #title is only useful with a #type.

+      'title' => array('data' => array('#title' => $comment->subject->value ?: $comment->id())),
this time there are two arrays before #title.

This is the style needed for '#type' => 'tableselect'

Not sure what's going on here.

Is the "language-name" class removal intended?

Why are we adding a "label" class here?

The CSS change is because we have a standard way of doing tabledrag, and the language code was working around it. To maintain visual consistency while improving the accessibility, I had to make a CSS change.

Why do we need to pass $title both as '#markup' and '#title'?

The #markup is for the actual printed value, the #title is for the title text or label, depending on the #type it is used in.

Stupid question: why do we need this?

I changed the structure of $options, we now sort by #title

I guess this was useless code -- wasn't it?

This is the simplification I made that resulted in the CSS change.

is there any standard on using % and/or @ to replace strings with variables in t()?

Yes, % results in the placeholder being wrapped in an EM tag. I just picked one, it doesn't matter really since it is a test code.

This is not a problem for me, but can we use t() in this case?

I am using t() here, and yes that's fine.

Same weird array nesting.

I personally think its fine, there will only ever be that in the row, no further additions (this is the syntax needed by tabledrag).

Response to review in #6

The "weird nesting" is pretty standard when it comes to 'data' in table code.

Not sure where this is used, but maybe "Default action" instead of "Default actions"?

It is a list of actions to be used as the default action, so I think "Default actions" is appropriate.

Are we sure that $this->options['group_info']['widget'] contains a '#type' value that supports '#title'?

Yes we are.

I will remove the extra use Drupal\Component\Utility\String; and fix the #title/#title_display ordering later.

Status:Needs work» Needs review
StatusFileSize
new7.82 KB
new56.72 KB
PASSED: [[SimpleTest]]: [MySQL] 58,432 pass(es).
[ View ]

I fixed all usages of #title_display to be directly after #title.
I removed the extra String use statement.
I also, after investigating its usage, removed the ambiguous 'Remove' title you questioned above. That input element is ALWAYS display:none, and is just used for JS.

All oddities around the array nesting are common enough patterns.

Status:Needs review» Needs work

@tim.plunkett: Patch looks really good, so I'd happily RTBC it... But, unfortunately it does not apply! :(

Also, regarding the "remove field": I'm fine with removing #title for it, since it is never displayed; however, if the property validation API would get in could that missing #title make tests fail? If so, let's keep that "Remove" title in without worrying too much about it! :-)

BTW: Not sure if I am able to be onLine until wednesday.

Status:Needs work» Needs review
StatusFileSize
new56.84 KB
PASSED: [[SimpleTest]]: [MySQL] 58,043 pass(es).
[ View ]

Quick reroll for the OverviewTerms form being converted.
I'd rather not add it in wrongly, and the other issue (if/when it happens) will catch it easily.

Status:Needs review» Reviewed & tested by the community

Completed a review of #11. This looks really good. Everything that stuck out at me in it as out of place, were addressed in earlier comments (like the css changes). Marking RTBC.

YAY! RTBC++! :-)

Status:Reviewed & tested by the community» Needs work

Most of this looks great. One "needs work" comment and a couple of questions.

+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -89,6 +89,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
+            '#title' => t($bundle),

AFAIK we are never, ever to do t($var). Gábor would know more about why that is.

+++ b/core/modules/locale/locale.pages.inc
@@ -527,12 +529,20 @@ function locale_translation_status_form($form, &$form_state) {
       $options[$langcode] = array(
-        'title' => check_plain($languages[$langcode]->name),
+        'title' => array(
+          'class' => array('label'),
+          'data' => array(
+            '#title' => $title,
+            '#markup' => $title
+          ),
+        ),

We removed check_plain here?

+++ b/core/modules/user/lib/Drupal/user/Form/UserPermissionsForm.php
@@ -139,7 +139,7 @@ public function buildForm(array $form, array &$form_state) {
-          $options[$perm] = '';
+          $options[$perm] = $perm_item['title'];

Is that translated somewhere?

Status:Needs work» Needs review
StatusFileSize
new56.84 KB
PASSED: [[SimpleTest]]: [MySQL] 58,702 pass(es).
[ View ]

$bundle was already translated, good catch!

+++ b/core/modules/locale/locale.pages.inc
@@ -520,6 +521,7 @@ function locale_translation_status_form($form, &$form_state) {
+      $title = String::checkPlain($languages[$langcode]->name);
       $locale_translation_update_info = array('#theme' => 'locale_translation_update_info');
       foreach (array('updates', 'not_found') as $update_status) {
         if (isset($update[$update_status])) {
@@ -527,12 +529,20 @@ function locale_translation_status_form($form, &$form_state) {
@@ -527,12 +529,20 @@ function locale_translation_status_form($form, &$form_state) {
         }
       }
       $options[$langcode] = array(
-        'title' => check_plain($languages[$langcode]->name),
+        'title' => array(
+          'class' => array('label'),
+          'data' => array(
+            '#title' => $title,
+            '#markup' => $title
+          ),
+        ),

This is the full context here, I moved it to a local variable so as to not run it twice

$options[$perm] = $perm_item['title']; is translated, its straight from hook_permission()

Status:Needs review» Reviewed & tested by the community

Patch applies cleanly. Bot can disagree if he wants to! :-)

I forgot the interdiff, it was just removing t() from the t($bundle) in the first snippet webchick pointed out.

Thanks falcon03!

@tim.plunkett: No problem for the interdiff. I knew what to look for in the new patch, so I quickly checked it out and it was fine for me! :-)

Looking forward to getting this into core! Great job Tim! :-)

Reposting the suggested commit message, since this was split off from another issue:
Issue #2074509 by tim.plunkett, falcon03, mgifford, Xano: Fixed Add missing #title property to ensure form accessibility.

Status:Reviewed & tested by the community» Fixed

Awesome!!

Committed and pushed to 8.x. Thanks!

Status:Fixed» Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Issue summary:View changes

updated for credit

+++ b/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -89,6 +89,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
@@ -89,6 +89,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
         if ($fields) {
           $form['settings'][$entity_type][$bundle]['translatable'] = array(
             '#type' => 'checkbox',
+            '#title' => $bundle,
             '#default_value' => content_translation_enabled($entity_type, $bundle),
           );
@@ -99,6 +100,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
@@ -99,6 +100,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
             $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
               '#label' => $instance['label'],
               '#type' => 'checkbox',
+              '#title' => $instance['label'],
               '#default_value' => $field['translatable'],
             );
             $column_element = content_translation_field_sync_widget($field, $instance);

These caused #2112303: Random extra text around translatability configuration is confusing. Note that as explained there these checkboxes get a <label for=""></label> elsewhere that is **more accessible** than the immediate simple text label that this patch introduced, because they include all levels of the hierarchy in visually hidden span parts.

So this does not only splintered the UI with some random (and inconsistent looking) labels, it is also *less accessible* (although there are now two <label for=""></label> elements for these, so who knows which one would a browser pick up on when reading out the form element.

Please see #2112303: Random extra text around translatability configuration is confusing for rollback of this part of the patch.

Issue summary:View changes

linking with the nice format to the issue it was split off of.