You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2023/01/12 12:51:49 UTC
[myfaces-tobago] branch tobago-5.x updated: Tobago 5.x message format (#3657)
This is an automated email from the ASF dual-hosted git repository.
lofwyr pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/tobago-5.x by this push:
new 641e35a762 Tobago 5.x message format (#3657)
641e35a762 is described below
commit 641e35a762c024450960af69da7e3746149082e0
Author: Udo Schnurpfeil <lo...@apache.org>
AuthorDate: Thu Jan 12 13:51:44 2023 +0100
Tobago 5.x message format (#3657)
* feat: message-format for tc:out
issue: TOBAGO-2177
---
.../myfaces/tobago/component/Attributes.java | 1 +
.../tobago/internal/component/AbstractUIOut.java | 2 +
.../internal/renderkit/renderer/OutRenderer.java | 59 ++++++++++++++++++++++
.../taglib/component/OutTagDeclaration.java | 11 ++++
.../internal/config/AbstractTobagoTestBase.java | 2 +
.../renderkit/renderer/OutRendererUnitTest.java | 23 +++++++++
.../src/test/resources/renderer/out/outFormat.html | 18 +++++++
.../tobago-example-demo/package-lock.json | 14 ++---
.../tobago/example/demo/DemoBundle.properties | 1 +
.../tobago/example/demo/DemoBundle_de.properties | 1 +
.../webapp/content/020-output/10-out/Out.xhtml | 14 ++++-
11 files changed, 136 insertions(+), 10 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
index 0ad982eff0..5b29c108fa 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
@@ -215,6 +215,7 @@ public enum Attributes {
maxWidth,
media,
method,
+ messageFormat,
min,
minHeight,
minWidth,
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIOut.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIOut.java
index 49bcdec70e..60288a6c56 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIOut.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIOut.java
@@ -49,6 +49,8 @@ public abstract class AbstractUIOut extends UIOutput implements SupportsLabelLay
@Deprecated
public abstract boolean isCompact();
+ public abstract boolean isMessageFormat();
+
public abstract SanitizeMode getSanitize();
@Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java
index 371058ebc2..0ed948f682 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java
@@ -30,13 +30,25 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
import org.apache.myfaces.tobago.sanitizer.SanitizeMode;
import org.apache.myfaces.tobago.sanitizer.Sanitizer;
import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
import java.util.StringTokenizer;
public class OutRenderer<T extends AbstractUIOut> extends MessageLayoutRendererBase<T> {
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
@Override
protected boolean isOutputOnly(T component) {
return true;
@@ -105,6 +117,10 @@ public class OutRenderer<T extends AbstractUIOut> extends MessageLayoutRendererB
text = "";
}
+ if (out.isMessageFormat()) {
+ text = getOutputFormatText(facesContext, text, out);
+ }
+
if (escape) {
if (keepLineBreaks) {
final StringTokenizer tokenizer = new StringTokenizer(text, "\r\n");
@@ -129,6 +145,49 @@ public class OutRenderer<T extends AbstractUIOut> extends MessageLayoutRendererB
}
}
+ private String getOutputFormatText(final FacesContext facesContext, final String pattern, final T out) {
+ final Object[] args;
+ if (out.getChildCount() > 0) {
+ final List<UIParameter> validParams = getValidUIParameterChildren(out);
+ if (!validParams.isEmpty()) {
+ List<Object> argsList = new ArrayList<>(validParams.size());
+ for (UIParameter param : validParams) {
+ argsList.add(param.getValue());
+ }
+ args = argsList.toArray(EMPTY_OBJECT_ARRAY);
+ } else {
+ args = EMPTY_OBJECT_ARRAY;
+ }
+ } else {
+ args = EMPTY_OBJECT_ARRAY;
+ }
+
+ final MessageFormat format = new MessageFormat(pattern, facesContext.getViewRoot().getLocale());
+ try {
+ return format.format(args);
+ } catch (Exception e) {
+ LOG.error("Error formatting message of component with clientId='{}'", out.getClientId(facesContext));
+ return pattern;
+ }
+ }
+
+ private List<UIParameter> getValidUIParameterChildren(T out) {
+
+ List<UIParameter> parameters = new ArrayList<>();
+ for (UIComponent child : out.getChildren()) {
+ if (child instanceof UIParameter) {
+ UIParameter param = (UIParameter) child;
+ if (param.isDisable() || !param.isRendered()) {
+ // ignore
+ continue;
+ }
+ parameters.add(param);
+ }
+ }
+
+ return parameters;
+ }
+
@Override
public void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
final TobagoResponseWriter writer = getResponseWriter(facesContext);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/OutTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/OutTagDeclaration.java
index 1591a29f2f..864a2c789b 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/OutTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/OutTagDeclaration.java
@@ -37,6 +37,7 @@ import org.apache.myfaces.tobago.internal.taglib.declaration.IsPlain;
import org.apache.myfaces.tobago.internal.taglib.declaration.IsVisual;
import javax.faces.component.UIOutput;
+import java.text.MessageFormat;
/**
* Renders a text
@@ -98,4 +99,14 @@ public interface OutTagDeclaration
@TagAttribute
@UIComponentTagAttribute(type = "boolean", defaultValue = "false")
void setCompact(String compact);
+
+ /**
+ * Activates formatting of the value with the method {@link MessageFormat#format(String, Object...)}
+ * A parameters the values of the children of type {@link javax.faces.component.UIParameter} are used.
+ *
+ * @since 5.5.0
+ */
+ @TagAttribute
+ @UIComponentTagAttribute(type = "boolean", defaultValue = "false")
+ void setMessageFormat(String messageFormat);
}
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java
index b6f2c4e2b6..9d9a071e4f 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/AbstractTobagoTestBase.java
@@ -114,6 +114,7 @@ import static org.apache.myfaces.tobago.util.ResourceUtils.TOBAGO_RESOURCE_BUNDL
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
+import javax.faces.component.UIParameter;
import javax.faces.component.behavior.AjaxBehavior;
import javax.faces.convert.DateTimeConverter;
import javax.faces.render.RenderKit;
@@ -200,6 +201,7 @@ public abstract class AbstractTobagoTestBase extends AbstractJsfTestCase {
application.addComponent(Tags.treeNode.componentType(), UITreeNode.class.getName());
application.addComponent(Tags.treeIndent.componentType(), UITreeIndent.class.getName());
application.addComponent(Tags.treeSelect.componentType(), UITreeSelect.class.getName());
+ application.addComponent(UIParameter.COMPONENT_TYPE, UIParameter.class.getName());
application.addBehavior(AjaxBehavior.BEHAVIOR_ID, AjaxBehavior.class.getName());
application.addBehavior(EventBehavior.BEHAVIOR_ID, EventBehavior.class.getName());
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRendererUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRendererUnitTest.java
index c743086f20..f0927b3c8a 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRendererUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRendererUnitTest.java
@@ -28,6 +28,7 @@ import org.apache.myfaces.tobago.util.ComponentUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import javax.faces.component.UIParameter;
import java.io.IOException;
public class OutRendererUnitTest extends RendererTestBase {
@@ -91,4 +92,26 @@ public class OutRendererUnitTest extends RendererTestBase {
Assertions.assertEquals(loadHtml("renderer/out/outSanitizeNever.html"), formattedResult());
}
+ @Test
+ public void outFormat() throws IOException {
+ final UIOut c = (UIOut) ComponentUtils.createComponent(
+ facesContext, Tags.out.componentType(), RendererTypes.Out, "id");
+ c.setValue("Hello {0} {1}!");
+ c.setMessageFormat(true);
+
+ final UIParameter p0 = (UIParameter) ComponentUtils.createComponent(
+ facesContext, UIParameter.COMPONENT_TYPE, null, "p0");
+ p0.setValue("Mrs");
+ c.getChildren().add(p0);
+
+ final UIParameter p1 = (UIParameter) ComponentUtils.createComponent(
+ facesContext, UIParameter.COMPONENT_TYPE, null, "p1");
+ p1.setValue("Smith");
+ c.getChildren().add(p1);
+
+ c.encodeAll(facesContext);
+
+ Assertions.assertEquals(loadHtml("renderer/out/outFormat.html"), formattedResult());
+ }
+
}
diff --git a/tobago-core/src/test/resources/renderer/out/outFormat.html b/tobago-core/src/test/resources/renderer/out/outFormat.html
new file mode 100644
index 0000000000..ecf3ca6b2c
--- /dev/null
+++ b/tobago-core/src/test/resources/renderer/out/outFormat.html
@@ -0,0 +1,18 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<tobago-out id='id' class='tobago-auto-spacing'><span class='form-control-plaintext'>Hello Mrs Smith!</span></tobago-out>
diff --git a/tobago-example/tobago-example-demo/package-lock.json b/tobago-example/tobago-example-demo/package-lock.json
index 235efd5d63..8ac044cbef 100644
--- a/tobago-example/tobago-example-demo/package-lock.json
+++ b/tobago-example/tobago-example-demo/package-lock.json
@@ -10,6 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"font-awesome": "4.7.0",
+ "glob-parent": "^6.0.2",
"jasmine-core": "^4.5.0",
"prismjs": "^1.29.0"
},
@@ -774,7 +775,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.3"
},
@@ -1031,7 +1031,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1049,7 +1048,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -2888,9 +2886,9 @@
}
},
"glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.3"
@@ -3075,8 +3073,7 @@
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
@@ -3088,7 +3085,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
diff --git a/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle.properties b/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle.properties
index ae68c5e8ad..38f04e1fa1 100644
--- a/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle.properties
+++ b/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle.properties
@@ -15,3 +15,4 @@
locale_short=default
not_translated=Some content of the demo is not translated!
+message_format_example=Welcome {0} {1}!
diff --git a/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle_de.properties b/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle_de.properties
index 6b72675004..3b3b104445 100644
--- a/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle_de.properties
+++ b/tobago-example/tobago-example-demo/src/main/resources/org/apache/myfaces/tobago/example/demo/DemoBundle_de.properties
@@ -15,3 +15,4 @@
locale_short=de
not_translated=Einige Teile dieser Seite sind nicht in allen Sprachen verf\u00FCgbar.
+message_format_example=Willkommen {0} {1}!
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/020-output/10-out/Out.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/020-output/10-out/Out.xhtml
index 4e5738f507..eef6d94df3 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/020-output/10-out/Out.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/020-output/10-out/Out.xhtml
@@ -20,7 +20,8 @@
<ui:composition template="/main.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:tc="http://myfaces.apache.org/tobago/component"
- xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
+ xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core">
<p>The <code class="language-markup"><tc:out/></code> display an outputtext combined with a label.</p>
<tc:link label="Tag Library Documentation" image="#{request.contextPath}/image/feather-leaf.png"
@@ -66,6 +67,17 @@
<tc:out value="combination: deleted danger italic" markup="deleted danger italic"/>
</tc:segmentLayout>
</tc:section>
+ <tc:section label="Message Format">
+ Using message formatting for i18n strings.
+ <demo-highlight language="markup"><tc:out value="\#{demoBundle.message_format_example}" messageFormat="true">
+ <f:param value="Mrs"/>
+ <f:param value="Smith"/>
+</tc:out></demo-highlight>
+ <tc:out value="#{demoBundle.message_format_example}" messageFormat="true">
+ <f:param value="Mrs"/>
+ <f:param value="Smith"/>
+ </tc:out>
+ </tc:section>
<tc:section label="Escape">
<p>If the given string to the output field is HTML/XML code, it will be escaped by default.
But you can turn it off with the <code>escape</code> attribute.</p>