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.

Issue fork drupal-3150540

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Rade created an issue. See original summary.

rade’s picture

Issue summary: View changes

Version: 9.0.x-dev » 9.1.x-dev

Drupal 9.0.10 was released on December 3, 2020 and is the final full bugfix release for the Drupal 9.0.x series. Drupal 9.0.x will not receive any further development aside from security fixes. Sites should update to Drupal 9.1.0 to continue receiving regular bugfixes.

Drupal-9-only bug reports should be targeted for the 9.1.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.2.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

rar9’s picture

in this helping for my issue that was closed?
https://www.drupal.org/project/drupal/issues/3161643#comment-14110368

johnwebdev’s picture

Seems like a great solution for your use case. I've had the same use case as you did before, and I actually wish that I would come up with something like that back then.

It would be interesting to try split all translatable strings directly into language/xx folder as default, and only keep "language neutral" configuration in the config/sync directory.

ckaotik’s picture

function locale_system_set_config_langcodes() {
  // Need to rewrite some default configuration language codes if the default
  // site language is not English.
  $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
  if ($default_langcode != 'en') {
    // ...

For the locale_system_set_config_langcodes function, can we assume that this langcode change is only necessary/desirable on non-English monolingual Drupal sites? Maybe also on sites that do not have English installed? Or on sites that do not use config_translation?

  • If the config_language module is installed, locale shouldn't mess with configuration at all. If the user requires translation, it will be imported as a translation override (e.g. from config/sync/language/de), and most modules will ship with English configuration.
    What happens to modules that ship non-English default configuration (keep as is/pretend it's English/transform between languages)?
  • If the site has English installed, do we want to have en overrides?
    Personally, I'd much prefer the base configuration being in English, even if the site default is another language. Primarily because that's the default language for un-specified install configuration items.
  • If the site has only one language, and it's not English, one could argue. But since Core has previously been changing the langcode, we should probably stick to this behavior.

Ideally, we would either ensure to always have English default configuration, or ensure that non-English default configuration is retained as such (optionally with en language overrides). The current handling is doing neither on sites with another default language.

Version: 9.1.x-dev » 9.3.x-dev

Drupal 9.1.10 (June 4, 2021) and Drupal 9.2.10 (November 24, 2021) were the last bugfix releases of those minor version series. Drupal 9 bug reports should be targeted for the 9.3.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

norman.lol’s picture

Yeah this behaviour can really create quite a mess. I wish default config always is EN, same as translatable strings.

Until then you'd probably need to ensure that default config simply is in the same language as the default language. Which makes life quite awful for editors though, because they might often see strings in the backend in a language they can't read.

bramvandenbulcke’s picture

I agree it's a mess right now.

For your information: I live in Belgium and we create lots of multilingual websites. We created a starter installation in English. We prefer to develop in English.

For a multilingual website there is not really a problem. We can set default language as English and disable English with the disable_language module.

But for websites with one (non-English) language it gets complicated. We want to roll out these websites without a path prefix for this one language. Disabling the path prefix is only possible on the default language, so the default language has to be non-English in that case. The moment we switch this setting all config languages change to the other language. Also, disabling the URL prefix globally (under Detection Method) doesn't seem to work and looks like a dangerous setting to disable.

So, we would also prefer to have English as the default config language!

ericdsd’s picture

That's why i think, that for non english sites, config should probably be considered as english config by default and might generate translation in other languages even if only one language (not english). So for exemple a german site should have config considered as english one and have a german translation generated.

pasqualle’s picture

Version: 9.3.x-dev » 9.5.x-dev
Category: Support request » Feature request
Status: Active » Needs work

I think patching core would be the preferred solution, as the current core behavior is not suitable for international teams.

The current patch is not acceptable for core, as it breaks the current core behavior. Existing sites applying this patch might get even messier.
The default language used for configuration entities needs to be configurable.

pasqualle’s picture

eiriksm’s picture

Status: Needs work » Needs review
StatusFileSize
new846 bytes

Here is the start of a patch that is backwards compatible, but makes it possible to disable what's in this function completely. Could this be acceptable as a first take?

Still needs tests, default config, schema updates and so on, but as a POC it should be possible to discuss.

eiriksm’s picture

Hm, I was writing it a bit quick I see. There is no default value param to the config get function. Not backwards compatible then... But now I have to run, so I will have to revisit

Status: Needs review » Needs work

The last submitted patch, 13: 3150540.patch, failed testing. View results

eiriksm’s picture

Status: Needs work » Needs review
StatusFileSize
new2.08 KB

I am glad to see we have tests that assume the default would be to have this option enabled. So here is a patch I think should pass tests (and as a consequence, hopefully be totally backwards compatible)

Status: Needs review » Needs work

The last submitted patch, 16: 3150540-16.patch, failed testing. View results

geek-merlin’s picture

@eiriksm Great you took a stab at this!

Code-wise it makes sense to me. Did not look into the failing tests though.

hudri’s picture

@bramvandenbulcke, #9

The current workaround here is to set the default site language to english, but the default language detection to your_lang. This way config should not get polluted, but visitors of / should still see the frontpage (and all sub pages) in your_lang language, while all english pages need an explicit /en prefix.

This is taken from https://www.drupal.org/project/drupal/issues/2806009#comment-14006988

eiriksm’s picture

Status: Needs work » Needs review
StatusFileSize
new2.1 KB

Updated patch that passes the last test at least locally. Let's get it green and go from there

eiriksm’s picture

StatusFileSize
new2.09 KB
new5.62 KB

And here is one with a test, and a test only patch. I also added the setting to the locale settings form. The text in the config form is, shall we say, not ideal. Would love to hear from someone with better English and/or better UX eye than me about that text.

eiriksm’s picture

StatusFileSize
new2.09 KB
new5.62 KB

Trying again... Now hopefully without cspell error

The last submitted patch, 22: 3150540-21-test-only.patch, failed testing. View results

eiriksm’s picture

StatusFileSize
new4.55 KB
new5.62 KB
eiriksm’s picture

The last patch was not the best test-only patch. It failed for other reasons. Included here is a test only patch that has everything of the patch, except the logic for doing "the stuff".

The last submitted patch, 24: 3150540-24-test-only.patch, failed testing. View results

bramvandenbulcke’s picture

@hudri, indeed this setup has some advantages over my current setup. I followed the comment from Sutharsan in the same thread you mention: https://www.drupal.org/project/drupal/issues/2806009#comment-14009513.

Steps to take:

  • Enable the Language module under Multilingual
  • Add Language: in my case Dutch
  • Default Language: English
  • Detection and Selection: everything off except Selected language = Dutch

The site is in this case in Dutch on the frontend and English in the backend. Only problem with this setup is that the backend is in English for both admins and editors. Some editors won't bother but others will prefer a backend in their native language.

michel.g’s picture

The latest patch is missing a default value set for the checkbox on admin/config/regional/translate/settings

michel.g’s picture

StatusFileSize
new3.61 KB

Attached the updated patch with the default value set

michel.g’s picture

StatusFileSize
new3.6 KB

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs tests, +Needs upgrade path

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.

antonín slejška’s picture

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

ericdsd’s picture

This is quite logical as https://www.drupal.org/project/drupal/issues/2806009 has been fixed and committed in 9.5.9 release, i didn't test it yet but it should address this issue too.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

kalvis’s picture

StatusFileSize
new5.86 KB
new4.12 KB

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 :)

arnalyse’s picture

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.

edurenye’s picture

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.

edurenye’s picture

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.

andriic’s picture

StatusFileSize
new3.62 KB
new1.32 KB

Rerolled the patch from #36 for Durpal 10.2.2.

kriboogh’s picture

#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.

edurenye’s picture

StatusFileSize
new3.67 KB

Rerolled the patch for Drupal 10.3.0.

kriboogh’s picture

StatusFileSize
new3.9 KB

Created MR for 11.x based on patch from #42.
Added patch of MR for use in composer.
Applies to 11.x and 10.3.x.

kriboogh’s picture

StatusFileSize
new3.9 KB

Fixed a spelling error so tests could run.

kuldeepbarot’s picture

Version: 11.x-dev » 10.4.x-dev
StatusFileSize
new4.14 KB

Rerolled the patch for Drupal 10.4.6.

mscieszka made their first commit to this issue’s fork.

mscieszka’s picture

StatusFileSize
new3.49 KB

Patch for Drupal 11.2.2

ericdsd’s picture

Note that when applying #46 you need to save the config if you want to have "Update default configuration when new modules or themes are installed." option disabled (at admin/config/regional/translate/settings) as if it's not saved the value will fallback to true and won't have any effect.
If properly saved it works over 10.4.6.

quietone’s picture

Version: 10.4.x-dev » 11.x-dev

Hi, in Drupal core changes are made on on 11.x (our main development branch) first, and are then back ported as needed according to the Core change policies. Thanks.

oily’s picture

There were a lot of broken tests in the pipeline but did not look related. Re-ran pipeline and it is green.

taran2l made their first commit to this issue’s fork.

oily’s picture

Started code review. Change to the form field description.

oily’s picture

It looks like the test coverage should go inside the Kernel test LocaleBuildTest.php.

anybody’s picture

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

ericdsd’s picture

Patch #46 still applies on 10.5.8

Also needs to save /admin/config/regional/translate/settings as newly created option "Update default configuration when new modules or themes are installed." must be explicitely saved to false (as it defaults to true until first saved).