Domain Config Language¶
The Domain Config Language module adds language-aware per-domain
configuration overrides on top of Domain Config.
Enable it on multilingual sites where you need overrides that vary by both
domain and language (e.g. a different site name on one.example.com in
English versus French).
It is the natural companion to Domain Config: by itself, Domain Config
provides one override layer per domain; with Domain Config Language you also
get a second layer keyed by (domain, langcode).
When to enable it¶
- You have the
languagemodule enabled. - You want different configuration values per domain and per language.
If you have a monolingual site, do not install this module — Domain Config
on its own already covers domain-only overrides without pulling the
language module into your install.
What it provides¶
Drupal\domain_config_language\Config\DomainLanguageConfigFactoryOverride— theconfig.factory.overrideservice registered asdomain.language.config_factory_override(priority-252).Drupal\domain_config_language\Config\DomainLanguageConfigOverride— the per-domain, per-language editable override object.Drupal\domain_config_language\DomainConfigLanguageManager— a decorator on the corelanguage_managerservice that resolves config overrides through the per-domain language configuration factory at runtime.
These classes are marked @internal. The stable contract is the service
ID domain.language.config_factory_override.
Storage layout¶
Overrides are stored as Drupal config collections named:
domain.{domain_id}.language.{langcode}
The collection name is built by
Drupal\domain_config_language\Config\DomainLanguageConfigCollectionUtils::createDomainLanguageConfigCollectionName().
Within a collection, the configuration object keeps its original name --
the site name override for one_example_com in French is stored as
system.site inside the domain.one_example_com.language.fr collection.
This format predates the module split and is unchanged. Existing 3.x sites
upgrade transparently — domain_config_update_10002() auto-installs this
submodule when the language module is already enabled.
How it works at runtime¶
Override resolution¶
This module registers a second config.factory.override service on top of
the one provided by Domain Config:
domain.config_factory_override(priority -253, from Domain Config) -- loads the domain override from thedomain.{domain_id}collection.domain.language.config_factory_override(priority -252, from this module) -- loads the domain+language override from thedomain.{domain_id}.language.{lang_code}collection.
Higher priority numbers run earlier; the language-aware override is applied after the per-domain one, so it sits on top of the cascade:
Base config (default collection)
↓ merged with
Domain override (domain.{domain_id} collection)
↓ merged with
Domain+language override (domain.{domain_id}.language.{lang_code} collection)
= Final runtime config
Example with system.site on domain two_example_com, language es:
# Base config (default collection):
system.site:
name: "My Site"
# Domain override (domain.two_example_com collection):
system.site:
name: "Two" # overrides "My Site" → "Two"
# Domain+language override (domain.two_example_com.language.es collection):
system.site:
name: "Dos" # overrides "Two" → "Dos"
# Final result at runtime: name = "Dos"
Caching¶
The language-aware override service provides a cache suffix that
combines the current domain ID with the language code, so a config object
cached for (two_example_com, es) is not served to (two_example_com, en).
The cache metadata adds languages:language_interface to the existing
domain cache context, so rendered output that depends on per-language
overrides is properly varied.
Config export and import¶
Drupal's FileStorage converts dots in collection names to directory
separators. On top of the per-domain export structure described in the
Domain Config documentation,
this module adds a language/{langcode}/ subdirectory under each domain
folder:
config/sync/
system.site.yml # Base config
domain/
one_example_com/
system.site.yml # Domain override
language/
fr/
system.site.yml # Domain+language override
two_example_com/
system.site.yml
language/
en/
system.site.yml
es/
system.site.yml
Modules can ship default domain+language overrides using the same convention
in their config/install/ directory:
mymodule/config/install/
domain/
one_example_com/
language/
fr/
system.site.yml
two_example_com/
language/
en/
system.site.yml
When a new domain entity is created or this module is installed, Drupal's
ConfigInstallerInterface::installCollectionDefaultConfig() picks these up
into the matching domain.{domain_id}.language.{langcode} collection.
Migration from 2.x to 3.x¶
In Domain 2.x, language-aware overrides were stored as separate configuration objects in the default collection alongside the per-domain ones, using a naming convention with the language code embedded in the flat name:
domain.config.{domain_id}.{langcode}.{config_name}
For example, a French-specific override of the site name on
one_example_com:
domain.config.one_example_com.fr.system.site
Limitation: language-specific overrides had to be handled separately from
Drupal's own LanguageConfigOverride system; they did not flow through any
standard config-override pipeline.
The 3.x format unifies both kinds of overrides under config collections (see
Storage layout above for the per-language collection name). The migration
to that format is shipped as domain_config_language_install() -- it runs
automatically the first time this module is installed (which on upgrading
sites is triggered by domain_config_update_10002()).
The migration is performed by the
Drupal\domain_config_language\Service\DomainConfigMigration service and
covers both the per-domain overrides (no langcode) and the per-language
ones in a single pass:
- Scans legacy config objects -- finds all
domain.config.{domain_id}.*entries in the default collection. - Parses each legacy name -- extracts the domain ID, optional language
code, and config name using the pattern:
/^domain\.config\.{domain_id}(?:\.([a-z]{2}))?\.([^.]+\.[^.]+)$/ - Writes to collections -- copies the data into the appropriate
domain.{domain_id}(when no langcode) ordomain.{domain_id}.language.{lang_code}(when a langcode is captured) collection. - Updates the registry -- if Domain Config UI is installed, updates the
overridable_configurationssetting indomain_config_ui.settings. - Cleans up -- deletes the legacy
domain.config.*objects from the default collection.
The migration is idempotent: on a fresh install with no legacy data it is a no-op. If any domain fails to migrate, exceptions are collected per-domain and reported in the migration result.
Services¶
| Service | Class | Role |
|---|---|---|
domain.language.config_factory_override |
DomainLanguageConfigFactoryOverride |
Domain+language config overrides (priority -252) |
domain.language_manager |
DomainConfigLanguageManager |
Decorates language_manager to integrate domain language overrides |
domain_config_language.config_migration |
DomainConfigMigration |
2.x → 3.x migration service (internal) |
Relationship to Domain Config UI¶
If you also enable Domain Config UI, install Domain Config Language UI so the admin overview page shows per-language overrides and language-aware overrides are cleaned up alongside their base override on delete.