-
Notifications
You must be signed in to change notification settings - Fork 16
Features
This documents version 0.5. You can see sample usages here
When you .getMessage()
from a MessageBundle
, the current JVM locale is tried first, then other, more generic locales are tried. For instance, if your locale is ja_JP_JP
, the following locales are tried in order:
-
ja_JP_JP
; -
ja_JP
; -
ja
; - the root locale (
Locale.ROOT
in Java parlance).
You can also specify the locale you want using dedicated methods.
A MessageBundle
works as follows when trying to find a message for a given locale/key pair:
- it loops through all of its registered
MessageSourceProvider
s in order (see below); - for one provider, it tries and sees if it has a
MessageSource
for this locale; - if one is found, it queries the source for the key.
You can implement these interfaces the way you want. The implementation provides two implementations of MessageSourceProvider
(one including dynamic lookup with caching and configurable timeout and expiry) and two implementations of MessageSource
, including one to read from property files.
And as to property files...
This is unlike the JDK's ResourceBundle
, which reads property files in ISO-8859-1.
Using the builder class for a MessageBundle
, you can append or prepend message providers:
MessageProvider p1, p2, p3;
MessageBundleBuilder builder = MessageBundle.newBuilder();
builder = builder.appendProvider(p1).appendProvider(p2); // Order is now: p1 -> p2
builder = builder.prependProvider(p3); // Order is now: p3 -> p1 -> p2
// Build the final bundle
final MessageBundle bundle = builder.build();
Note that MessageBundle
s are immutable. However, You can reuse an existing one and extend it:
MessageProvider p4;
// New bundle with order p3 -> p1 -> p2 -> p4
final MessageBundle newBundle = bundle.thaw().appendProvider(p4).freeze();
This is unlike a ResourceBundle
, which, in this case, throws an (unchecked!!) exception. In the event when a key does not exist, the key itself is returned. This allows for more graceful failures, and an easy spotting of missing keys.
Example:
final Map<String, String> map = new HashMap<String, String>();
map.put("foo", "bar");
final MessageSource source = new MapMessageSource(map);
// .appendSource() is a convenience method to append a provider with a single source for all locales
final MessageBundle bundle = MessageBundle.newBuilder().appendSource(source).freeze();
bundle.getKey("foo"); // returns "bar"
bundle.getKey("baz"); // returns "baz"
ServiceLoader support
You can now automatically register bundles using this API. For this, you need to have one or more implementation(s) of com.github.fge.msgsimple.serviceprovider.MessageBundleProvider
and register them where appropriate.
See here for a good, detailed explanation. Also note that there is a Maven plugin which can generate the appropriate file in your build output directory for you.
One thing a ResourceBundle
does not support! You can use format strings in your property files and use the available .printf()
methods on a bundle to get a message just like what String.format()
does.
There are two family of assertion methods: null checks and condition checks. Failure of a null check throws a NullPointerException
; failure of a condition check throws an IllegalArgumentException
. In both cases, the message associated with the exception is looked up/built in the same way as regular messages. For instance:
bundle.checkNotNull(foo, "cfg.error.nullFoo");
bundle.checkNotNullPrintf(bar, "cfg.error.nullBar", arg1, arg2);
bundle.checkArgument(cond1, "cfg.cond.fail1");
bundle.checkArgumentPrintf(cond2, "cfg.cond.fail2", arg);