Problem/motivation

When the language module is enabled, content types, taxonomy terms, etc. have a language configuration element which allows you to configure the default language applied to the entity (bundle) with a checkbox:

HideCheckbox.jpg

Observed in user testing that this backwards pattern of needing to check a checkbox to turn OFF a feature is backwards, and people don't expect it to work like that. Even people who read and repeated the label to me understood it the other way around.

Proposed solution

Rename the checkbox to "Expose language selector" and don't check it by default. Might need internal changes to the configuration element / upgrade path as well given that we probably don't want to keep the opposite setting in the backend either.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sun’s picture

Status: Active » Needs review
FileSize
30.5 KB

Thanks. We're dealing with two common sense violations here at the same time:

- UX: Never expose a negated checkbox.

- DX: Avoid values that have a negated meaning, because it inherently means that all conditions need to be negated, too.

FWIW:

Off-hand, I do not understand why this setting is called 'language_hidden'. Originally, I assumed this to be a UI/UX hiccup only, but after grepping + adjusting the entire code base, it appears to me that this value has a much larger meaning and consequences than just show/hide.

I almost have the impression that the tweak in this patch is incorrect — instead of 'language_show', it should probably be 'language_enabled' or something.

...and if that is the case, then I'm not sure whether I understand why this setting exists in the first place, and whether it doesn't actually duplicate some other configuration elsewhere... (?)

[At this point, it should be obvious that I'm a little lost ;)]

Bojhan’s picture

Pretty image plz :D And @sun is correct, its even in the handbooks at http://drupal.org/node/387526 - wish we could scan drupal for these mistakes.

Status: Needs review » Needs work

The last submitted patch, drupal8.language-hidden.1.patch, failed testing.

Gábor Hojtsy’s picture

@sun: the goal of this checkbox is to expose a language dropdown to users. If the dropdown is not exposed, language is still "enabled", it is just that the default language option set will be used and no user interaction will be allowed. So it is *very* similar to exposed filters in Views. If it is not exposed, the admin set value is used, if it is exposed, the user can change the value.

Even without language module enabled, things which could otherwise have an exposed language selector get language_default()->langcode as their value. So for backwards compatibility (and to avoid magic), when you enable language module, the language selector is not tacked onto everything right away but it requires configuration to be enabled for each (the settings defaults to the site default language and to hide the selector). So the "Hide" option is enabled by default currently. I guess our thinking was that hiding *is* *the* *feature*, but that is silly :D Exposing is the feature.

sun’s picture

Should we rename it from 'language_show' to 'language_select' then? Or 'language_user_overridable' ? :)

The new checkbox is:

[ ] Show language selector on create and edit pages

Without description.

Gábor Hojtsy’s picture

I originally thought "expose" because views has that too, and its a similar concept, but I'm equally happy with "show" if that works. 'language_show' works for me too, or "language_expose" or "language_editable" or something. I don't have a strong preference on wording.

Bojhan’s picture

Show just sounds a little less scary than expose :)

Gábor Hojtsy’s picture

Works for me. :)

Gábor Hojtsy’s picture

Status: Needs work » Needs review
Issue tags: +sprint
FileSize
4.54 KB
34.71 KB

Rerolled @sun's patch (it did not apply at a couple places) and found a couple more places where language_hidden was used. I think those were mostly introduced since his patch.

Status: Needs review » Needs work

The last submitted patch, drupal8.language-hidden.9.patch, failed testing.

vijaycs85’s picture

Status: Needs work » Needs review
FileSize
8.14 KB
37.05 KB

Fixing test cases in #9

Gábor Hojtsy’s picture

Good finds and good fixes, thanks!

Status: Needs review » Needs work

The last submitted patch, 1853720-drupal8.language-hidden-11.patch, failed testing.

vijaycs85’s picture

Status: Needs work » Needs review
FileSize
4.12 KB
38.11 KB

Fixing test cases.

YesCT’s picture

Issue tags: +medium
Gábor Hojtsy’s picture

Status: Needs review » Needs work
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.phpundefined
@@ -78,9 +78,9 @@ public function testLanguageUpgrade() {
     // Check for node content type settings upgrade.
     $this->drupalGet('node/add/article');
-    $this->assertField('langcode', 'There is a language selector.');
+    $this->assertNoField('langcode', 'There is a language selector.');
     $this->drupalGet('node/add/page');
-    $this->assertNoField('langcode', 'There is no language selector.');
+    $this->assertField('langcode', 'There is no language selector.');

Uhm, hum, that sounds like it negates the tested things? The assert text contradicts the assert code. Does not look like a correct fix?!

vijaycs85’s picture

Updating asset text.

vijaycs85’s picture

Status: Needs work » Needs review
YesCT’s picture

Sometimes interdiff'ing to specific patches in the past is helpful. (like the interdiff to 11)
A plain interdiff to whatever the most recent patch is should also usually be included.

I'm guessing you can just do that next time, just interdiff back to the most recent patch.

Gábor Hojtsy’s picture

So the upgrade path seems to test the opposite of what happened before, but the test data did not change, so the upgrade is bugos?! Adjusting the test for the bugos behavior is not very good I think. Unless I'm missing something.

vijaycs85’s picture

Hopefully node.install change fix test case issue.

Gábor Hojtsy’s picture

Status: Needs review » Needs work

That looks good :) I am still seeing chnages in the patch where the TRUE/FALSE value in the test and assert did not change, even though it is now testing the show feature v.s the hide feature, so the test is essentially changed to do the opposite. However, to keep the behavior, wherever the property rename is done, the value should also be flipped in the test data setup and the assertion. Otherwise looks good, thanks for working on this, it is going to be a great usability improvement!

vijaycs85’s picture

Hi @Gábor Hojtsy , thank you for your review. Except below one, we are good with other parts (i.e. we have replace FALSE as TRUE and TRUE as FALSE):

   public function testLanguageConfigurationElement() {
     $this->drupalGet('language-tests/language_configuration_element');
     $edit['lang_configuration[langcode]'] = 'current_interface';
-    $edit['lang_configuration[language_hidden]'] = TRUE;
+    $edit['lang_configuration[language_show]'] = TRUE;
     $this->drupalPost(NULL, $edit, 'Save');
     $lang_conf = language_get_default_configuration('some_custom_type', 'some_bundle');

     // Check that the settings have been saved.
     $this->assertEqual($lang_conf['langcode'], 'current_interface');
-    $this->assertTrue($lang_conf['language_hidden']);
+    $this->assertTrue($lang_conf['language_show']);
     $this->drupalGet('language-tests/language_configuration_element');
     $this->assertOptionSelected('edit-lang-configuration-langcode', 'current_interface');
-    $this->assertFieldChecked('edit-lang-configuration-language-hidden');
+    $this->assertFieldChecked('edit-lang-configuration-language-show');

     // Reload the page and save again.
     $this->drupalGet('language-tests/language_configuration_element');
     $edit['lang_configuration[langcode]'] = 'authors_default';
-    $edit['lang_configuration[language_hidden]'] = FALSE;
+    $edit['lang_configuration[language_show]'] = FALSE;
     $this->drupalPost(NULL, $edit, 'Save');
     $lang_conf = language_get_default_configuration('some_custom_type', 'some_bundle');

     // Check that the settings have been saved.
     $this->assertEqual($lang_conf['langcode'], 'authors_default');
-    $this->assertFalse($lang_conf['language_hidden']);
+    $this->assertFalse($lang_conf['language_show']);
     $this->drupalGet('language-tests/language_configuration_element');
     $this->assertOptionSelected('edit-lang-configuration-langcode', 'authors_default');
-    $this->assertNoFieldChecked('edit-lang-configuration-language-hidden');
+    $this->assertNoFieldChecked('edit-lang-configuration-language-show');
   }

vs.

   public function testLanguageConfigurationElement() {
     $this->drupalGet('language-tests/language_configuration_element');
-    $edit['lang_configuration[langcode]'] = 'current_interface';
-    $edit['lang_configuration[language_hidden]'] = TRUE;
+    $edit['lang_configuration[langcode]'] = 'authors_default';
+    $edit['lang_configuration[language_show]'] = FALSE;
     $this->drupalPost(NULL, $edit, 'Save');
     $lang_conf = language_get_default_configuration('some_custom_type', 'some_bundle');

     // Check that the settings have been saved.
-    $this->assertEqual($lang_conf['langcode'], 'current_interface');
-    $this->assertTrue($lang_conf['language_hidden']);
+    $this->assertEqual($lang_conf['langcode'], 'authors_default');
+    $this->assertFalse($lang_conf['language_show']);
     $this->drupalGet('language-tests/language_configuration_element');
-    $this->assertOptionSelected('edit-lang-configuration-langcode', 'current_interface');
-    $this->assertFieldChecked('edit-lang-configuration-language-hidden');
+    $this->assertOptionSelected('edit-lang-configuration-langcode', 'authors_default');
+    $this->assertNoFieldChecked('edit-lang-configuration-language-show');

     // Reload the page and save again.
     $this->drupalGet('language-tests/language_configuration_element');
-    $edit['lang_configuration[langcode]'] = 'authors_default';
-    $edit['lang_configuration[language_hidden]'] = FALSE;
+    $edit['lang_configuration[langcode]'] = 'current_interface';
+    $edit['lang_configuration[language_show]'] = TRUE;
     $this->drupalPost(NULL, $edit, 'Save');
     $lang_conf = language_get_default_configuration('some_custom_type', 'some_bundle');

     // Check that the settings have been saved.
-    $this->assertEqual($lang_conf['langcode'], 'authors_default');
-    $this->assertFalse($lang_conf['language_hidden']);
+    $this->assertEqual($lang_conf['langcode'], 'current_interface');
+    $this->assertTrue($lang_conf['language_show']);
     $this->drupalGet('language-tests/language_configuration_element');
-    $this->assertOptionSelected('edit-lang-configuration-langcode', 'authors_default');
-    $this->assertNoFieldChecked('edit-lang-configuration-language-hidden');
+    $this->assertOptionSelected('edit-lang-configuration-langcode', 'current_interface');
+    $this->assertFieldChecked('edit-lang-configuration-language-show');
   }

As you can see, by not changing the TRUE/FALSE, but the assert part (NoField to Field and assertTrue to assertFalse), we are changing the order of test cases and It covers exactly the same it used to.

However I have committed the changes to make this patch clear and consistent with other part of this patch.

Thank you.

Regards,
Vijay.

vijaycs85’s picture

Status: Needs work » Needs review
Gábor Hojtsy’s picture

Status: Needs review » Needs work
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.phpundefined
@@ -35,31 +35,31 @@ public static function getInfo() {
-    $edit['lang_configuration[langcode]'] = 'current_interface';
-    $edit['lang_configuration[language_hidden]'] = TRUE;
+    $edit['lang_configuration[langcode]'] = 'authors_default';
+    $edit['lang_configuration[language_show]'] = FALSE;
...
-    $this->assertEqual($lang_conf['langcode'], 'current_interface');
-    $this->assertTrue($lang_conf['language_hidden']);
+    $this->assertEqual($lang_conf['langcode'], 'authors_default');
+    $this->assertFalse($lang_conf['language_show']);

And so on... Can we limit the scope of the patch to changes only related to the rename? Why would we need to change the test to test the authors_default language instead of the current interface language while flipping the show condition as per the required change? Why is changing the type needed?!

Can we limit the scope to only the changes required? It *really* helps review the patch and get it in sooner and simpler.

Thanks!

vijaycs85’s picture

Status: Needs work » Needs review
FileSize
37.04 KB

Updating patch with review comments in #25.

Gábor Hojtsy’s picture

Status: Needs review » Needs work

Unfortunately still contains flipped test logic still. Discussed in IRC:

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.phpundefined
@@ -36,30 +36,30 @@ public static function getInfo() {
-    $edit['lang_configuration[language_hidden]'] = TRUE;
+    $edit['lang_configuration[language_show]'] = TRUE;
...
-    $this->assertTrue($lang_conf['language_hidden']);
+    $this->assertTrue($lang_conf['language_show']);

These ones.

vijaycs85’s picture

Status: Needs work » Needs review
FileSize
2.35 KB
37.04 KB
vijaycs85’s picture

Gábor Hojtsy’s picture

Looks all good to me now. Should be RTBC once it gets back green :)

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community
Dries’s picture

Status: Reviewed & tested by the community » Fixed

Nice UX clean-up. Glad we are doing user testing. Committed to 8.x.

Gábor Hojtsy’s picture

Issue tags: -sprint

Perfect thanks! @sun thanks for kicking this off! @vijaycs85 thanks for sticking to this :)

@Dries we did two user testing sessions so far (http://groups.drupal.org/node/274458 and http://groups.drupal.org/node/271918) and calling people to technically test systems in Drupal 8 as well (for example, lots of good crowd-sourced feedback in http://groups.drupal.org/node/276518). We should be able to verify our test driven changes once more of them lands (eg. #1869328: Restore simplicity of language list :).

YesCT’s picture

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