Internationalization and Static Resources - StrangeSkies/uk.co.strangeskies GitHub Wiki

A simple internationalization and static property resource loading strategy is provided via the uk.co.strangeskies.text library bundle. This library is designed to overcome some of the problems which are typical of such systems.

##Providers

Developers of internationalized bundles and applications need only specify one or more simple Java "properties interfaces" whose methods correspond to properties, their signatures indicating the type of localized content which should be available. The system will automatically provide an implementation of this interface at runtime which defers method invocations to an appropriate resource resolution strategy.

When using the default resource strategy, providers of localized content then only need to make a .properties file available on the same class loader as the interface it corresponds to. File names should be modified as per the ResourceBundle rules for resolving resources according to locale. In an OSGi application there are some simple caveats and augmentations.

A typical properties interface may looks something like the following:

package foo.bar;

import uk.co.strangeskies.text.properties.Localized;

public interface MyApplicationProperties {
	Localized<String> applicationTitle();

	Localized<String> welcomeMessage(String userName);

	Localized<String> goodbyeMessage(String userName);

	LocalDate copyrightYear();

	String companyName();
}

In general there are no restrictions on the form of the class other than that it be an interface. The mechanism for parsing a string resource into an appropriate Object or value is determined by the return type of a method, including annotations on the type. In some cases it may be necessary to attach a custom parser to the property loader used to instantiate the interface.

No configuration annotations are present in this example, so the default resource strategy configuration is used. This means that the root locale resource should be placed at foo/bar/MyApplication.properties and contain the following entries:

MyApplication/applicationTitle = My Application Title
MyApplication/welcomeMessage = Hello, %s!
MyApplication/goodbyeMessage = See you soon, %s.
MyApplication/companyName = FooBar

(Here the word Properties is stripped from the end of the class name. If the class name does not end with this string it will be left as is.)

The Localized class described in more detail in the next section, but essentially marks the property as localizable. In this example, the company does not consider it's name, or the copyright year, to be internationalizable content and so it is a plain string. Properties which are not localized are loaded from the root locale only.

##Consumers

Consumers obtain usable instances of a properties interface via implementations of uk.co.strangeskies.text.properties.PropertyLoader, which can be instantiated via static methods on the interface or consumed as a service in OSGi. A property loader has a locale attached to it which may change depending on the implementation.

The PropertyLoader.getProperties method then reflectively defines an implementation for the interface and returns an instantiation.

The generic Localized class is parameterized with the type of the property to localize. It is observable over the localized value, which is loaded and parsed each time the locale changes. It is also possible to request the value for any other locale than the current one via the interface.

Method invocation arguments are interpreted according to the parser type. For String properties they are simply substituted according to the String.format(String, Object[]) method.

For the above example this would give the following results:

MyApplicationProperties props = PropertyLoader.getDefaultProperties(MyApplicationProperties.class); // a convenience method
System.out.println(props.welcomeMessage("John")); // Hello, John!

##Resource Resolution

##Configuration

##Features

###Refactoring

Refactoring is far simpler than strategies which use plain strings as keys. When a key must be changed or removed the associated method is simply renamed or removed at the same time, which can be neatly and reliably taken care of by any IDE without leaving any hanging references to the key.

It is also possible to find potentially obsolete properties by searching for unused methods.

###Immutable

Many similar alternatives which also solve the refactoring problem do so by injecting localized strings into either static or instance fields. Since these fields values must be populated externally by some sort of resource loading or translation service they cannot be final and so clients are free to violate the intended usage contract and modify the values.

By using abstract methods as the API surface for retrieving values we ensure that mutation is not possible.

###Dynamic

Since the Localized class extends ObservableValue, with events triggered by locale changes, it is trivial to design interfaces which react dynamically to these changes.

###OSGi and Eclipse Support

Attaching extra localizations in an OSGi application then typically involves attaching fragment bundles to the bundle containing the root locale .properties file.

###Custom Parsing

⚠️ **GitHub.com Fallback** ⚠️