Skip to content

Commit d4064d0

Browse files
committed
Add MessageResolver
Provide how to change MessageResolver.
1 parent ead98cd commit d4064d0

32 files changed

Lines changed: 1494 additions & 0 deletions

testsuite/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@
133133
<groupId>net.sourceforge.htmlunit</groupId>
134134
<artifactId>htmlunit</artifactId>
135135
</dependency>
136+
137+
<!-- Thymeleaf API for custom resolvers in test code -->
138+
<dependency>
139+
<groupId>org.thymeleaf</groupId>
140+
<artifactId>thymeleaf</artifactId>
141+
<scope>provided</scope>
142+
</dependency>
136143
</dependencies>
137144

138145
<build>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package org.eclipse.krazo.test.ext.thymeleaf.custombasename;
20+
21+
import jakarta.ws.rs.ApplicationPath;
22+
import jakarta.ws.rs.core.Application;
23+
24+
import java.util.HashMap;
25+
import java.util.Map;
26+
27+
/**
28+
* Application with custom message basename configuration.
29+
*
30+
* @author Satoshi Seto
31+
*/
32+
@ApplicationPath("thymeleaf/custom-basename")
33+
public class CustomBasenameApplication extends Application {
34+
35+
@Override
36+
public Map<String, Object> getProperties() {
37+
Map<String, Object> map = new HashMap<>();
38+
// Set custom basename for message resolution
39+
map.put("org.eclipse.krazo.thymeleaf.messages.basename", "custom-messages");
40+
return map;
41+
}
42+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package org.eclipse.krazo.test.ext.thymeleaf.custombasename;
20+
21+
import jakarta.inject.Inject;
22+
import jakarta.mvc.Controller;
23+
import jakarta.mvc.Models;
24+
import jakarta.mvc.View;
25+
import jakarta.ws.rs.GET;
26+
import jakarta.ws.rs.Path;
27+
import jakarta.ws.rs.QueryParam;
28+
29+
import java.util.Locale;
30+
31+
/**
32+
* Controller for testing custom basename configuration.
33+
*
34+
* @author Satoshi Seto
35+
*/
36+
@Controller
37+
@Path("messages")
38+
public class CustomBasenameController {
39+
40+
@Inject
41+
private Models models;
42+
43+
@GET
44+
@View("custom-basename.html")
45+
public void showMessages(@QueryParam("name") String name, @QueryParam("lang") String lang) {
46+
if (name != null) {
47+
models.put("userName", name);
48+
}
49+
50+
if (lang != null) {
51+
models.put("locale", new Locale(lang));
52+
}
53+
}
54+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package org.eclipse.krazo.test.ext.thymeleaf.custombasename;
20+
21+
import jakarta.annotation.Priority;
22+
import jakarta.enterprise.context.ApplicationScoped;
23+
import jakarta.mvc.locale.LocaleResolver;
24+
import jakarta.mvc.locale.LocaleResolverContext;
25+
26+
import java.util.List;
27+
import java.util.Locale;
28+
29+
/**
30+
* Locale resolver for custom basename tests.
31+
*
32+
* @author Satoshi Seto
33+
*/
34+
@ApplicationScoped
35+
@Priority(1)
36+
public class CustomBasenameLocaleResolver implements LocaleResolver {
37+
38+
@Override
39+
public Locale resolveLocale(LocaleResolverContext context) {
40+
List<String> lang = context.getUriInfo().getQueryParameters().get("lang");
41+
42+
if (lang != null && !lang.isEmpty()) {
43+
return new Locale(lang.get(0));
44+
}
45+
46+
return null;
47+
}
48+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2018, 2019 Eclipse Krazo committers and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package org.eclipse.krazo.test.ext.thymeleaf.i18n;
20+
21+
import org.thymeleaf.context.ITemplateContext;
22+
import org.thymeleaf.messageresolver.AbstractMessageResolver;
23+
24+
import java.util.HashMap;
25+
import java.util.Locale;
26+
import java.util.Map;
27+
28+
/**
29+
* Example custom message resolver that resolves messages from an in-memory map.
30+
* This demonstrates how applications can provide their own message resolution logic
31+
* (e.g., from database, cache, external service, etc.)
32+
*
33+
* @author Satoshi Seto
34+
*/
35+
public class CustomMessageResolver extends AbstractMessageResolver {
36+
37+
private final Map<String, Map<Locale, String>> messages = new HashMap<>();
38+
39+
public CustomMessageResolver() {
40+
// Set highest priority (lowest order value)
41+
setOrder(0);
42+
initializeMessages();
43+
}
44+
45+
private void initializeMessages() {
46+
// English messages
47+
Map<Locale, String> customGreeting = new HashMap<>();
48+
customGreeting.put(Locale.ENGLISH, "Custom Hello from CDI!");
49+
customGreeting.put(Locale.JAPANESE, "CDIからのカスタムこんにちは!");
50+
messages.put("custom.greeting", customGreeting);
51+
52+
Map<Locale, String> customTitle = new HashMap<>();
53+
customTitle.put(Locale.ENGLISH, "Custom Application");
54+
customTitle.put(Locale.JAPANESE, "カスタムアプリケーション");
55+
messages.put("custom.title", customTitle);
56+
}
57+
58+
@Override
59+
public String resolveMessage(
60+
ITemplateContext context,
61+
Class<?> origin,
62+
String key,
63+
Object[] messageParameters) {
64+
65+
Map<Locale, String> localeMessages = messages.get(key);
66+
if (localeMessages == null) {
67+
return null;
68+
}
69+
70+
Locale locale = context.getLocale();
71+
String message = localeMessages.get(locale);
72+
73+
if (message == null) {
74+
// Fallback to English
75+
message = localeMessages.get(Locale.ENGLISH);
76+
}
77+
78+
return message;
79+
}
80+
81+
@Override
82+
public String createAbsentMessageRepresentation(
83+
ITemplateContext context,
84+
Class<?> origin,
85+
String key,
86+
Object[] messageParameters) {
87+
return null; // Delegate to next resolver
88+
}
89+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package org.eclipse.krazo.test.ext.thymeleaf.i18n;
20+
21+
import org.thymeleaf.context.ITemplateContext;
22+
import org.thymeleaf.messageresolver.AbstractMessageResolver;
23+
24+
import java.text.MessageFormat;
25+
import java.util.HashMap;
26+
import java.util.Locale;
27+
import java.util.Map;
28+
29+
/**
30+
* Second custom message resolver for testing multiple resolvers.
31+
* This resolver has lower priority (order=50) than CustomMessageResolver (order=0).
32+
*
33+
* @author Satoshi Seto
34+
*/
35+
public class CustomMessageResolver2 extends AbstractMessageResolver {
36+
37+
private static final Map<String, String> MESSAGES_EN = new HashMap<>();
38+
private static final Map<String, String> MESSAGES_JA = new HashMap<>();
39+
private static final Object[] EMPTY_MESSAGE_PARAMETERS = new Object[0];
40+
41+
static {
42+
// English messages (only resolved if CustomMessageResolver doesn't handle them)
43+
MESSAGES_EN.put("resolver2.message", "This is from CustomMessageResolver2");
44+
MESSAGES_EN.put("resolver2.greeting", "Hello from Resolver2, {0}!");
45+
MESSAGES_EN.put("custom.greeting", "This should NOT be used (Resolver2 has lower priority)");
46+
47+
// Japanese messages
48+
MESSAGES_JA.put("resolver2.message", "これはCustomMessageResolver2からです");
49+
MESSAGES_JA.put("resolver2.greeting", "Resolver2からこんにちは、{0}さん!");
50+
MESSAGES_JA.put("custom.greeting", "これは使われないはず(Resolver2は優先度が低い)");
51+
}
52+
53+
public CustomMessageResolver2() {
54+
// Lower priority than CustomMessageResolver (which has order=0)
55+
setOrder(50);
56+
}
57+
58+
@Override
59+
public String resolveMessage(
60+
ITemplateContext context,
61+
Class<?> origin,
62+
String key,
63+
Object[] messageParameters) {
64+
65+
Locale locale = context.getLocale();
66+
Map<String, String> messages = locale != null && locale.getLanguage().equals("ja")
67+
? MESSAGES_JA
68+
: MESSAGES_EN;
69+
70+
String message = messages.get(key);
71+
if (message == null) {
72+
return null;
73+
}
74+
75+
return formatMessage(locale, message, messageParameters);
76+
}
77+
78+
@Override
79+
public String createAbsentMessageRepresentation(
80+
ITemplateContext context,
81+
Class<?> origin,
82+
String key,
83+
Object[] messageParameters) {
84+
return null;
85+
}
86+
87+
private String formatMessage(Locale locale, String message, Object[] params) {
88+
if (message == null) {
89+
return null;
90+
}
91+
final MessageFormat messageFormat = new MessageFormat(message, locale);
92+
return messageFormat.format((params != null ? params : EMPTY_MESSAGE_PARAMETERS));
93+
}
94+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package org.eclipse.krazo.test.ext.thymeleaf.i18n;
20+
21+
import jakarta.enterprise.inject.Produces;
22+
import org.eclipse.krazo.engine.ViewEngineConfig;
23+
import org.thymeleaf.messageresolver.IMessageResolver;
24+
25+
/**
26+
* Producer for CustomMessageResolver2.
27+
* This demonstrates that multiple custom message resolvers can be registered.
28+
*
29+
* @author Satoshi Seto
30+
*/
31+
public class CustomMessageResolver2Producer {
32+
33+
@Produces
34+
@ViewEngineConfig
35+
public IMessageResolver createCustomMessageResolver2() {
36+
return new CustomMessageResolver2();
37+
}
38+
}

0 commit comments

Comments
 (0)