package sample.context; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.support.ResourceBundleMessageSource; /** * ResourceBundleに対する簡易アクセスを提供します。 * <p>本コンポーネントはAPI経由でのラベル一覧の提供等、i18n用途のメッセージプロパティで利用してください。 * <p>ResourceBundleは単純な文字列変換を目的とする標準のMessageSourceとは異なる特性(リスト概念)を * 持つため、別インスタンスでの管理としています。 * (spring.messageとは別に指定[extension.messages]する必要があるので注意してください) */ @ConfigurationProperties(prefix = "extension.messages") public class ResourceBundleHandler { private String encoding = "UTF-8"; private Map<String, ResourceBundle> bundleMap = new ConcurrentHashMap<>(); /** * 指定されたメッセージソースのResourceBundleを返します。 * <p>basenameに拡張子(.properties)を含める必要はありません。 */ public ResourceBundle get(String basename) { return get(basename, Locale.getDefault()); } public synchronized ResourceBundle get(String basename, Locale locale) { bundleMap.putIfAbsent(keyname(basename, locale), ResourceBundleFactory.create(basename, locale, encoding)); return bundleMap.get(keyname(basename, locale)); } private String keyname(String basename, Locale locale) { return basename + "_" + locale.toLanguageTag(); } /** * 指定されたメッセージソースのラベルキー、値のMapを返します。 * <p>basenameに拡張子(.properties)を含める必要はありません。 */ public Map<String, String> labels(String basename) { return labels(basename, Locale.getDefault()); } public Map<String, String> labels(String basename, Locale locale) { ResourceBundle bundle = get(basename, locale); return bundle.keySet().stream().collect(Collectors.toMap( key -> key, key -> bundle.getString(key))); } /** * SpringのMessageSource経由でResourceBundleを取得するFactory。 * <p>プロパティファイルのエンコーディング指定を可能にしています。 */ public static class ResourceBundleFactory extends ResourceBundleMessageSource { /** ResourceBundleを取得します。 */ public static ResourceBundle create(String basename, Locale locale, String encoding) { ResourceBundleFactory factory = new ResourceBundleFactory(); factory.setDefaultEncoding(encoding); return Optional.ofNullable(factory.getResourceBundle(basename, locale)) .orElseThrow(() -> new IllegalArgumentException("指定されたbasenameのリソースファイルは見つかりませんでした。[]")); } } }