Configuration langcode is forced to site default language

Created on 10 June 2020, over 4 years ago
Updated 6 August 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 2 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

Merge Requests

Comments & Activities

Not all content is available!

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

Production build 0.71.5 2024