Configuration langcode is forced to site default language

Created on 10 June 2020, about 4 years ago
Updated 3 April 2024, 3 months ago

Problem/Motivation

In #2212069: Non-English Drupal sites get default configuration in English, edited in English, originals not actually used if translated โ†’ , the function locale_system_set_config_langcodes() was introduced in locale.module. This function is called whenever a module (hook_modules_installed()) or theme (hook_themes_installed()) is installed, and it forces the language of configuration to be set to the site default language.

My case is that we have a multi-site (shared codebase, separate databases). Some of these sites have English as default language, many of them have some other language as the default. English language is still enabled on all sites. Currently, each site has its full configuration exported to /config/<site name>. As the sites mostly consist of the same set of features, a lot of the configs are just duplicates.

Our plan is to start combining all of the common config using the config_split module, in order to reduce duplicate config files. Due to this, we want to keep the configuration language as English, since otherwise it would become really hard to start combining those.

We currently have the configuration language as English for all configs, but whenever a module gets installed, the behaviour of locale module causes the configuration language to change, which we would not want.

Another factor is that when we are developing the sites, for example creating new fields and such, we want to do the development in English as we don't necessarily speak all of the languages that the multi-site uses. Example: If I were to create a new field to example.no, I want to enter the field label in English and not in Norwegian. The same config would then be used also in example.se and example.fi, and the field label would be translated on each site via the Translate Interface tool.

Proposed resolution

I came up with three different approaches:

  1. Defining our own implementations of hook_modules/themes_installed(), make sure that they are called after locale modules hooks, and then call our own helper function, which reverses the logic of what locale_system_set_config_langcodes() does
  2. Defining our own implementations of hook_modules/themes_installed(), make them be run instead of locale modules hooks, and make them be identical with locale modules hooks with the difference that they don't call locale_system_set_config_langcodes()
  3. Patching the locale module and remove the body of the locale_system_set_config_langcodes() function

Approach 1:


use Drupal\locale\Locale;

/**
 * @file
 * My module.
 *
 * We have multiple different sites and most of them have a non-English default
 * language. Currently the sites have their own configs exported to their own
 * directories, but we aim towards combining all of the common config using
 * config_split. Therefore we want to keep all of the configs in English.
 *
 * The locale module implements hook_modules_installed() and
 * hook_themes_installed(). Both implementations call
 * locale_system_set_config_langcodes(), which will force the langcode of all
 * config files to be set to the site's default language.
 *
 * In this module we implement the same hooks and then call our own function,
 * which basically reverses what locale module does.
 *
 * We also make sure our hooks are implemented after local module's hooks.
 */

/**
 * Implements hook_module_implements_alter().
 */
function mymodule_module_implements_alter(&$implementations, $hook) {
  if ($hook === 'modules_installed' || $hook === 'themes_installed') {
    // Move this module's hook's to be run immediately after the locale
    // module's hooks, since our code fixes configuration langcodes issues that
    // locale messes up.
    // The code below removes 'mymodule' from which ever position it
    // currently is in, finds the position of 'locale', and inserts
    // 'mymodule' immediately after it.
    $group = $implementations['mymodule'];
    unset($implementations['mymodule']);
    $local_position = array_search('locale', array_keys($implementations)) + 1;
    // Slice 1 contains all elements from the start to 'locale'.
    $slice1 = array_slice($implementations, 0, $local_position);
    // Slice 2 contains all elements that are after 'locale'.
    $slice2 = array_slice($implementations, $local_position);
    // Insert 'mymodule' so it's directly after 'locale'.
    $slice1['mymodule'] = $group;
    // Merge slices back together.
    $implementations = array_merge($slice1, $slice2);
  }
}

/**
 * Implements hook_modules_installed().
 */
function mymodule_modules_installed($modules) {
  mymodule_set_config_langcodes();
}

/**
 * Implements hook_themes_installed().
 */
function mymodule_themes_installed($theme_list) {
  mymodule_set_config_langcodes();
}

/**
 * Updates configuration langcodes to English.
 *
 * Basically this reverts what locale_system_set_config_langcodes() does, since
 * we want config langcodes to be in English.
 */
function mymodule_set_config_langcodes() {
  $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
  if ($default_langcode !== 'en') {
    $names = Locale::config()->getComponentNames();
    foreach ($names as $name) {
      $config = \Drupal::configFactory()->reset($name)->getEditable($name);
      if (!$config->isNew()) {
        $langcode = $config->get('langcode');
        if ($langcode === $default_langcode) {
          $config->set('langcode', 'en')->save();
        }
      }
    }
  }
}

Approach 2:


use Drupal\locale\Locale;

/**
 * @file
 * My module.
 *
 * We have multiple different sites and most of them have a non-English default
 * language. Currently the sites have their own configs exported to their own
 * directories, but we aim towards combining all of the common config using
 * config_split. Therefore we want to keep all of the configs in English.
 *
 * The locale module implements hook_modules_installed() and
 * hook_themes_installed(). Both implementations call
 * locale_system_set_config_langcodes(), which will force the langcode of all
 * config files to be set to the site's default language.
 *
 * In this module we implement the same hooks and use them INSTEAD of locale's
 * hooks. They are identical with the original hooks but with the callback to
 * locale_system_set_config_langcodes() removed.
 *
 * We use hook_module_implements_alter() to remove the original hooks.
 */

/**
 * Implements hook_module_implements_alter().
 */
function mymodule_config_module_implements_alter(&$implementations, $hook) {
  if ($hook === 'modules_installed' || $hook === 'themes_installed') {
    unset($implementations['locale']);
  }
}

/**
 * Implements hook_modules_installed().
 *
 * @see locale_modules_installed()
 */
function mymodule_config_modules_installed($modules) {
  $components['module'] = $modules;
  locale_system_update($components);
}

/**
 * Implements hook_themes_installed().
 *
 * @see locale_themes_installed()
 */
function mymodule_config_themes_installed($themes) {
  $components['theme'] = $themes;
  locale_system_update($components);
}

Approach 3:

See attached patch and apply it using composer.
This approach allows us to notice if locale.module is changed by a core update, since the patch would probably not apply anymore.

I can only assume that others have also faced similar problems as what I've described here. Even though I understand that this is the intended behaviour of Drupal core and of the locale module, it just doesn't fit our needs at the moment, which is why I posted some different approaches here for those who are interested.

โœจ Feature request
Status

Needs work

Version

11.0 ๐Ÿ”ฅ

Component
Language systemย  โ†’

Last updated about 6 hours ago

  • Maintained by
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany @sun
Created by

๐Ÿ‡ซ๐Ÿ‡ฎFinland Rade

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request โ†’ as a guide.

    This new feature request will require test coverage.
    Adding the new configuration option will require an upgrade path for existing sites.
    That new field may need a change record as well.

    Thanks.

  • last update about 1 year ago
    Patch Failed to Apply
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Antonรญn Slejลกka Hannover

    I get the following error message after composer update:
    Cannot apply patch #3150540 Config in en (patches/core/3150540-30.patch)!

    I have started a new test for 3150540-30.patch. The test failed: https://www.drupal.org/pift-ci-job/2657165 โ†’

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance ericdsd France

    This is quite logical as https://www.drupal.org/project/drupal/issues/2806009 ๐Ÿ› Installing a module causes translations to be overwritten Fixed has been fixed and committed in 9.5.9 release, i didn't test it yet but it should address this issue too.

  • last update about 1 year ago
    Patch Failed to Apply
  • ๐Ÿ‡ฑ๐Ÿ‡ปLatvia kalvis Riga

    Rerolled the patch from #30 against latest 9.5.x as it no longer applied due to some recent changes in core.
    NB! For the patch to take effect, after applying you need to untick the new checkbox in /admin/config/regional/translate/settings :)

    Couple of things I adjusted:
    - Renamed the new enable_set_config_langcodes setting to update_default_config_langcodes and updated some of the descriptions to be more aligned with the variable namings/descriptions that are already in core.
    - Fixed the default value assignment in settings form - if no value was present in config yet, checkbox was not selected (while it should be according to the defaults)
    - Removed the alteration part, not sure if it's really needed. But please feel free to add it back if so :)
    Here's the full diff, if you interested: https://www.drupal.org/files/issues/2023-05-24/reroll_diff_30_36.txt โ†’

    @ericdsd I tested with latest 9.5.x release on the same project which @Rade was working on when reporting this problem an it was still present. Thus the rerolled patch :)

  • last update about 1 year ago
    30,367 pass
  • last update about 1 year ago
    30,311 pass, 2 fail
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany arnalyse

    Just for completeness sake: Drupal 9.5.9 has removed the calls to locale_system_set_config_langcodes() which were former placed in locale_themes_installed() and locale_modules_installed().

    If I'm not mistaken locale_system_set_config_langcodes() isn't called anywhere else.

  • ๐Ÿ‡ช๐Ÿ‡ธSpain edurenye

    Seems like sometimes it does not work, but I'm not quite sure which conditions make it to not work, so I have the default language in Swedish, but we want the base config in English and have the translations in Swedish.
    And most of the time it works but then today I changed some permissions and when I exported it wanted to add the labels in Swedish to the English base exported config, really weird.

  • ๐Ÿ‡ช๐Ÿ‡ธSpain edurenye

    The patch does no longuer apply to Drupal 10.2.2.
    And `Locale::config()->updateDefaultConfigLangcodes();` is not called in `locale_system_set_config_langcodes()` anymore.

    Not sure if the issue will still happen or if this should be fixed now.

  • ๐Ÿ‡บ๐Ÿ‡ฆUkraine andriic

    Rerolled the patch from #36 for Durpal 10.2.2.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium kriboogh

    #40 works for us.

    I think config management in drupal should be that, all config is considered English always and if you install a different language, translatable keys in config are then dealt with using normal locale translation by default, or by a language config override if that's present.

Production build 0.69.0 2024