|
20 | 20 | */ |
21 | 21 | package eu.openanalytics.containerproxy.util; |
22 | 22 |
|
23 | | -import org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration; |
24 | | -import org.springframework.boot.autoconfigure.context.MessageSourceProperties; |
25 | | -import org.springframework.boot.context.properties.EnableConfigurationProperties; |
26 | | -import org.springframework.context.MessageSource; |
27 | | -import org.springframework.context.MessageSourceResolvable; |
28 | | -import org.springframework.context.NoSuchMessageException; |
| 23 | +import eu.openanalytics.containerproxy.service.LanguageService; |
| 24 | +import org.apache.commons.lang3.StringUtils; |
| 25 | +import org.jspecify.annotations.Nullable; |
| 26 | +import org.springframework.boot.context.properties.bind.Bindable; |
| 27 | +import org.springframework.boot.context.properties.bind.Binder; |
| 28 | +import org.springframework.context.support.AbstractMessageSource; |
| 29 | +import org.springframework.context.support.ResourceBundleMessageSource; |
| 30 | +import org.springframework.core.env.Environment; |
29 | 31 | import org.springframework.stereotype.Component; |
30 | | -import org.thymeleaf.util.StringUtils; |
31 | 32 |
|
32 | 33 | import javax.annotation.Nonnull; |
| 34 | +import java.text.MessageFormat; |
| 35 | +import java.util.HashMap; |
33 | 36 | import java.util.Locale; |
| 37 | +import java.util.Map; |
| 38 | +import java.util.ResourceBundle; |
| 39 | +import java.util.stream.Collectors; |
34 | 40 |
|
35 | 41 | @Component("messageSource") |
36 | | -@EnableConfigurationProperties(MessageSourceProperties.class) |
37 | | -public class CustomMessageSource implements MessageSource { |
| 42 | +public class CustomMessageSource extends AbstractMessageSource { |
38 | 43 |
|
39 | | - private MessageSource delegate; |
| 44 | + private static final String PROP_PROXY_TRANSLATION_OVERRIDES = "proxy.translation-overrides"; |
| 45 | + private final Map<String, Map<String, String>> translationOverrides = new HashMap<>(); |
| 46 | + private final Map<String, Map<String, MessageFormat>> translationOverridesMessageFormat = new HashMap<>(); |
40 | 47 |
|
41 | | - public CustomMessageSource(MessageSourceProperties properties) { |
42 | | - MessageSourceAutoConfiguration autoConfiguration = new MessageSourceAutoConfiguration(); |
43 | | - this.delegate = autoConfiguration.messageSource(properties); |
| 48 | + public CustomMessageSource(Environment environment, LanguageService languageService) { |
| 49 | + ResourceBundleMessageSource parentMessageSource = new CapitalizedMessageSource(); |
| 50 | + parentMessageSource.setBasenames("messages", "cp_messages"); |
| 51 | + parentMessageSource.setAlwaysUseMessageFormat(true); |
| 52 | + setParentMessageSource(parentMessageSource); |
| 53 | + |
| 54 | + // read overridden translations from config file |
| 55 | + for (String language : languageService.getEnabledLanguages().keySet()) { |
| 56 | + Map<String, String> messages = getTranslationOverrides(environment, language); |
| 57 | + translationOverrides.put(language, messages); |
| 58 | + translationOverridesMessageFormat.put(language, convertToMessageFormat(messages, language)); |
| 59 | + } |
44 | 60 | } |
45 | 61 |
|
46 | 62 | @Override |
47 | | - public String getMessage(@Nonnull String code, Object[] args, String defaultMessage, @Nonnull Locale locale) { |
48 | | - return StringUtils.capitalize(delegate.getMessage(code, args, defaultMessage, locale)); |
| 63 | + protected @Nullable String resolveCodeWithoutArguments(@Nonnull String code, @Nonnull Locale locale) { |
| 64 | + if (translationOverrides.containsKey(locale.getLanguage())) { |
| 65 | + return translationOverrides.get(locale.getLanguage()).get(code); |
| 66 | + } |
| 67 | + return null; |
49 | 68 | } |
50 | 69 |
|
51 | 70 | @Override |
52 | | - public String getMessage(@Nonnull String code, Object[] args, @Nonnull Locale locale) throws NoSuchMessageException { |
53 | | - return StringUtils.capitalize(delegate.getMessage(code, args, locale)); |
| 71 | + protected @Nullable MessageFormat resolveCode(@Nonnull String code, @Nonnull Locale locale) { |
| 72 | + if (translationOverrides.containsKey(locale.getLanguage())) { |
| 73 | + return translationOverridesMessageFormat.get(locale.getLanguage()).get(code); |
| 74 | + } |
| 75 | + return null; |
54 | 76 | } |
55 | 77 |
|
56 | | - @Override |
57 | | - public String getMessage(@Nonnull MessageSourceResolvable resolvable, @Nonnull Locale locale) throws NoSuchMessageException { |
58 | | - return StringUtils.capitalize(delegate.getMessage(resolvable, locale)); |
| 78 | + private Map<String, String> getTranslationOverrides(Environment environment, String language) { |
| 79 | + return Binder.get(environment) |
| 80 | + .bind(PROP_PROXY_TRANSLATION_OVERRIDES + "." + language, Bindable.mapOf(String.class, String.class)) |
| 81 | + .orElse(new HashMap<>()); |
| 82 | + } |
| 83 | + |
| 84 | + private Map<String, MessageFormat> convertToMessageFormat(Map<String, String> messages, String language) { |
| 85 | + Locale locale = Locale.forLanguageTag(language); |
| 86 | + return messages.entrySet().stream().collect(Collectors.toMap( |
| 87 | + Map.Entry::getKey, |
| 88 | + e -> new MessageFormat(StringUtils.capitalize(e.getValue()), locale)) |
| 89 | + ); |
| 90 | + } |
| 91 | + |
| 92 | + private static class CapitalizedMessageSource extends ResourceBundleMessageSource { |
| 93 | + |
| 94 | + /** |
| 95 | + * Capitalizes the first letter of each string. Because this low-level method |
| 96 | + * is overridden, the strings are still properly cached. |
| 97 | + * |
| 98 | + * @param bundle the ResourceBundle to perform the lookup in |
| 99 | + * @param key the key to look up |
| 100 | + * @return the associated value, or {@code null} if none |
| 101 | + */ |
| 102 | + @Override |
| 103 | + protected @Nullable String getStringOrNull(@Nonnull ResourceBundle bundle, @Nonnull String key) { |
| 104 | + String result = super.getStringOrNull(bundle, key); |
| 105 | + if (result != null) { |
| 106 | + return StringUtils.capitalize(result); |
| 107 | + } |
| 108 | + return null; |
| 109 | + } |
| 110 | + |
59 | 111 | } |
60 | 112 |
|
61 | 113 | } |
0 commit comments