You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/04/29 11:15:28 UTC

[isis] branch master updated: ISIS-3032: render placeholders as badge

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new d2c6757a1f ISIS-3032: render placeholders as badge
d2c6757a1f is described below

commit d2c6757a1f08776eca7482343504fd0b0f871fa3
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Apr 29 13:15:19 2022 +0200

    ISIS-3032: render placeholders as badge
---
 .../org/apache/isis/applib/value/Password.java     |  3 +-
 .../value/semantics/ValueSemanticsAbstract.java    | 44 +++++++++++++++++--
 .../apache/isis/applib/value/Password_Test.java    | 10 ++---
 .../valuesemantics/BigDecimalValueSemantics.java   |  7 +++-
 .../valuesemantics/BigIntegerValueSemantics.java   |  7 +++-
 .../valuesemantics/BlobValueSemantics.java         | 49 +++++++++++-----------
 .../valuesemantics/BooleanValueSemantics.java      | 16 +++----
 .../valuesemantics/ByteValueSemantics.java         |  7 +++-
 .../valuesemantics/CharacterValueSemantics.java    |  7 +++-
 .../valuesemantics/ClobValueSemantics.java         | 41 +++++++++---------
 .../valuesemantics/DoubleValueSemantics.java       |  7 +++-
 .../valuesemantics/EnumValueSemanticsAbstract.java |  7 +++-
 .../valuesemantics/FloatValueSemantics.java        |  7 +++-
 .../valuesemantics/IntValueSemantics.java          |  7 +++-
 .../LocalResourcePathValueSemantics.java           | 16 ++++++-
 .../valuesemantics/LocaleValueSemantics.java       | 34 ++++++++-------
 .../valuesemantics/LongValueSemantics.java         |  7 +++-
 .../valuesemantics/MarkupValueSemantics.java       |  4 +-
 .../valuesemantics/PasswordValueSemantics.java     |  9 +++-
 .../valuesemantics/ShortValueSemantics.java        |  7 +++-
 .../valuesemantics/TreeNodeValueSemantics.java     |  7 +++-
 .../valuesemantics/URLValueSemantics.java          |  4 +-
 .../valuesemantics/XmlValueSemanticsAbstract.java  |  4 +-
 .../temporal/TemporalValueSemanticsProvider.java   |  9 +++-
 .../value/BooleanValueSemanticsProviderTest.java   |  4 +-
 .../ValueSemanticsProviderAbstractTestCase.java    |  3 +-
 .../AsciiDocValueSemanticsWithPreprocessing.java   |  3 +-
 .../applib/value/CalendarEventSemantics.java       |  4 +-
 .../isis/testdomain/value/ValueSemanticsTest.java  |  3 +-
 .../semantics/AsciiDocValueSemantics.java          |  4 +-
 .../semantics/MarkdownValueSemantics.java          |  4 +-
 .../components/scalars/ScalarPanelAbstract2.java   |  8 ++--
 .../blobclob/IsisBlobOrClobPanelAbstract.java      |  5 ++-
 .../scalars/reference/ReferencePanel.java          |  4 +-
 .../entitysimplelink/EntityLinkSimplePanel.java    | 17 +++++++-
 .../ObjectAdapterMementoProviderAbstract.java      |  6 +--
 .../wicket/ui/pages/bootstrap-overrides-all-v2.css |  4 ++
 37 files changed, 266 insertions(+), 123 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/Password.java b/api/applib/src/main/java/org/apache/isis/applib/value/Password.java
index f9f2fd752b..df59c03d10 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/Password.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/Password.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
 
 import org.apache.isis.applib.IsisModuleApplib;
 import org.apache.isis.applib.annotation.Value;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 
 /**
  * Represents a password that will not displayed to the UI but can be persisted.
@@ -62,7 +63,7 @@ public class Password implements Serializable {
 
     @Override
     public String toString() {
-        return "*";
+        return PlaceholderLiteral.SUPPRESSED.getLiteral();
     }
 
     public static class JaxbToStringAdapter
diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
index 09e7efad99..d5acf6425b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
@@ -31,12 +31,16 @@ import java.util.Locale;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.lang.Nullable;
 
 import org.apache.isis.applib.annotation.TimePrecision;
 import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
 import org.apache.isis.applib.locale.UserLocale;
+import org.apache.isis.applib.services.i18n.TranslationContext;
+import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.util.schema.CommonDtoUtils;
 import org.apache.isis.applib.value.semantics.TemporalValueSemantics.EditingFormatDirection;
@@ -48,7 +52,9 @@ import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.schema.common.v2.ValueType;
 import org.apache.isis.schema.common.v2.ValueWithTypeDto;
 
+import lombok.Getter;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 /**
@@ -58,8 +64,22 @@ public abstract class ValueSemanticsAbstract<T>
 implements
     ValueSemanticsProvider<T> {
 
-    public static final String NULL_REPRESENTATION = "(none)";
-
+    @Getter
+    @RequiredArgsConstructor
+    public static enum PlaceholderLiteral {
+        NULL_REPRESENTATION("(none)",   "badge bg-light placeholder-literal-null"),
+        SUPPRESSED("(suppressed)",      "badge bg-light placeholder-literal-suppressed");
+        private final String literal;
+        private final String cssClass;
+        public String asText(final UnaryOperator<String> translator) {
+            return translator.apply(literal);
+        }
+        public String asHtml(final UnaryOperator<String> translator) {
+            return String.format("<span class=\"%s\">%s</span>",
+                    getCssClass(),
+                    asText(translator));
+        }
+    }
 
     @SuppressWarnings("unchecked")
     @Override
@@ -107,12 +127,19 @@ implements
         .orElseGet(UserLocale::getDefault);
     }
 
-    protected String render(final T value, final Function<T, String> toString) {
+    protected String renderTitle(final T value, final Function<T, String> toString) {
         return Optional.ofNullable(value)
                 .map(toString)
-                .orElse(NULL_REPRESENTATION);
+                .orElse(PlaceholderLiteral.NULL_REPRESENTATION.asText(this::translate));
     }
 
+    protected String renderHtml(final T value, final Function<T, String> toString) {
+        return Optional.ofNullable(value)
+                .map(toString)
+                .orElse(PlaceholderLiteral.NULL_REPRESENTATION.asHtml(this::translate));
+    }
+
+
     // -- COMPOSITION UTILS
 
     protected ValueDecomposition decomposeAsString(
@@ -308,6 +335,15 @@ implements
         }
     }
 
+    // TRANSLATION SUPPORT
+
+    @Autowired(required = false) // nullable (JUnit support)
+    protected TranslationService translationService;
+    protected String translate(final String text) {
+        return translationService!=null
+                ? translationService.translate(TranslationContext.empty(), text)
+                : text;
+    }
 
 
 }
diff --git a/api/applib/src/test/java/org/apache/isis/applib/value/Password_Test.java b/api/applib/src/test/java/org/apache/isis/applib/value/Password_Test.java
index 8b9ab05277..2d56173b98 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/value/Password_Test.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/value/Password_Test.java
@@ -25,18 +25,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
+
 import lombok.val;
 
 class Password_Test {
 
-    private static final String STARS = "*";
-
     @Nested
     public class checkPassword {
 
         @Test
         void case_sensitive() {
-            // guven
+            // given
             final Password password = new Password("secret");
 
             // when, then
@@ -75,10 +75,10 @@ class Password_Test {
         @Test
         void obscures_password() {
             Password password = new Password("secret");
-            assertEquals(STARS, password.toString());
+            assertEquals(PlaceholderLiteral.SUPPRESSED.getLiteral(), password.toString());
 
             password = new Password("a very very very long password");
-            assertEquals(STARS, password.toString());
+            assertEquals(PlaceholderLiteral.SUPPRESSED.getLiteral(), password.toString());
         }
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
index 8256c8b417..053691b466 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
@@ -86,7 +86,12 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final BigDecimal value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final ValueSemanticsProvider.Context context, final BigDecimal value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigIntegerValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigIntegerValueSemantics.java
index 032780b829..ac973bccfc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigIntegerValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigIntegerValueSemantics.java
@@ -75,7 +75,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final BigInteger value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final BigInteger value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BlobValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BlobValueSemantics.java
index f81da919b6..f63d474502 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BlobValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BlobValueSemantics.java
@@ -18,12 +18,8 @@
  */
 package org.apache.isis.core.metamodel.valuesemantics;
 
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
 import java.util.function.UnaryOperator;
 
-import javax.activation.MimeType;
-import javax.activation.MimeTypeParseException;
 import javax.inject.Named;
 
 import org.springframework.stereotype.Component;
@@ -36,8 +32,6 @@ import org.apache.isis.applib.value.semantics.ValueDecomposition;
 import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
 import org.apache.isis.applib.value.semantics.ValueSemanticsProvider;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._Bytes;
-import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.schema.common.v2.ValueType;
 
 @Component
@@ -74,29 +68,34 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final Blob value) {
-        return render(value, Blob::getName);
+        return renderTitle(value, Blob::getName);
     }
 
-    // -- ENCODER DECODER
-
-    public String toEncodedString(final Blob blob) {
-        return blob.getName() + ":" + blob.getMimeType().getBaseType() + ":" +
-        _Strings.ofBytes(_Bytes.encodeToBase64(Base64.getEncoder(), blob.getBytes()), StandardCharsets.UTF_8);
+    @Override
+    public String htmlPresentation(final ValueSemanticsProvider.Context context, final Blob value) {
+        return renderHtml(value, Blob::getName);
     }
 
-    public Blob fromEncodedString(final String data) {
-        final int colonIdx = data.indexOf(':');
-        final String name  = data.substring(0, colonIdx);
-        final int colon2Idx  = data.indexOf(":", colonIdx+1);
-        final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
-        final String payload = data.substring(colon2Idx+1);
-        final byte[] bytes = _Bytes.decodeBase64(Base64.getDecoder(), payload.getBytes(StandardCharsets.UTF_8));
-        try {
-            return new Blob(name, new MimeType(mimeTypeBase), bytes);
-        } catch (MimeTypeParseException e) {
-            throw new RuntimeException(e);
-        }
-    }
+    // -- ENCODER DECODER
+
+//    public String toEncodedString(final Blob blob) {
+//        return blob.getName() + ":" + blob.getMimeType().getBaseType() + ":" +
+//        _Strings.ofBytes(_Bytes.encodeToBase64(Base64.getEncoder(), blob.getBytes()), StandardCharsets.UTF_8);
+//    }
+//
+//    public Blob fromEncodedString(final String data) {
+//        final int colonIdx = data.indexOf(':');
+//        final String name  = data.substring(0, colonIdx);
+//        final int colon2Idx  = data.indexOf(":", colonIdx+1);
+//        final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
+//        final String payload = data.substring(colon2Idx+1);
+//        final byte[] bytes = _Bytes.decodeBase64(Base64.getDecoder(), payload.getBytes(StandardCharsets.UTF_8));
+//        try {
+//            return new Blob(name, new MimeType(mimeTypeBase), bytes);
+//        } catch (MimeTypeParseException e) {
+//            throw new RuntimeException(e);
+//        }
+//    }
 
     // -- EXAMPLES
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BooleanValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BooleanValueSemantics.java
index 48ce1921e0..da452beb80 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BooleanValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BooleanValueSemantics.java
@@ -22,12 +22,9 @@ import java.util.function.UnaryOperator;
 
 import javax.inject.Named;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
-import org.apache.isis.applib.services.i18n.TranslationContext;
-import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.value.semantics.DefaultsProvider;
 import org.apache.isis.applib.value.semantics.Parser;
 import org.apache.isis.applib.value.semantics.Renderer;
@@ -53,9 +50,6 @@ implements
     Parser<Boolean>,
     Renderer<Boolean> {
 
-    @Autowired(required = false)
-    private TranslationService translationService;
-
     @Override
     public Class<Boolean> getCorrespondingClass() {
         return Boolean.class;
@@ -88,10 +82,12 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final Boolean value) {
-        val title = render(value, v->v.booleanValue() ? "True" : "False");
-        return translationService!=null
-                ? translationService.translate(TranslationContext.empty(), title)
-                : title;
+        return renderTitle(value, v->translate(v.booleanValue() ? "True" : "False"));
+    }
+
+    @Override
+    public String htmlPresentation(final ValueSemanticsProvider.Context context, final Boolean value) {
+        return renderHtml(value, v->translate(v.booleanValue() ? "True" : "False"));
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ByteValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ByteValueSemantics.java
index 6a987b2545..d6240bbb43 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ByteValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ByteValueSemantics.java
@@ -82,7 +82,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Byte value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Byte value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/CharacterValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/CharacterValueSemantics.java
index 0016417d44..ffe0cbdc3e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/CharacterValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/CharacterValueSemantics.java
@@ -88,7 +88,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Character value) {
-        return render(value, c->""+c);
+        return renderTitle(value, c->""+c);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Character value) {
+        return renderHtml(value, c->""+c);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ClobValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ClobValueSemantics.java
index 00fdcd909f..66088dcdc0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ClobValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ClobValueSemantics.java
@@ -20,8 +20,6 @@ package org.apache.isis.core.metamodel.valuesemantics;
 
 import java.util.function.UnaryOperator;
 
-import javax.activation.MimeType;
-import javax.activation.MimeTypeParseException;
 import javax.inject.Named;
 
 import org.springframework.stereotype.Component;
@@ -70,27 +68,32 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final Clob value) {
-        return render(value, Clob::getName);
+        return renderTitle(value, Clob::getName);
     }
 
-    // -- ENCODER DECODER
-
-    private String toEncodedString(final Clob clob) {
-        return clob.getName() + ":" + clob.getMimeType().getBaseType() + ":" + clob.getChars();
+    @Override
+    public String htmlPresentation(final ValueSemanticsProvider.Context context, final Clob value) {
+        return renderHtml(value, Clob::getName);
     }
 
-    private Clob fromEncodedString(final String data) {
-        final int colonIdx = data.indexOf(':');
-        final String name  = data.substring(0, colonIdx);
-        final int colon2Idx  = data.indexOf(":", colonIdx+1);
-        final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
-        final CharSequence chars = data.substring(colon2Idx+1);
-        try {
-            return new Clob(name, new MimeType(mimeTypeBase), chars);
-        } catch (MimeTypeParseException e) {
-            throw new RuntimeException(e);
-        }
-    }
+    // -- ENCODER DECODER
+
+//    private String toEncodedString(final Clob clob) {
+//        return clob.getName() + ":" + clob.getMimeType().getBaseType() + ":" + clob.getChars();
+//    }
+//
+//    private Clob fromEncodedString(final String data) {
+//        final int colonIdx = data.indexOf(':');
+//        final String name  = data.substring(0, colonIdx);
+//        final int colon2Idx  = data.indexOf(":", colonIdx+1);
+//        final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
+//        final CharSequence chars = data.substring(colon2Idx+1);
+//        try {
+//            return new Clob(name, new MimeType(mimeTypeBase), chars);
+//        } catch (MimeTypeParseException e) {
+//            throw new RuntimeException(e);
+//        }
+//    }
 
     // -- EXAMPLES
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/DoubleValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/DoubleValueSemantics.java
index ff4d495373..569f9bb917 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/DoubleValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/DoubleValueSemantics.java
@@ -78,7 +78,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Double value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Double value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/EnumValueSemanticsAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/EnumValueSemanticsAbstract.java
index 1a01cd66fc..3146a96eaa 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/EnumValueSemanticsAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/EnumValueSemanticsAbstract.java
@@ -142,7 +142,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final T value) {
-        return render(value, v->friendlyName(context, v));
+        return renderTitle(value, v->friendlyName(context, v));
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final T value) {
+        return renderHtml(value, v->friendlyName(context, v));
     }
 
     private String friendlyName(final Context context, final T object) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/FloatValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/FloatValueSemantics.java
index 03ef5f1799..d76873b94b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/FloatValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/FloatValueSemantics.java
@@ -78,7 +78,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Float value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Float value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/IntValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/IntValueSemantics.java
index 8019e1236f..ab050fd94c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/IntValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/IntValueSemantics.java
@@ -82,7 +82,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Integer value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Integer value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocalResourcePathValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocalResourcePathValueSemantics.java
index d1633178ef..c9af88b0d6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocalResourcePathValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocalResourcePathValueSemantics.java
@@ -69,9 +69,23 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final LocalResourcePath value) {
-        return render(value, LocalResourcePath::getValue);
+        return renderTitle(value, LocalResourcePath::getValue);
     }
 
+    @Override
+    public String htmlPresentation(final Context context, final LocalResourcePath value) {
+        return renderHtml(value, v->toHtmlLink(v));
+    }
+
+    private String toHtmlLink(final LocalResourcePath path) {
+        val href = path.getValue();
+        return String.format("<a "
+                + "target=\"_blank\" "
+                + "class=\"no-click-bubbling\" "
+                + "href=\"%s\">%s</a>", href, href);
+    }
+
+
     // -- PARSER
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocaleValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocaleValueSemantics.java
index 9927ef6526..6106603e19 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocaleValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LocaleValueSemantics.java
@@ -70,26 +70,30 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final Locale value) {
+        return renderTitle(value, v->localeToString(context, value));
+    }
 
-        return render(value, v->{
-
-            val userLanguageLocale = context.getInteractionContext().getLocale().getLanguageLocale();
+    @Override
+    public String htmlPresentation(final ValueSemanticsProvider.Context context, final Locale value) {
+        return renderHtml(value, v->localeToString(context, value));
+    }
 
-            val language = value.getDisplayLanguage(userLanguageLocale);
-            if(_Strings.isEmpty(language)) {
-                return stringify(v);
-            }
+    private String localeToString(final ValueSemanticsProvider.Context context, final Locale value) {
+        val userLanguageLocale = context.getInteractionContext().getLocale().getLanguageLocale();
 
-            val country = value.getDisplayCountry(userLanguageLocale);
-            if(_Strings.isEmpty(country)) {
-                return language;
-            }
+        val language = value.getDisplayLanguage(userLanguageLocale);
+        if(_Strings.isEmpty(language)) {
+            return stringify(value);
+        }
 
-            return String.format("%s (%s)",
-                    value.getDisplayLanguage(userLanguageLocale),
-                    value.getDisplayCountry(userLanguageLocale));
+        val country = value.getDisplayCountry(userLanguageLocale);
+        if(_Strings.isEmpty(country)) {
+            return language;
+        }
 
-        });
+        return String.format("%s (%s)",
+                value.getDisplayLanguage(userLanguageLocale),
+                value.getDisplayCountry(userLanguageLocale));
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LongValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LongValueSemantics.java
index 747f5f7f15..f39a6b1ac2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LongValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/LongValueSemantics.java
@@ -82,7 +82,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Long value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Long value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/MarkupValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/MarkupValueSemantics.java
index 0689dcbe43..948c39270a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/MarkupValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/MarkupValueSemantics.java
@@ -65,12 +65,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Markup value) {
-        return render(value, Markup::toString);
+        return renderTitle(value, Markup::toString);
     }
 
     @Override
     public String htmlPresentation(final ValueSemanticsProvider.Context context, final Markup adoc) {
-        return render(adoc, Markup::asHtml);
+        return renderHtml(adoc, Markup::asHtml);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/PasswordValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/PasswordValueSemantics.java
index 035e3615b1..545bfd9a19 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/PasswordValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/PasswordValueSemantics.java
@@ -67,14 +67,19 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Password value) {
-        return render(value, v->"*");
+        return renderTitle(value, v->PlaceholderLiteral.SUPPRESSED.asText(this::translate));
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Password value) {
+        return renderHtml(value, v->PlaceholderLiteral.SUPPRESSED.asHtml(this::translate));
     }
 
     // -- PARSER
 
     @Override
     public String parseableTextRepresentation(final Context context, final Password value) {
-        return render(value, v->"*");
+        return renderTitle(value, v->PlaceholderLiteral.SUPPRESSED.asText(this::translate));
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ShortValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ShortValueSemantics.java
index 0b81b614af..bb9d2b0c2d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ShortValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/ShortValueSemantics.java
@@ -82,7 +82,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Short value) {
-        return render(value, getNumberFormat(context)::format);
+        return renderTitle(value, getNumberFormat(context)::format);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final Short value) {
+        return renderHtml(value, getNumberFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/TreeNodeValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
index 9751a0eada..dcf5dd3463 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
@@ -93,7 +93,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final TreeNode<?> value) {
-        return super.render(value, TreeNode::toString);
+        return renderTitle(value, TreeNode::toString);
+    }
+
+    @Override
+    public String htmlPresentation(final Context context, final TreeNode<?> value) {
+        return renderHtml(value, TreeNode::toString);
     }
 
     // -- EXAMPLES
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/URLValueSemantics.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/URLValueSemantics.java
index 4cbfb2f357..3865c2d8a7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/URLValueSemantics.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/URLValueSemantics.java
@@ -79,12 +79,12 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final java.net.URL value) {
-        return render(value, v->v.toString());
+        return renderTitle(value, v->v.toString());
     }
 
     @Override
     public String htmlPresentation(final ValueSemanticsProvider.Context context, final java.net.URL value) {
-        return render(value, v->toHtmlLink(v));
+        return renderHtml(value, v->toHtmlLink(v));
     }
 
     private String toHtmlLink(final java.net.URL url) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/XmlValueSemanticsAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/XmlValueSemanticsAbstract.java
index b5625fa748..62fb503462 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/XmlValueSemanticsAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/XmlValueSemanticsAbstract.java
@@ -89,12 +89,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final T value) {
-        return render(value, v->String.format("XML[length=%d]", toXml(v).length()));
+        return renderTitle(value, v->String.format("XML[length=%d]", toXml(v).length()));
     }
 
     @Override
     public String htmlPresentation(final Context context, final T value) {
-        return render(value, v->renderXml(context, toXml(v)));
+        return renderHtml(value, v->renderXml(context, toXml(v)));
     }
 
     protected String renderXml(final @NonNull Context context, final @NonNull String xml) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java
index e8492c5a09..818bb30ab5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java
@@ -143,7 +143,14 @@ implements TemporalValueSemantics<T> {
     public final String titlePresentation(
             final ValueSemanticsProvider.Context context,
             final T value) {
-        return render(value, getRenderingFormat(context)::format);
+        return renderTitle(value, getRenderingFormat(context)::format);
+    }
+
+    @Override
+    public final String htmlPresentation(
+            final ValueSemanticsProvider.Context context,
+            final T value) {
+        return renderHtml(value, getRenderingFormat(context)::format);
     }
 
     // -- PARSER
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/BooleanValueSemanticsProviderTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/BooleanValueSemanticsProviderTest.java
index 56cb06697a..4e9aebaa58 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/BooleanValueSemanticsProviderTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/BooleanValueSemanticsProviderTest.java
@@ -25,7 +25,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
-import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.core.metamodel.valuesemantics.BooleanValueSemantics;
 
 public class BooleanValueSemanticsProviderTest
@@ -81,7 +81,7 @@ extends ValueSemanticsProviderAbstractTestCase<Boolean> {
 
     @Test
     public void testTitleWhenNotSet() throws Exception {
-        assertEquals(ValueSemanticsAbstract.NULL_REPRESENTATION,
+        assertEquals(PlaceholderLiteral.NULL_REPRESENTATION.getLiteral(),
                 value.titlePresentation(null, null));
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/ValueSemanticsProviderAbstractTestCase.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/ValueSemanticsProviderAbstractTestCase.java
index 4cdf6793ca..a2c41772cd 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/ValueSemanticsProviderAbstractTestCase.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/value/ValueSemanticsProviderAbstractTestCase.java
@@ -38,6 +38,7 @@ import org.apache.isis.applib.services.iactn.InteractionProvider;
 import org.apache.isis.applib.value.semantics.Parser;
 import org.apache.isis.applib.value.semantics.Renderer;
 import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.applib.value.semantics.ValueSemanticsProvider;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
@@ -159,7 +160,7 @@ public abstract class ValueSemanticsProviderAbstractTestCase<T> {
             assertEquals("",
                     semantics.getRenderer().titlePresentation(null, null));
         } else {
-            assertEquals(ValueSemanticsAbstract.NULL_REPRESENTATION,
+            assertEquals(PlaceholderLiteral.NULL_REPRESENTATION.getLiteral(),
                     semantics.getRenderer().titlePresentation(null, null));
         }
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java b/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java
index 8185ec7955..34944457ed 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/_infra/resources/AsciiDocValueSemanticsWithPreprocessing.java
@@ -20,8 +20,7 @@ extends AsciiDocValueSemantics {
 
     @Override
     public String htmlPresentation(final ValueSemanticsProvider.Context context, final AsciiDoc adoc) {
-
-        return render(adoc, plainAdoc->
+        return renderHtml(adoc, plainAdoc->
             asciiDocConverterService
             .adocToHtml(
                     context.getFeatureIdentifier().getLogicalType().getCorrespondingClass(),
diff --git a/extensions/vw/fullcalendar/applib/src/main/java/org/apache/isis/extensions/fullcalendar/applib/value/CalendarEventSemantics.java b/extensions/vw/fullcalendar/applib/src/main/java/org/apache/isis/extensions/fullcalendar/applib/value/CalendarEventSemantics.java
index 00de2abb89..13a4747547 100644
--- a/extensions/vw/fullcalendar/applib/src/main/java/org/apache/isis/extensions/fullcalendar/applib/value/CalendarEventSemantics.java
+++ b/extensions/vw/fullcalendar/applib/src/main/java/org/apache/isis/extensions/fullcalendar/applib/value/CalendarEventSemantics.java
@@ -125,7 +125,7 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final CalendarEvent value) {
-        return render(value, v->{
+        return renderTitle(value, v->{
             val title = new _StringInterpolation(toMap(context, value))
                     .applyTo(titleTemplate);
             return title;
@@ -137,7 +137,7 @@ implements
 
     @Override
     public String htmlPresentation(final Context context, final CalendarEvent value) {
-        return render(value, v->{
+        return renderHtml(value, v->{
             val html = new _StringInterpolation(toMap(context, value))
                     .applyTo(htmlTemplate)
                     .stream()
diff --git a/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java b/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
index 6bf04425ef..742064d232 100644
--- a/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
+++ b/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
@@ -50,6 +50,7 @@ import org.apache.isis.applib.value.Password;
 import org.apache.isis.applib.value.semantics.Parser;
 import org.apache.isis.applib.value.semantics.Renderer;
 import org.apache.isis.applib.value.semantics.ValueDecomposition;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.applib.value.semantics.ValueSemanticsProvider;
 import org.apache.isis.applib.value.semantics.ValueSemanticsResolver;
 import org.apache.isis.commons.internal.collections._Sets;
@@ -197,7 +198,7 @@ class ValueSemanticsTest {
 
                         if(valueType.equals(Password.class)) {
                             val recoveredValue = (Password)parser.parseTextRepresentation(context, stringified);
-                            assertTrue(recoveredValue.checkPassword("*"));
+                            assertTrue(recoveredValue.checkPassword(PlaceholderLiteral.SUPPRESSED.getLiteral()));
 
                         } else {
 
diff --git a/valuetypes/asciidoc/metamodel/src/main/java/org/apache/isis/valuetypes/asciidoc/metamodel/semantics/AsciiDocValueSemantics.java b/valuetypes/asciidoc/metamodel/src/main/java/org/apache/isis/valuetypes/asciidoc/metamodel/semantics/AsciiDocValueSemantics.java
index 2a02d7790c..ecf215c0ed 100644
--- a/valuetypes/asciidoc/metamodel/src/main/java/org/apache/isis/valuetypes/asciidoc/metamodel/semantics/AsciiDocValueSemantics.java
+++ b/valuetypes/asciidoc/metamodel/src/main/java/org/apache/isis/valuetypes/asciidoc/metamodel/semantics/AsciiDocValueSemantics.java
@@ -65,12 +65,12 @@ implements
 
     @Override
     public String titlePresentation(final ValueSemanticsProvider.Context context, final AsciiDoc adoc) {
-        return render(adoc, AsciiDoc::toString);
+        return renderTitle(adoc, AsciiDoc::toString);
     }
 
     @Override
     public String htmlPresentation(final ValueSemanticsProvider.Context context, final AsciiDoc adoc) {
-        return render(adoc, AsciiDoc::asHtml);
+        return renderHtml(adoc, AsciiDoc::asHtml);
     }
 
     // -- PARSER
diff --git a/valuetypes/markdown/metamodel/src/main/java/org/apache/isis/valuetypes/markdown/metamodel/semantics/MarkdownValueSemantics.java b/valuetypes/markdown/metamodel/src/main/java/org/apache/isis/valuetypes/markdown/metamodel/semantics/MarkdownValueSemantics.java
index 7baeb073b4..8274bc3d9f 100644
--- a/valuetypes/markdown/metamodel/src/main/java/org/apache/isis/valuetypes/markdown/metamodel/semantics/MarkdownValueSemantics.java
+++ b/valuetypes/markdown/metamodel/src/main/java/org/apache/isis/valuetypes/markdown/metamodel/semantics/MarkdownValueSemantics.java
@@ -65,12 +65,12 @@ implements
 
     @Override
     public String titlePresentation(final Context context, final Markdown value) {
-        return render(value, Markdown::toString);
+        return renderTitle(value, Markdown::toString);
     }
 
     @Override
     public String htmlPresentation(final ValueSemanticsProvider.Context context, final Markdown adoc) {
-        return render(adoc, Markdown::asHtml);
+        return renderHtml(adoc, Markdown::asHtml);
     }
 
     // -- PARSER
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
index 9863713af7..a09b9048bf 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
@@ -28,7 +28,7 @@ import org.apache.wicket.markup.html.form.FormComponent;
 import org.apache.wicket.markup.repeater.RepeatingView;
 import org.springframework.lang.Nullable;
 
-import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.viewer.wicket.model.models.InlinePromptContext;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
@@ -41,11 +41,12 @@ import org.apache.isis.viewer.wicket.ui.panels.FormExecutorDefault;
 import org.apache.isis.viewer.wicket.ui.util.Wkt;
 import org.apache.isis.viewer.wicket.ui.util.WktTooltips;
 
-import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.BootstrapFileInputField;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.val;
 
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.BootstrapFileInputField;
+
 /**
  *  Adds inline prompt logic.
  */
@@ -147,7 +148,8 @@ extends ScalarPanelAbstract {
     protected String obtainOutputFormat() {
         return _Strings.nonEmpty(
                     scalarModel().proposedValue().getValueAsHtml().getValue())
-                .orElseGet(()->translate(ValueSemanticsAbstract.NULL_REPRESENTATION));
+                .orElseGet(()->
+                    PlaceholderLiteral.NULL_REPRESENTATION.asHtml(this::translate));
     }
 
     /**
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
index da7f372ed2..baf879cd81 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
@@ -32,7 +32,7 @@ import org.apache.wicket.request.resource.IResource;
 import org.apache.isis.applib.value.Blob;
 import org.apache.isis.applib.value.Clob;
 import org.apache.isis.applib.value.NamedWithMimeType;
-import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.CompactFragment;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.InputFragment;
@@ -89,7 +89,8 @@ extends ScalarPanelFormFieldAbstract<T> {
     protected String obtainOutputFormat() {
         return getBlobOrClobFromModel()
                 .map(NamedWithMimeType::getName)
-                .orElse(translate(ValueSemanticsAbstract.NULL_REPRESENTATION));
+                .orElseGet(()->
+                    PlaceholderLiteral.NULL_REPRESENTATION.asHtml(this::translate));
     }
 
     @Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
index 7bce33b875..f72e228e68 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
@@ -31,6 +31,7 @@ import org.apache.wicket.util.convert.IConverter;
 import org.wicketstuff.select2.ChoiceProvider;
 import org.wicketstuff.select2.Settings;
 
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.core.metamodel.objectmanager.memento.ObjectMemento;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.util.Facets;
@@ -205,7 +206,8 @@ public class ReferencePanel extends ScalarPanelSelectAbstract {
                     || isInlinePrompt) {
                 WktComponents.permanentlyHide(container, ID_ENTITY_TITLE_IF_NULL);
             } else {
-                Wkt.labelAdd(container, ID_ENTITY_TITLE_IF_NULL, "(none)"); //XXX missing i18n support
+                Wkt.labelAdd(container, ID_ENTITY_TITLE_IF_NULL,
+                        PlaceholderLiteral.NULL_REPRESENTATION.asHtml(this::translate));
             }
         });
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitysimplelink/EntityLinkSimplePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitysimplelink/EntityLinkSimplePanel.java
index 9ef8299b96..22c2ce17bd 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitysimplelink/EntityLinkSimplePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/entitysimplelink/EntityLinkSimplePanel.java
@@ -23,7 +23,8 @@ import org.apache.wicket.markup.html.form.FormComponent;
 import org.apache.wicket.markup.html.form.FormComponentPanel;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.isis.applib.services.i18n.TranslationContext;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
@@ -67,7 +68,8 @@ implements CancelHintRequired  {
         if(isEmpty) {
             // represent no object by a simple label displaying '(none)'
             val nullRepresentation =
-                    Wkt.labelAdd(this, ID_ENTITY_TITLE_NULL, ValueSemanticsAbstract.NULL_REPRESENTATION);
+                    Wkt.labelAdd(this, ID_ENTITY_TITLE_NULL,
+                            PlaceholderLiteral.NULL_REPRESENTATION.asHtml(this::translate));
             Wkt.cssAppend(nullRepresentation, "null-representation");
             permanentlyHide(ID_ENTITY_ICON_AND_TITLE);
 
@@ -105,4 +107,15 @@ implements CancelHintRequired  {
         // no-op since immutable
     }
 
+    // -- TRANSLATION
+
+    /**
+     * Translate without context: Tooltips, Button-Labels, etc.
+     */
+    public final String translate(final String input) {
+        return ((HasCommonContext)getModel()).getCommonContext().getTranslationService()
+                .translate(TranslationContext.empty(), input);
+    }
+
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
index a93c1da027..e21da48406 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
@@ -28,7 +28,7 @@ import org.wicketstuff.select2.ChoiceProvider;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.i18n.TranslationContext;
-import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -62,7 +62,7 @@ extends ChoiceProvider<ObjectMemento> {
     public String getDisplayValue(final ObjectMemento choiceMemento) {
         if (choiceMemento == null
                 || choiceMemento instanceof ObjectMementoForEmpty) {
-            return translate(ValueSemanticsAbstract.NULL_REPRESENTATION);
+            return PlaceholderLiteral.NULL_REPRESENTATION.asText(this::translate);
         }
         val choice = getCommonContext().reconstructObject(choiceMemento);
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(choice)) {
@@ -74,7 +74,7 @@ extends ChoiceProvider<ObjectMemento> {
     @Override
     public String getIdValue(final ObjectMemento choiceMemento) {
         if (choiceMemento == null) {
-            return NULL_PLACEHOLDER;
+            return PlaceholderLiteral.NULL_REPRESENTATION.asText(this::translate);
         }
         val logicalType = choiceMemento.getLogicalType();
         val spec = getCommonContext().getSpecificationLoader()
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides-all-v2.css b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides-all-v2.css
index c0c850b0ee..175e980280 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides-all-v2.css
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides-all-v2.css
@@ -823,6 +823,10 @@ div.referencePanel.scalarNameAndValueComponentType {
     margin-right: 0px;
 }
 
+.placeholder-literal-null,
+.placeholder-literal-suppressed {
+	opacity: 0.85;
+}
 
 .scalarValueWrapper ul.additionalLinkList {
     padding-bottom: 5px;