Skip to content

Commit

Permalink
Qute message bundles - use locale from the selected variant if needed
Browse files Browse the repository at this point in the history
- resolves #14794
  • Loading branch information
mkouba committed Feb 3, 2021
1 parent 2d629a8 commit e2e5675
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import io.quarkus.qute.NamespaceResolver;
import io.quarkus.qute.Resolver;
import io.quarkus.qute.Template;
import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Variant;
import io.quarkus.qute.runtime.MessageBundleRecorder.BundleContext;

public final class MessageBundles {
Expand Down Expand Up @@ -81,10 +83,21 @@ static void setupNamespaceResolvers(@Observes EngineBuilder builder, BundleConte
public CompletionStage<Object> resolve(EvalContext context) {
Object locale = context.getAttribute(ATTRIBUTE_LOCALE);
if (locale == null) {
return defaultResolver.resolve(context);
Object selectedVariant = context.getAttribute(TemplateInstance.SELECTED_VARIANT);
if (selectedVariant != null) {
locale = ((Variant) selectedVariant).getLocale();
}
if (locale == null) {
return defaultResolver.resolve(context);
}
}
// First try the exact match
Resolver localeResolver = interfaces
.get(locale instanceof Locale ? ((Locale) locale).toLanguageTag() : locale.toString());
if (localeResolver == null && locale instanceof Locale) {
// Next try the language
localeResolver = interfaces.get(((Locale) locale).getLanguage());
}
return localeResolver != null ? localeResolver.resolve(context) : defaultResolver.resolve(context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand Down Expand Up @@ -184,7 +185,8 @@ private Template template() {
Variant selected = (Variant) getAttribute(TemplateInstance.SELECTED_VARIANT);
String id;
if (selected != null) {
id = variants.variantToTemplate.get(selected);
// Currently, we only use the content type to match the template
id = variants.getId(selected.getContentType());
if (id == null) {
id = variants.defaultTemplate;
}
Expand All @@ -206,14 +208,23 @@ public TemplateVariants(Map<Variant, String> variants, String defaultTemplate) {
this.defaultTemplate = defaultTemplate;
}

String getId(String contentType) {
for (Entry<Variant, String> entry : variantToTemplate.entrySet()) {
if (entry.getKey().getContentType().equals(contentType)) {
return entry.getValue();
}
}
return null;
}

@Override
public String toString() {
return "TemplateVariants{default=" + defaultTemplate + ", variants=" + variantToTemplate + "}";
}
}

private static Map<Variant, String> initVariants(String base, List<String> availableVariants, ContentTypes contentTypes) {
Map<Variant, String> map = new HashMap<>();
Map<Variant, String> map = new LinkedHashMap<>();
for (String path : availableVariants) {
if (!base.equals(path)) {
map.put(new Variant(null, contentTypes.getContentType(path), null), path);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.quarkus.qute.resteasy.deployment;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;

public class MessageBundleLocaleFromVariantTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(AppMessages.class, AppMessageHelloResource.class)
.addAsResource(new StringAsset(
"{msg:hello_name('Georg')}"),
"templates/hello.html")
.addAsResource(new StringAsset(
"hello=Hallo Welt!\nhello_name=Hallo {name}!"),
"messages/msg_de.properties"));

@Test
public void testMessageBundles() {
given().header("Accept-Language", "de-DE").when().get("/hello").then().body(is("Hallo Georg!"));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class VariantTemplateTest {
@Test
public void testVariant() {
given().when().accept("text/plain").get("/item/10").then().body(Matchers.is("Item foo: 10"));
given().when().get("/item/20").then().body(Matchers.is("<html><body>Item foo: 20</body></html>"));
given().when().accept("text/html").get("/item/20").then().body(Matchers.is("<html><body>Item foo: 20</body></html>"));
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.quarkus.resteasy.qute.runtime;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Locale;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
Expand All @@ -18,6 +19,7 @@
@Provider
public class TemplateResponseFilter implements ContainerResponseFilter {

@SuppressWarnings("unchecked")
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
Expand All @@ -30,24 +32,30 @@ public void filter(ContainerRequestContext requestContext, ContainerResponseCont
TemplateInstance instance = (TemplateInstance) entity;
Object variantsAttr = instance.getAttribute(TemplateInstance.VARIANTS);
if (variantsAttr != null) {
@SuppressWarnings("unchecked")
List<Variant> variants = (List<Variant>) variantsAttr;
List<javax.ws.rs.core.Variant> variants = new ArrayList<>();
for (Variant variant : (List<Variant>) variantsAttr) {
variants.add(new javax.ws.rs.core.Variant(MediaType.valueOf(variant.getMediaType()), variant.getLocale(),
variant.getEncoding()));
}
javax.ws.rs.core.Variant selected = requestContext.getRequest()
.selectVariant(variants.stream()
.map(v -> new javax.ws.rs.core.Variant(MediaType.valueOf(v.getMediaType()), v.getLocale(),
v.getEncoding()))
.collect(Collectors.toList()));
.selectVariant(variants);

if (selected != null) {
Locale selectedLocale = selected.getLanguage();
if (selectedLocale == null) {
List<Locale> acceptableLocales = requestContext.getAcceptableLanguages();
if (!acceptableLocales.isEmpty()) {
selectedLocale = acceptableLocales.get(0);
}
}
instance.setAttribute(TemplateInstance.SELECTED_VARIANT,
new Variant(selected.getLanguage(), selected.getMediaType().toString(), selected.getEncoding()));
new Variant(selectedLocale, selected.getMediaType().toString(), selected.getEncoding()));
mediaType = selected.getMediaType();
} else {
// TODO we should use the default
mediaType = null;
mediaType = responseContext.getMediaType();
}
} else {
// TODO how to get media type from non-variant templates?
mediaType = null;
mediaType = responseContext.getMediaType();
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class VariantTemplateTest {
@Test
public void testVariant() {
given().when().accept("text/plain").get("/item/10").then().body(Matchers.is("Item foo: 10"));
given().when().get("/item/20").then().body(Matchers.is("<html><body>Item foo: 20</body></html>"));
given().when().accept("text/html").get("/item/20").then().body(Matchers.is("<html><body>Item foo: 20</body></html>"));
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.quarkus.resteasy.reactive.qute.runtime;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;

import javax.ws.rs.container.ContainerResponseContext;
Expand All @@ -15,6 +17,7 @@

public class TemplateResponseFilter {

@SuppressWarnings("unchecked")
@ServerResponseFilter
public Uni<Void> filter(ResteasyReactiveContainerRequestContext requestContext, ContainerResponseContext responseContext) {
Object entity = responseContext.getEntity();
Expand All @@ -26,16 +29,24 @@ public Uni<Void> filter(ResteasyReactiveContainerRequestContext requestContext,
TemplateInstance instance = (TemplateInstance) entity;
Object variantsAttr = instance.getAttribute(TemplateInstance.VARIANTS);
if (variantsAttr != null) {
@SuppressWarnings("unchecked")
List<Variant> variants = (List<Variant>) variantsAttr;
List<javax.ws.rs.core.Variant> variants = new ArrayList<>();
for (Variant variant : (List<Variant>) variantsAttr) {
variants.add(new javax.ws.rs.core.Variant(MediaType.valueOf(variant.getMediaType()), variant.getLocale(),
variant.getEncoding()));
}
javax.ws.rs.core.Variant selected = requestContext.getRequest()
.selectVariant(variants.stream()
.map(v -> new javax.ws.rs.core.Variant(MediaType.valueOf(v.getMediaType()), v.getLocale(),
v.getEncoding()))
.collect(Collectors.toList()));
.selectVariant(variants);

if (selected != null) {
Locale selectedLocale = selected.getLanguage();
if (selectedLocale == null) {
List<Locale> acceptableLocales = requestContext.getAcceptableLanguages();
if (!acceptableLocales.isEmpty()) {
selectedLocale = acceptableLocales.get(0);
}
}
instance.setAttribute(TemplateInstance.SELECTED_VARIANT,
new Variant(selected.getLanguage(), selected.getMediaType().toString(), selected.getEncoding()));
new Variant(selectedLocale, selected.getMediaType().toString(), selected.getEncoding()));
mediaType = selected.getMediaType();
} else {
mediaType = responseContext.getMediaType();
Expand Down

0 comments on commit e2e5675

Please sign in to comment.