Language negotiation config is not overrideable.

Created on 11 November 2023, about 1 year ago
Updated 13 November 2023, about 1 year ago

Problem/Motivation

The language negotiation system, particularly the language.types config item, is not overridable with traditional config override mechanisms, due to the way this config was built.

First, since the $config['language.types']['negotiation']['language_interface']['enabled'] configuration, for example, is an array, it makes it impossible to unset a default array item through code, like "language_url".

Second, and more importantly, the "enabled" and the "method_weights" keys both are key/value pairs, where the value is a weight that gets set by default via code, and then via the /admin/config/regional/language/detection page.

From what I can tell, Drupal core orders the array keys based on the weights when this config gets saved via the form, but if you attempt to use a config override on this configuration item, you cannot change the order of the keys.
So consider the below Drupal config override...

  public function loadOverrides($names) {
    $overrides = [];
    if (in_array('language.types', $names)) {
      $overrides['language.types']['negotiation']['language_interface']['enabled']['language-session'] = -100;
    }
    return $overrides;
  }

When you then run $ drush config:get language.types --include-overridden you will end up seeing something like this (I'm sort of glomming these together)...

[...]
negotiation:
  [...]
  language_interface:
    enabled:
      language-url: 0
      language-session: -100

So in this example, you can see that I am setting "language-session" to have a weight of -100 (same as the form would do), but b/c it's an override, it comes 2nd in the array, which actually means it does not work...

Now, consider the following code in the LanguageNegotiator.php class.

  protected function getEnabledNegotiators($type) { 
    return $this->configFactory->get('language.types')->get('negotiation.' . $type . '.enabled') ?: [];
  }

This method will get the negotiators from the config, but it does not respect that weight, and expects it to already be sorted (which is fine if you use the UI). And the order is important! In the example above, the "language-url" negotiator will execute first, and come back with the language, and it never makes it to "language-session" at all!

Steps to reproduce

Admittedly these are pretty loose steps to reproduce...

  1. Implement a config override similar to the code above.
  2. Visit a page you expect to respect your override.
  3. Observe that your override gets ignored by the language negotiator.

Proposed resolution

I would suggest that we update the LanguageNegotiator::getEnabledNegotiators() method to return results that respect the WEIGHT that's saved. Like an asort()?

I'm additionally linking to some issues that have to do with clearing arrays in config overrides which I think would also be relevant here. Maybe it's a stretch, or even a bigger long-term solution, but the config structure could also change to be more normalized, I guess (?). It's a very different config structure, that's for sure...

Remaining tasks

  1. Write a test to show the issue...
  2. Update the method to sort the array before returning

User interface changes

N/A

API changes

N/A, I don't believe...

Data model changes

N/A

Release notes snippet

N/A

πŸ› Bug report
Status

Closed: duplicate

Version

11.0 πŸ”₯

Component
Language systemΒ  β†’

Last updated 1 day ago

  • Maintained by
  • πŸ‡©πŸ‡ͺGermany @sun
Created by

πŸ‡ΊπŸ‡ΈUnited States dpagini

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024