Localization and Internationalization
Jakob Jenkov |
If your application is to be ported to different languages you will need to be able to localize the components in your application. Butterfly Container can help you do that.
Instantiation and Execution Time Localization
When localizing a component you basically have two options:
Instantiation Time Localization
Instantiation time localization means that you inject localized dependencies
(texts, paths, number and date formatters etc.) into the component when it
is instantiated. The component doesn't have to know anything about Locale
or the localization mechanism used.
Furthermore, since resources are injected it is visible from the interface of the component
what resources it needs.
This makes instantiation time localization a nice and clean localization method.
In order for instantiation time localization to work the Locale
(language) to localize to must
be known when the component is instantiated. This is not always the case.
Execution Time Localization
Execution time localization means that the component obtains the localized dependencies
when it executes. For this to work the Locale
does not have to be known until
execution time. This is often the case for singletons that need to produce localized output
in different languages during the same runtime session. For instance, for a singleton component
in a web application, the language to localize to depends on the language chosen by the
current user. The singleton may serve requests for several users at the same time, each
with a different language selected.
Instantiation or Execution Time Localization?
Instantiation time localization is the cleanest way to localize your components, but execution time localization is the most flexible way, meaning it works for all situations. Of course you can use both methods in your application depending on the situation, but you risk that maintenance developers get confused about how a given component is localized.
Furthermore, instantiation time localization can lead to more messy configurations and code. If a component needs a lot of localized resources (texts and paths for instance), the configuration of that component factory in the container script grows quite large. In addition the component needs members (field + perhaps getters/setters) for those resources, so the component code may grow unnecessarily too.
Here is an instantiation time localization example:
//instantiation time localization example public class MyComponent{ String localText1 = null; String localText2 = null; public void setLocalText1(String text){ this.localText1 = text; } public void setLocalText2(String text){ this.localText2 = text; } public void execute(...){ //output the localized texts, localText1 and localText2 System.out.print(localText1); System.out.print(localText2); } }
Here is the butterfly container script for the MyComponent
configuration:
myComponent = * com.myapp.MyComponent().setLocalText1(...) .setLocalText2(...);
As you can imagine, the more resources the MyComponent
needs, the larger
both the class and the configuration grows. The advantage is that you can see
from the configuration exactly what dependencies the MyComponent
has.
Here is the same example using execution time localization:
public class MyComponent{ Resources resources = null; public MyComponent(Resources resources){ this.resources = resources; } public void execute(...){ Locale locale = ... //obtain locale for this request System.out.println(resources.get("localText1").get(locale)); System.out.println(resources.get("localText2").get(locale)); } }
And here is the butterfly container script configuration for it:
myComponent = * com.myapp.MyComponent(resources);
As you can imagine, only the execute()
method will
grow as the number of localized dependencies grow. All localized
dependencies are obtained from the Resources
object.
This makes execution time localization a less verbose localization
method. The downside is that it leads to hidden dependencies.
You can no longer see from the interface or configuration of
MyComponent
exactly what localized resources it needs.
Note, that this Resources
object still needs to be
configured somehow, but this configuration is left out of the
example.
Which of the two methods you choose is up to you. Personally I think execution time localization is the simplest mechanism to use, and being the most flexible, working for singletons, flyweights, cached objects etc, it can be applied across all components in your application.
Tweet | |
Jakob Jenkov |