Important: Strict language fallback for selected profiles 

Description 

When profiles are selected explicitly (by uid) in the List of profiles field of the Persons List or Persons List and Detail content element, a site language configured with fallbackType: strict does not hide profiles that are not translated into the requested language. Such profiles are rendered in their default language instead of being removed, even when the plugin option Fallback to default language for non translated profiles is not enabled.

This is not a defect of EXT:academic_persons. The extension already resolves the correct language overlay type from the site configuration and only relies on Extbase persistence to apply it. The behaviour is caused by a long-standing Extbase regression that ignored the resolved language overlay type and always overlaid single records with OVERLAYS_MIXED , so untranslated records were kept.

Core references (issue and both patches):

  • Forge issue #88886: "DataMapper: Consider languageOverlayMode hideNonTranslated ..."
  • Gerrit change 66694: "[BUGFIX] Respect language overlay type in Extbase" (TYPO3 main line)
  • Gerrit change 94935: the TYPO3 14.3 backport (same Change-Id)

The fix is released with TYPO3 v14.3.6 and newer. It is not part of TYPO3 v12 or v13 and, being a behavioural change, is not backported to those LTS lines. This version of the extension supports TYPO3 v12 and v13, so none of its supported core versions contain the fix out of the box.

Impact 

On the supported TYPO3 v12 and v13 core versions the affected Extbase code still overlays with OVERLAYS_MIXED , so untranslated selected profiles keep being shown in their default language when the site language uses fallbackType: strict and the plugin fallback option is not enabled.

Affected Installations 

Installations on TYPO3 v12 or v13 that use selected profiles in a list plugin with a site language configured as fallbackType: strict and expect untranslated profiles to be hidden.

Solution 

The corrected behaviour ships with TYPO3 v14.3.6 and newer, which this version of the extension does not support.

If the correct behaviour is required on TYPO3 v12 or v13, apply the core change as a composer patch against typo3/cms-extbase until the installation is upgraded to a core version that contains the fix. Cleaned patches (narrowed to typo3/cms-extbase , derived from Gerrit changes 66694 / 94935) are shipped with this extension and were verified to make the strict-fallback behaviour correct on the respective core version:

TYPO3 v13.4 patch 

Documentation/Patches/extbase-88886-respect-language-overlay-type-v13.patch

extbase-88886-respect-language-overlay-type-v13.patch (TYPO3 v13.4)
diff -ruN a/Classes/Persistence/Generic/Backend.php b/Classes/Persistence/Generic/Backend.php
--- a/Classes/Persistence/Generic/Backend.php
+++ b/Classes/Persistence/Generic/Backend.php
@@ -148,11 +148,14 @@
         // This allows to fetch IDs for languages for default language AND language IDs
         // This is especially important when using the PropertyMapper of the Extbase MVC part to get
         // an object of the translated version of the incoming ID of a record.
+        // "Free" mode (OVERLAYS_OFF) is mapped to OVERLAYS_MIXED - overlays need to be enabled for the
+        // identity lookup, but hiding untranslated records is not a configured intent in free mode.
+        // This is consistent with the same handling for related objects in DataMapper->getPreparedQuery().
         $languageAspect = $query->getQuerySettings()->getLanguageAspect();
         $languageAspect = new LanguageAspect(
             $languageAspect->getId(),
             $languageAspect->getContentId(),
-            $languageAspect->getOverlayType() === LanguageAspect::OVERLAYS_OFF ? LanguageAspect::OVERLAYS_ON_WITH_FLOATING : $languageAspect->getOverlayType(),
+            $languageAspect->getOverlayType() === LanguageAspect::OVERLAYS_OFF ? LanguageAspect::OVERLAYS_MIXED : $languageAspect->getOverlayType(),
             $languageAspect->getFallbackChain()
         );
         $query->getQuerySettings()->setLanguageAspect($languageAspect);
diff -ruN a/Classes/Persistence/Generic/Storage/Typo3DbBackend.php b/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
--- a/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
+++ b/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
@@ -580,9 +580,16 @@
                     $row['uid'] = $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']];
                     $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] = 0;
                 }
-                // Currently this needs to return the default record (OVERLAYS_MIXED) if no translation is found
-                //however this is a hack and should actually use the overlay functionality as given in the original LanguageAspect.
-                $customLanguageAspect = new LanguageAspect($languageUid, $languageUid, LanguageAspect::OVERLAYS_MIXED, $languageAspect->getFallbackChain());
+                // The overlay type (and fallback chain) of the language aspect is respected, so translation
+                // behavior is consistent with the regular page / content rendering. The content language
+                // however may have been adjusted above to the language of the actually fetched record
+                // (see Note #1 and the respectSysLanguage handling), so a custom aspect is passed here.
+                $customLanguageAspect = new LanguageAspect(
+                    $languageAspect->getId(),
+                    $languageUid,
+                    $languageAspect->getOverlayType(),
+                    $languageAspect->getFallbackChain()
+                );
                 $row = $pageRepository->getLanguageOverlay($tableName, $row, $customLanguageAspect);
             }
         } elseif (is_array($row)) {
Copied!

TYPO3 v12.4 patch 

Documentation/Patches/extbase-88886-respect-language-overlay-type-v12.patch

extbase-88886-respect-language-overlay-type-v12.patch (TYPO3 v12.4)
diff -ruN a/Classes/Persistence/Generic/Backend.php b/Classes/Persistence/Generic/Backend.php
--- a/Classes/Persistence/Generic/Backend.php
+++ b/Classes/Persistence/Generic/Backend.php
@@ -203,11 +203,14 @@
         // This allows to fetch IDs for languages for default language AND language IDs
         // This is especially important when using the PropertyMapper of the Extbase MVC part to get
         // an object of the translated version of the incoming ID of a record.
+        // "Free" mode (OVERLAYS_OFF) is mapped to OVERLAYS_MIXED - overlays need to be enabled for the
+        // identity lookup, but hiding untranslated records is not a configured intent in free mode.
+        // This is consistent with the same handling for related objects in DataMapper->getPreparedQuery().
         $languageAspect = $query->getQuerySettings()->getLanguageAspect();
         $languageAspect = new LanguageAspect(
             $languageAspect->getId(),
             $languageAspect->getContentId(),
-            $languageAspect->getOverlayType() === LanguageAspect::OVERLAYS_OFF ? LanguageAspect::OVERLAYS_ON_WITH_FLOATING : $languageAspect->getOverlayType()
+            $languageAspect->getOverlayType() === LanguageAspect::OVERLAYS_OFF ? LanguageAspect::OVERLAYS_MIXED : $languageAspect->getOverlayType()
         );
         $query->getQuerySettings()->setLanguageAspect($languageAspect);
         return $query->matching($query->equals('uid', $identifier))->execute()->getFirst();
diff -ruN a/Classes/Persistence/Generic/Storage/Typo3DbBackend.php b/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
--- a/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
+++ b/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
@@ -535,9 +535,16 @@
                     $row['uid'] = $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']];
                     $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] = 0;
                 }
-                // Currently this needs to return the default record (OVERLAYS_MIXED) if no translation is found
-                //however this is a hack and should actually use the overlay functionality as given in the original LanguageAspect.
-                $customLanguageAspect = new LanguageAspect($languageUid, $languageUid, LanguageAspect::OVERLAYS_MIXED, $languageAspect->getFallbackChain());
+                // The overlay type (and fallback chain) of the language aspect is respected, so translation
+                // behavior is consistent with the regular page / content rendering. The content language
+                // however may have been adjusted above to the language of the actually fetched record
+                // (see Note #1 and the respectSysLanguage handling), so a custom aspect is passed here.
+                $customLanguageAspect = new LanguageAspect(
+                    $languageAspect->getId(),
+                    $languageUid,
+                    $languageAspect->getOverlayType(),
+                    $languageAspect->getFallbackChain()
+                );
                 $row = $pageRepository->getLanguageOverlay($tableName, $row, $customLanguageAspect);
             }
         } elseif (is_array($row)) {
Copied!

Apply the matching patch with the composer plugin cweagans/composer-patches (see its README for installation and usage). Copy the patch into the project (for example into a patches/ directory) and reference it:

{
    "require": {
        "cweagans/composer-patches": "^1.7"
    },
    "extra": {
        "patches": {
            "typo3/cms-extbase": {
                "Respect language overlay type in Extbase (forge #88886, review 66694)": "patches/extbase-88886-respect-language-overlay-type-v13.patch"
            }
        }
    }
}
Copied!

Both patches touch only typo3/cms-extbase (Classes/Persistence/Generic/Storage/Typo3DbBackend.php and Classes/Persistence/Generic/Backend.php). EXT:academic_persons itself needs no change. Use the patch that matches the installed core version, the composer example above names the one for TYPO3 v13.4.