feat: add language_hierarchy for multilingual translation fallback - #76
Conversation
Add the language_hierarchy module to the multilingual recipe so that untranslated content falls back through a configured language chain instead of showing empty listings or picking an arbitrary translation. All languages fall back to English by default; nl-be (Vlaams) falls back to Dutch first. The en-gb footer translation is removed since it is identical to the English original and now falls back naturally. Views with interface-language filters (blog, case_studies, news) are automatically swapped to the hierarchy fallback filter on install via hook_install in dxpr_cms_multilingual_content. Also adds nl-be language entity config with label "Vlaams", removes obsolete translated menu link content for deleted pages, and adds the nl-be homepage translation.
The recipe config action `language.entity.*` with setThirdPartySettings does not apply to language entities created by the installer, because the multilingual form batch runs after recipe application. Move fallback chain configuration into hook_install (for languages existing at module install time) and hook_configurable_language_insert (for languages created afterwards by the installer batch).
Replace em dashes with colons/semicolons in skill markdown files and fix excess spaces inside empty braces in recipe YAML configs.
jjroelofs
left a comment
There was a problem hiding this comment.
Thanks for pushing this, the direction makes sense, but I found two correctness issues that can keep the fallback behavior from working reliably.
The main blocker is that nl-be is hard-wired to fall back to nl even when Dutch is not installed, which leaves the Views fallback chain without English. I also think the Views rewrite needs to run somewhere more durable than this module's one-time install hook, because optional recipes/views installed after multilingual will keep the old language filter.
Checks run locally: git diff --check, php -l on the changed PHP files, and YAML parsing of changed YAML files with Ruby. I could not run a Drupal bootstrap/drush validation because this machine's CLI PHP is 8.3.22 and the checkout's Composer platform check requires PHP >= 8.4.
| */ | ||
| function _dxpr_cms_multilingual_content_configure_fallback_chains(): void { | ||
| $overrides = [ | ||
| 'nl-be' => 'nl', |
There was a problem hiding this comment.
nl-be is now configured to fall back to nl unconditionally, but this recipe does not guarantee that Dutch is installed. If a site has nl-be without nl, language_hierarchy's query fallback candidates become nl-be, nl, and und, so the new Views filter will not include English content at all. That contradicts the PR summary's nl-be -> nl -> en behavior and leaves /nl-be/... listings empty unless Dutch was also selected. Please either install/configure nl as part of this chain, or choose the default language when nl is absent and update nl-be if Dutch is added later. The same hard-coded map also appears in dxpr_cms_multilingual_content.module and the new language.entity.nl-be.yml config.
| /** | ||
| * Swaps standard language filters in Views with language_hierarchy fallback. | ||
| */ | ||
| function _dxpr_cms_multilingual_content_swap_views_filters(): void { |
There was a problem hiding this comment.
Doing the Views rewrite only from hook_install() means it only sees views that already exist at the exact moment dxpr_cms_multilingual_content is installed. Optional recipes can be applied later, or in a different order, so views such as News/Case Studies can still be imported with the original langcode interface-language filter and never get the fallback filter. That leaves the very listing pages this PR targets without fallback. This needs to be expressed as recipe config actions for the known views, or handled when relevant view config is inserted/updated, or otherwise made order-independent.
1. nl-be fallback now checks if nl is actually installed before using it; falls back to the site default language when nl is absent. When nl is added later, nl-be is updated automatically. 2. Added hook_view_insert() so views imported after module install (e.g. from recipes applied in a different order) also get the language_hierarchy fallback filter swap. 3. Removed hardcoded third_party_settings from language.entity.nl-be.yml; the hook handles fallback configuration dynamically. 4. Consolidated duplicated filter-swap logic into a shared helper in the .module file, called by both hook_install and hook_view_insert.
Summary
language_hierarchycontrib module to the multilingual recipe, enabling per-language fallback chains for untranslated contentnl-be(Vlaams) falls back to Dutch first, then Englishnl-belanguage entity config with label "Vlaams"Test plan
/nl/blog,/de/case-studies,/ar/newsshow English content (fallback) instead of empty listings/nl-bepages show Dutch content for entities without nl-be translations (footer, menu links)/en-gbfooter falls back to English without a separate en-gb translation