Problem/Motivation

When a module with config is installed on a non-English website 3 things happen:

  1. The config langcode gets rewritten from the shipped English to the site default language
  2. After the module is installed .po files get downloaed/imported for the new extension
  3. Translations get applied to the config (overwriting the active config text in-place for the site default language and adding translation overrides for any other languages that exist on the site).

None of this happens for config in recipe installation. The langcode remains English, .po files for recipes is not a thing that is currently being generated, but they are not attempted to be imported either and the config is not overwritten either.

The result is that if you install Drupal in a foreign language, when you apply a recipe afterwards (even with core only, one of the core recipes!), the installed configuration appears being in the Unkown (en) language. Configuration translations are also not applied of course. You can't even add a configuration translation because you get:

TypeError: Drupal\config_translation\FormElement\ListElement::getTranslationBuild(): Argument #1 ($source_language) must be of type Drupal\Core\Language\LanguageInterface, null given, called in /var/www/html/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php on line 178 en Drupal\config_translation\FormElement\ListElement->getTranslationBuild() (linea 48 de /var/www/html/core/modules/config_translation/src/FormElement/ListElement.php).

But you should not need to add a translation anyway, the config should be rewritten to be in the default language of the site and translated labels should apply to the configuration directly. Plus translation overrides for multilingual sites.

Steps to reproduce

  • Install Drupal in a language other than English.
  • Apply a recipe, for example the media type image.
  • Enable the configuration translation module. Access the page to translate the created media type.

Issue

A config export will show that config installed with Drupal will be in the right language while the config imported by the recipe will be 'English' (which is unknown to the site as a config language on monolingual foreign language sites).

Proposed resolution

  • Fix recipe's config language upon install, setting it to current site default language.
  • Translate default configuration from recipe running it through the locale system and create any needed language overrides.

New RecipeTranslationTest verifies these scenarios that we already have for module install and expect in module install also now work for recipe application:

  • Single foreign language site: When a site uses Spanish as default language and has no other language, recipes with English config get translated to Spanish automatically in place in active config.
  • Multi-foreign language: On a site with Spanish default and Hungarian installed, the recipe config gets Spanish translation in the active config, plus Hungarian translation overrides.
  • English + foreign language: On English sites with Spanish installed, recipe config stays English but Spanish translation overrides get created.
  • Foreign language + English: On Hungarian site with English installed, recipe config gets to become Hungarian while English text moves to an override.

Out of scope: downloading .po files that may be later available related to recipes. That should be a followup and require infrastructure work. This can be done as a bugfix in the meantime.

Remaining tasks

Reviews!

LLM disclosure

At least the tests were built LLM assisted but everything was heavily reviewed manually.

Issue fork drupal-3472317

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

cbccharlie created an issue. See original summary.

cbccharlie’s picture

thejimbirch’s picture

Title: Original language is unknown » Original language is unknown when install a core recipe in a site that does not have the English language
Issue summary: View changes
bsnodgrass’s picture

Project: Recipes Initiative » Drupal core
Component: Code » recipe system
Issue tags: +Recipes initiative
bsnodgrass’s picture

bsnodgrass’s picture

jose reyero’s picture

Just testing - it still happens with latest Drupal core -
and adding related issue, where we are addressing translatability of recipes #3313863: Translation of recipe input and config actions [monolingual]

jose reyero’s picture

Issue summary: View changes
StatusFileSize
new64.51 KB

It looks like the bug is still worse, because when you try to add any translation it produces an error so we are stuck with the untranslatable configuration. I'll update the description accordingly.

jose reyero’s picture

I've done some testing / debugging and this is what is going on:

- The configuration in the recipe is just installed as-is with whatever language code it has in the yml, usually English.
- The process to fix or translate installed configuration is never triggered as it happens usually upon module install. For configuration included in modules the 'langcode' would be set to the current default language. See locale_config_batch_update_default_config_langcodes()
- Also, our configuration is updated by the locale system when any other module is installed, and this includes fixing the language code in the configuration files. But this happens only for configuration that is included with installed components (modules, themes, profiles), not for Recipes. See LocaleConfigManager::getComponentNames() which gets the configuration from default storage (just modules, themes install files).

Quick workaround:
- Manually edit the configuration file - media.type.image - in this case, replace 'langcode: en' by the default language code of the site.
- Re-import / update the configuration file.

Proposed resolution:

I think we should be 'improving' Recipes to behave like other drupal components - modules, themes - including all the post-install hooks, etc, so they could be handled by locale system, but this may be a long term goal. So in the meantime the quick fix would be just setting the configuration language when installing from recipes.

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.

anjali rathod’s picture

Assigned: Unassigned » anjali rathod

anjali rathod’s picture

Assigned: anjali rathod » Unassigned
Status: Active » Needs review
thejimbirch’s picture

Great comments. Makes sense to me. Will ping in the #recipes channel of the Drupal slack to get some more eyes on it. Thanks for the effort!

thejimbirch’s picture

Title: Original language is unknown when install a core recipe in a site that does not have the English language » Original language is unknown when installing a core recipe in a site that does not have the English language
nedjo’s picture

Issue tags: +Needs tests

Thanks for this proposed fix.

We'll need to get test coverage, adding the relevant tag.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update

Thanks for working on this!

This one needs an summary update as the template appears to be incomplete.

Also the MR needs to be changed to main and probably rebased. Depending when it lands it can be backported to 11.x

Thanks

jose reyero changed the visibility of the branch 3472317-original-language-is to hidden.

jose reyero’s picture

Building on the initial patch / idea by @anjali - and already discussed with her - , this is a full patch that takes care of both default language and translations for configuration included in recipes...

## Patch description

This patch extends the scope of the aforementioned issue and fixes two problems:

* Fix recipe's config language upon install, setting it to current default language.
* Translates default configuration from recipe running it through the locale system.

It builds on existing functionality for modules and themes, implementing minimal extensions to make it work for Recipes too.

## Notes

API Extensions:

* Extends existing LocaleConfigManager::updateDefaultConfigLangcodes()
to make it work for limited configuration names or components too.
* New methods for LocaleConfigManager service, get/setDefaultConfigStorage()
to be able to switch the default config storage at runtime and read default configuration from recipes too.

New files / classes:

* core/lib/Drupal/Core/Config/DefaultConfigStorageInterface.php Interface defining methods from LocaleDefaultConfigStorage.
* core/lib/Drupal/Core/Recipe/RecipeDefaultConfigStorage.php Wrapper for LocaleDefaultConfigStorage
implementing DefaultConfigStorageInterface that adds in recipe configuration.

Other changes
* \Drupal\locale\LocaleDefaultConfigStorage implements DefaultConfigStorageInterface - keeps the same methods.
* Adds a step to \Drupal\Core\Recipe\RecipeRunner::processConfig(), only when locale module is enabled that,
right after installing some new configuration takes care of fixing default language and translates the configuarion: processConfigTranslations()

## TO DO / Pending
* Update the issue description, including scope extension.
* Add some tests.

thejimbirch’s picture

In core/lib/Drupal/Core/Config/DefaultConfigStorageInterface.php

/**
 * Provides access to default configuration for locale integration.
 *
 * Allows unified access to default configuration from multiple sources:
 * - Required default configuration (config/install/*)
 * - Optional default configuration (config/optional/*)
 * - Configuration provided by Recipes (config/recipes/*)
 *
 * These sources are considered equal in terms of how locale module interacts
 * with them for translation. Their translatable source strings are exposed
 * for interface translation and participate in remote translation updates.
 */
interface DefaultConfigStorageInterface {

Recipes are not kept in the config folder, so they will never be at config/recipes/*. Most of the time, they are kept at ../recipes/recipe_name/config/*

jose reyero’s picture

Issue summary: View changes
jose reyero’s picture

Agree with @thejimbirch, there are also some other issues with the documentation for this interface and both implementations. So I've done some clean up and now the docblocs look like this - showing all of them together so we can have a complete view:

/**
* Provides access to default configuration for locale integration.
*/
interface DefaultConfigStorageInterface {

/**
* Provides access to default configuration for locale integration.
*
* Allows unified access to default configuration from one of three sources:
* - Required default configuration (config/install/*)
* - Optional default configuration (config/optional/*)
* - Predefined languages mocked as default configuration (list defined in
* LocaleConfigManagerInterface::getStandardLanguageList())
*
* These sources are considered equal in terms of how locale module interacts
* with them for translation. Their translatable source strings are exposed
* for interface translation and participate in remote translation updates.
*/
class LocaleDefaultConfigStorage implements DefaultConfigStorageInterface {

/**
* Provides a wrapper around existing default config storage to add a recipe
* config storage as a configuration source. This allows locale system to read
* configuration from the recipe when determining translatability.
*
* @see \Drupal\locale\LocaleDefaultConfigStorage
*/
class RecipeDefaultConfigStorage implements DefaultConfigStorageInterface {

Other minor changes too (inheritdoc), see https://git.drupalcode.org/issue/drupal-3472317/-/commit/15cdc76ff94a28f...

gábor hojtsy made their first commit to this issue’s fork.

gábor hojtsy’s picture

Title: Original language is unknown when installing a core recipe in a site that does not have the English language » Config language adaptation and translation does not happen at all when config is installed from a recipe
Issue summary: View changes

Significant update to the issue summary to explain the problem.

gábor hojtsy’s picture

Issue summary: View changes

Used Claude to write comprehensive test coverage for this. New RecipeTranslationTest has:

  • Foreign language: When a site uses Spanish as default language, recipes with English config get translated to Spanish automatically in place in active config.
  • Multi-foreign language: On a site with Spanish default and Hungarian installed, the recipe config gets Spanish translation in the active config, plus Hungarian translation overrides.
  • English + foreign language: On English sites with Spanish installed, recipe config stays English but Spanish translation overrides get created.
gábor hojtsy’s picture

Has pretty thorough tests (manually reviewed) and issue summary is updated now.

gábor hojtsy’s picture

Issue summary: View changes
gábor hojtsy’s picture

Title: Config language adaptation and translation does not happen at all when config is installed from a recipe » Config language adaptation and translation does not happen at all when config is applied from a recipe
Issue summary: View changes
gábor hojtsy’s picture

Status: Needs work » Needs review

Add added one more test where English is not the default site language but is present on the site. Now that is verified to get a language override created as well.

gábor hojtsy’s picture

Issue summary: View changes

Moved explanation of all tests to issue summary too.

gábor hojtsy’s picture

Issue summary: View changes
phenaproxima’s picture

Status: Needs review » Needs work

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

alexpott’s picture

Priority: Normal » Major

I think we also need to be mindful of what locale is already doing when a module or theme is installed - see \Drupal\locale\Hook\LocaleExtensionHooks::extensionsInstalled() and work out our this effects everything. I wonder what is happening to the batch that is set there... it's probably being ignored.

alexpott’s picture

So I've confirmed that \Drupal\locale\Hook\LocaleExtensionHooks::extensionsInstalled is triggered when a recipe installs a module which is interesting because of course we're not honouring that batch_set at all. I feel we should be - but that means we need to make it easier to do batches in dr - also I need to find out what occurs when you install a recipe via the UI using project browser.

alexpott’s picture

Of course the project browser gives you a CLI command to install a recipe ATM... at least in the stable version.

gábor hojtsy’s picture

Re the locale batches quoting @alexpott:

I think we also need to be mindful of what locale is already doing when a module or theme is installed - see \Drupal\locale\Hook\LocaleExtensionHooks::extensionsInstalled() and work out our this effects everything. I wonder what is happening to the batch that is set there... it's probably being ignored.

and

So I've confirmed that \Drupal\locale\Hook\LocaleExtensionHooks::extensionsInstalled is triggered when a recipe installs a module which is interesting because of course we're not honouring that batch_set at all. I feel we should be - but that means we need to make it easier to do batches in dr - also I need to find out what occurs when you install a recipe via the UI using project browser.

First there was #3612163: When installing themes on the Appearance page, batches added (eg. by locale) are never executed which you already found. Second, I have ample test coverage for the recipe application scenario in config_language_lock including applying a recipe and how it affects which language is used:

  1. For recipe shipped config the config language directly is used.
  2. For recipe config action created config the request language is used.
  3. For the extensions installed the locale adaptation runs (config gets installed as site default language if it was English originally.

So applying a recipe could end you up with new config in 3 different languages depending on the request language and recipe contents. :D

Docs at https://git.drupalcode.org/project/config_language_lock/-/blob/1.0.x/doc... and https://git.drupalcode.org/project/config_language_lock/-/blob/1.0.x/doc...

alexpott’s picture

@gábor hojtsy yep - I'm pondering whether we should block this work on #3337864: Ensure "Site default language' is used when installing config by any means and is updated correctly to sort out the underlying issue of what language config is created in. And then this issue will sort out the running of LocaleMananger::updateConfigTranslations() and downloading extension translations. One thing we need to think about is that the Recipe ethos is that it should be the same as doing something via the UI. This has a couple of effects on this issue:

  • it means that we need to enable the batch that \Drupal\locale\Hook\LocaleExtensionHooks::extensionsInstalled() sets to somehow be run.
  • it also brings into question whether we should or how we should be running LocaleMananger::updateConfigTranslations() as this wouldn't happen via config created via the UI. But if we don't then recipe config won't get translated.

Here's my thoughts:

  • We should run batches after extensions have been installed - this is what happens in the UI - and recipes should work the same
  • We should run a something after a recipe and any sub recipes are applied to handle translation of any config created outside of regular extension install - note this will mean that extension provided config and recipe supplied config work a bit different. But this has to be true. Locale relies on the fact that that it can access config in the extension directories after install and that is not true for recipes which are ephemeral.

In order to do this where going to need to modify the recipe runner extensively and potentially think about how vendor/bin/dr runs batches.

gábor hojtsy’s picture

In config_language_lock I use RecipeAppliedEvents, see https://git.drupalcode.org/project/config_language_lock/-/blob/1.0.x/src... to react to recipes being applied. While extension installs and config actions are resolved by that module via config save being adapted, the config import from recipes still need that to change the language. That module does not solve the lack of locale .po import batch on recipe install, although it could if we widen the scope a bit.

rajab natshah’s picture

Facing the same issue :)

alexpott’s picture