diff --git a/src/CoreBundle/EventListener/DcGeneral/Table/DcaSetting/FallbackLanguageHintListener.php b/src/CoreBundle/EventListener/DcGeneral/Table/DcaSetting/FallbackLanguageHintListener.php
new file mode 100644
index 000000000..3761ef5ab
--- /dev/null
+++ b/src/CoreBundle/EventListener/DcGeneral/Table/DcaSetting/FallbackLanguageHintListener.php
@@ -0,0 +1,145 @@
+
+ * @copyright 2012-2026 The MetaModels team.
+ * @license https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later
+ * @filesource
+ */
+
+declare(strict_types=1);
+
+namespace MetaModels\CoreBundle\EventListener\DcGeneral\Table\DcaSetting;
+
+use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
+use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\ManipulateWidgetEvent;
+use ContaoCommunityAlliance\DcGeneral\Data\MultiLanguageDataProviderInterface;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
+use MetaModels\Attribute\ITranslated;
+use MetaModels\IFactory;
+use MetaModels\ITranslatedMetaModel;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+/**
+ * Adds a label hint to every translated-attribute widget that implements
+ * {@see ITranslated}, indicating whether the displayed value is an
+ * own translation ("[Tx]", green) or comes from the fallback language ("[Fb]", yellow).
+ * Works independently of any machine-translation provider.
+ *
+ * FIXME: AI Bullshit! should never be the case! If it is, the attribute is WRONG!
+ * Attributes opt in by implementing {@see ITranslationHintSupport}. Attributes
+ * that only implement the base {@see \MetaModels\Attribute\ITranslated} (e.g. TranslatedSelect,
+ * TranslatedTags) are skipped because their getTranslatedDataFor() may silently return
+ * fallback data, making a reliable distinction impossible.
+ */
+final class FallbackLanguageHintListener
+{
+ public function __construct(
+ private readonly RequestScopeDeterminator $scopeDeterminator,
+ private readonly IFactory $factory,
+ private readonly TranslatorInterface $translator,
+ ) {
+ }
+
+ public function handle(ManipulateWidgetEvent $event): void
+ {
+ if (!$this->scopeDeterminator->currentScopeIsBackend()) {
+ return;
+ }
+
+ $context = $this->resolveContext($event);
+ if (null === $context) {
+ return;
+ }
+
+ [$attribute, $targetLang, $sourceLang] = $context;
+
+ $fromFallback = $this->isFromFallback($event->getModel()->getId(), $attribute, $targetLang);
+ $event->getWidget()->xlabel .= $this->buildHint($fromFallback, $sourceLang, $targetLang);
+ }
+
+ /** @return array{0: ITranslated, 1: string, 2: string}|null */
+ private function resolveContext(ManipulateWidgetEvent $event): ?array
+ {
+ $environment = $event->getEnvironment();
+ $dataDefinition = $environment->getDataDefinition();
+ assert($dataDefinition instanceof ContainerInterface);
+
+ $tableName = $dataDefinition->getName();
+ if (!\str_starts_with($tableName, 'mm_')) {
+ return null;
+ }
+
+ $metaModel = $this->factory->getMetaModel($tableName);
+ if (!($metaModel instanceof ITranslatedMetaModel)) {
+ return null;
+ }
+
+ $dataProvider = $environment->getDataProvider($event->getModel()->getProviderName());
+ if (!($dataProvider instanceof MultiLanguageDataProviderInterface)) {
+ return null;
+ }
+
+ $targetLang = $dataProvider->getCurrentLanguage();
+ $sourceLang = $metaModel->getMainLanguage();
+ if ($targetLang === $sourceLang) {
+ return null;
+ }
+
+ $attribute = $metaModel->getAttribute($event->getProperty()->getName());
+ if (!($attribute instanceof ITranslated)) {
+ return null;
+ }
+
+ return [$attribute, $targetLang, $sourceLang];
+ }
+
+ private function isFromFallback(mixed $itemId, ITranslated $attribute, string $targetLang): bool
+ {
+ if (null === $itemId) {
+ return true;
+ }
+
+ $data = $attribute->getTranslatedDataFor([(string) $itemId], $targetLang);
+
+ return !\array_key_exists((string) $itemId, $data);
+ }
+
+ private function buildHint(bool $fromFallback, string $sourceLang, string $targetLang): string
+ {
+ if ($fromFallback) {
+ $label = $this->translator->trans('fallback_language_hint.label_fallback', [], 'metamodels_default');
+ $title = $this->translator->trans(
+ 'fallback_language_hint.title_fallback',
+ ['%source%' => $sourceLang, '%target%' => $targetLang],
+ 'metamodels_default',
+ );
+ $cssClass = 'mm-lang-hint mm-lang-hint--fallback';
+ } else {
+ $label = $this->translator->trans('fallback_language_hint.label_translated', [], 'metamodels_default');
+ $title = $this->translator->trans(
+ 'fallback_language_hint.title_translated',
+ ['%target%' => $targetLang],
+ 'metamodels_default',
+ );
+ $cssClass = 'mm-lang-hint mm-lang-hint--translated';
+ }
+
+ return \sprintf(
+ '%s',
+ $cssClass,
+ \htmlspecialchars($title, \ENT_QUOTES),
+ \htmlspecialchars($label, \ENT_QUOTES),
+ );
+ }
+}
diff --git a/src/CoreBundle/Resources/config/dc-general/table/tl_dcasetting.yml b/src/CoreBundle/Resources/config/dc-general/table/tl_dcasetting.yml
index 88c56677d..f97a6cbc2 100644
--- a/src/CoreBundle/Resources/config/dc-general/table/tl_dcasetting.yml
+++ b/src/CoreBundle/Resources/config/dc-general/table/tl_dcasetting.yml
@@ -163,3 +163,13 @@ services:
event: dc-general.view.contao2backend.manipulate-widget
method: handle
+ MetaModels\CoreBundle\EventListener\DcGeneral\Table\DcaSetting\FallbackLanguageHintListener:
+ arguments:
+ - "@cca.dc-general.scope-matcher"
+ - "@metamodels.factory"
+ - "@translator"
+ tags:
+ - name: kernel.event_listener
+ event: dc-general.view.contao2backend.manipulate-widget
+ method: handle
+
diff --git a/src/CoreBundle/Resources/public/css/style.css b/src/CoreBundle/Resources/public/css/style.css
index dab13ad74..6ff1df1c2 100644
--- a/src/CoreBundle/Resources/public/css/style.css
+++ b/src/CoreBundle/Resources/public/css/style.css
@@ -1,2 +1,2 @@
-.header_css_fields{padding:2px 0 3px 20px;background-image:url("../images/icons/fields.png");background-position:left center;background-repeat:no-repeat;margin-left:15px}.header_add_all{padding:2px 0 3px 20px;background-image:url("../images/icons/dca_add.png");background-position:left center;background-repeat:no-repeat;margin-left:15px}.rendersetting_add_all{background-image:url("../images/icons/rendersettings_add.png")}.dca_palette{color:rgb(138,184,88);margin:6px 0;padding-left:24px;background:url("/system/themes/flexible/icons/navcol.svg") 3px center no-repeat}.mm_problem_display{margin-bottom:30px}.mm_problem_display ul{padding:0;list-style:none}.tl_subdca>legend{margin:0;padding:10px 0 10px 23px;background:url("../images/icons/filter_settings.png") no-repeat left center}.tl_subdca legend label{font-weight:bold}.list_view li:first-child .tl_content{border-top:1px solid rgb(235,235,228)}.list_view .tl_content>div:first-child{float:left}.tl_class{color:rgb(198,198,198)}.tl_formbody{position:relative}input[readonly]{background-color:rgb(235,235,228)}input[readonly]:focus{background-color:rgb(235,235,228)}textarea[readonly]{background-color:rgb(235,235,228)}textarea[readonly]:focus{background-color:rgb(235,235,228)}.wc_info{margin:0}.wc_label{width:31px;display:inline-block}.clx{overflow:visible}.w50x{height:auto}#table_tl_metamodel_dcasetting_ tr.odd td{background-color:transparent}.dca_combine.widget td:empty{display:none}form[id*=tl_metamodel_] .wizard a[data-lightbox] img{margin-top:3px}form[id*=tl_metamodel_] .wizard a[onclick] img{margin-top:3px}div[class*=table_tl_metamodel_] .tl_file_list{padding:4px 0 6px}fieldset.tl_subdca{padding:0;margin:0;border:none}.multicolumnwizard .fallback_language span{font-weight:bold}form[id^=mm_] .sort_hint{display:none}.long .chzn-container{width:100%}.widget.translat-attr label{padding-left:20px;display:inline-block;background:url("../images/icons/locale.png") no-repeat left center}.tl_formbody_edit .settings{margin:0 0 10px 12px}#tl_metamodel_rendersettings .jumpTo_language{width:15%}#tl_metamodel_rendersettings .jumpTo_type{width:15%}#tl_metamodel_rendersettings .jumpTo_type select{width:100%}#tl_metamodel_rendersettings .jumpTo_page{width:15%}#tl_metamodel_rendersettings .jumpTo_page input{width:83%}#tl_metamodel_rendersettings .jumpTo_filter{width:55%}#tl_metamodel_rendersettings .jumpTo_filter div.tl_select,#tl_metamodel_rendersettings .jumpTo_filter select{width:100%}#tl_metamodel_rendersettings .operations{display:none}.empty_icon{width:16px;height:16px;display:inline-block}
+.header_css_fields{padding:2px 0 3px 20px;background-image:url("../images/icons/fields.png");background-position:left center;background-repeat:no-repeat;margin-left:15px}.header_add_all{padding:2px 0 3px 20px;background-image:url("../images/icons/dca_add.png");background-position:left center;background-repeat:no-repeat;margin-left:15px}.rendersetting_add_all{background-image:url("../images/icons/rendersettings_add.png")}.dca_palette{color:rgb(138,184,88);margin:6px 0;padding-left:24px;background:url("/system/themes/flexible/icons/navcol.svg") 3px center no-repeat}.mm_problem_display{margin-bottom:30px}.mm_problem_display ul{padding:0;list-style:none}.tl_subdca>legend{margin:0;padding:10px 0 10px 23px;background:url("../images/icons/filter_settings.png") no-repeat left center}.tl_subdca legend label{font-weight:bold}.list_view li:first-child .tl_content{border-top:1px solid rgb(235,235,228)}.list_view .tl_content>div:first-child{float:left}.tl_class{color:rgb(198,198,198)}.tl_formbody{position:relative}input[readonly]{background-color:rgb(235,235,228)}input[readonly]:focus{background-color:rgb(235,235,228)}textarea[readonly]{background-color:rgb(235,235,228)}textarea[readonly]:focus{background-color:rgb(235,235,228)}.wc_info{margin:0}.wc_label{width:31px;display:inline-block}.clx{overflow:visible}.w50x{height:auto}#table_tl_metamodel_dcasetting_ tr.odd td{background-color:transparent}.dca_combine.widget td:empty{display:none}form[id*=tl_metamodel_] .wizard a[data-lightbox] img{margin-top:3px}form[id*=tl_metamodel_] .wizard a[onclick] img{margin-top:3px}div[class*=table_tl_metamodel_] .tl_file_list{padding:4px 0 6px}fieldset.tl_subdca{padding:0;margin:0;border:none}.multicolumnwizard .fallback_language span{font-weight:bold}form[id^=mm_] .sort_hint{display:none}.long .chzn-container{width:100%}.widget.translat-attr label{padding-left:20px;display:inline-block;background:url("../images/icons/locale.png") no-repeat left center}.tl_formbody_edit .settings{margin:0 0 10px 12px}#tl_metamodel_rendersettings .jumpTo_language{width:15%}#tl_metamodel_rendersettings .jumpTo_type{width:15%}#tl_metamodel_rendersettings .jumpTo_type select{width:100%}#tl_metamodel_rendersettings .jumpTo_page{width:15%}#tl_metamodel_rendersettings .jumpTo_page input{width:83%}#tl_metamodel_rendersettings .jumpTo_filter{width:55%}#tl_metamodel_rendersettings .jumpTo_filter div.tl_select,#tl_metamodel_rendersettings .jumpTo_filter select{width:100%}#tl_metamodel_rendersettings .operations{display:none}.empty_icon{width:16px;height:16px;display:inline-block}.mm-lang-hint{display:inline-block;margin-left:.5ch;padding:0 3px;font-size:.75rem !important;font-weight:bold;line-height:1.4;vertical-align:middle;border-radius:2px;cursor:help;color:#fff}.mm-lang-hint--fallback{background-color:#e6a118}.mm-lang-hint--translated{background-color:#4a9a3f}
/*# sourceMappingURL=style.css.map */
diff --git a/src/CoreBundle/Resources/public/scss/style.scss b/src/CoreBundle/Resources/public/scss/style.scss
index 122dfac39..944e9167d 100644
--- a/src/CoreBundle/Resources/public/scss/style.scss
+++ b/src/CoreBundle/Resources/public/scss/style.scss
@@ -229,3 +229,24 @@ form[id^=mm_] .sort_hint {
height: 16px;
display: inline-block;
}
+
+.mm-lang-hint {
+ display: inline-block;
+ margin-left: 0.5ch;
+ padding: 0 3px;
+ font-size: 0.75rem !important;
+ font-weight: bold;
+ line-height: 1.4;
+ vertical-align: middle;
+ border-radius: 2px;
+ cursor: help;
+ color: #fff;
+}
+
+.mm-lang-hint--fallback {
+ background-color: #e6a118;
+}
+
+.mm-lang-hint--translated {
+ background-color: #4a9a3f;
+}
diff --git a/src/CoreBundle/Resources/translations/metamodels_default.de.xlf b/src/CoreBundle/Resources/translations/metamodels_default.de.xlf
index 7d26481fa..121e34908 100644
--- a/src/CoreBundle/Resources/translations/metamodels_default.de.xlf
+++ b/src/CoreBundle/Resources/translations/metamodels_default.de.xlf
@@ -13,6 +13,22 @@
%template% (%themes%)
%template% (%themes%)
+
+ Fallback
+ Fallback
+
+
+ Value from fallback language "%source%" (not yet translated to "%target%")
+ Wert aus Fallback-Sprache „%source%" (noch nicht nach „%target%" übersetzt)
+
+
+ Translated
+ Übersetzt
+
+
+ Value has its own translation in "%target%"
+ Wert hat eine eigene Übersetzung in „%target%"
+