Problem/Motivation
When a module with config is installed on a non-English website 3 things happen:
- The config langcode gets rewritten from the shipped English to the site default language
- After the module is installed .po files get downloaed/imported for the new extension
- 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.

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.
| Comment | File | Size | Author |
|---|---|---|---|
| #8 | Screenshot from 2025-10-30 19-59-48.png | 64.51 KB | jose reyero |
| capture.png | 7.26 KB | cbccharlie |
Issue fork drupal-3472317
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
Comment #2
cbccharlie commentedComment #3
thejimbirch commentedComment #4
bsnodgrass commentedmoved to Drupal Core, per https://www.drupal.org/project/distributions_recipes/issues/3513044
Comment #5
bsnodgrass commentedmoved to Drupal Core, per https://www.drupal.org/project/distributions_recipes/issues/3513044
Comment #6
bsnodgrass commentedmoved to Drupal Core, per https://www.drupal.org/project/distributions_recipes/issues/3513044
Comment #7
jose reyero commentedJust 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]
Comment #8
jose reyero commentedIt 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.
Comment #9
jose reyero commentedI'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.
Comment #11
anjali rathodComment #13
anjali rathodComment #14
thejimbirch commentedGreat 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!
Comment #15
thejimbirch commentedComment #16
nedjoThanks for this proposed fix.
We'll need to get test coverage, adding the relevant tag.
Comment #17
smustgrave commentedThanks 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
Comment #19
jose reyero commentedBuilding 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.
Comment #20
thejimbirch commentedIn
core/lib/Drupal/Core/Config/DefaultConfigStorageInterface.phpRecipes 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/*Comment #22
jose reyero commentedComment #23
jose reyero commentedAgree 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:
Other minor changes too (inheritdoc), see https://git.drupalcode.org/issue/drupal-3472317/-/commit/15cdc76ff94a28f...
Comment #25
gábor hojtsySignificant update to the issue summary to explain the problem.
Comment #26
gábor hojtsyUsed Claude to write comprehensive test coverage for this. New
RecipeTranslationTesthas:Comment #27
gábor hojtsyHas pretty thorough tests (manually reviewed) and issue summary is updated now.
Comment #28
gábor hojtsyComment #29
gábor hojtsyComment #30
gábor hojtsyAdd 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.
Comment #31
gábor hojtsyMoved explanation of all tests to issue summary too.
Comment #32
gábor hojtsyComment #33
phenaproximaComment #35
alexpottI 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.
Comment #36
alexpottSo I've confirmed that
\Drupal\locale\Hook\LocaleExtensionHooks::extensionsInstalledis 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 indr- also I need to find out what occurs when you install a recipe via the UI using project browser.Comment #37
alexpottOf course the project browser gives you a CLI command to install a recipe ATM... at least in the stable version.
Comment #38
gábor hojtsyRe the locale batches quoting @alexpott:
and
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:
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...
Comment #39
alexpott@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:
Here's my thoughts:
In order to do this where going to need to modify the recipe runner extensively and potentially think about how
vendor/bin/drruns batches.Comment #40
gábor hojtsyIn 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.
Comment #41
rajab natshahFacing the same issue :)
Comment #42
alexpottI think this might be fixed now that #3613607: Add RecipeRunner::isApplying() to determine if a recipe is being applied, without confusing it with a config sync is merged.