-
Notifications
You must be signed in to change notification settings - Fork 9
Using I18N4Vaadin with CDI
This page will explain how to install and use I18N4Vaadin 2.0 in a Vaadin 7 project that uses CDI. Although I18N4Vaadin itself does not require it, I recommend you use the Vaadin CDI Add-on to configure your UIs and views.
You will need to add the following JARs to your project's compile time and runtime classpaths:
-
i18n4vaadin-api-2.x.x.jar
- the annotations and interfaces you will be using in your application -
i18n4vaadin-cdi-2.x.x.jar
- the classes that provide CDI support
In addition, the annotation processor JAR i18n4vaadin-cdi-ap-2.x.x.jar
needs to be available on
the classpath during compilation. It is not, however, required during runtime. Also note that the annotation processor requires some additional libraries. Maven will download them automatically.
The first thing you need to do is to enable I18N4Vaadin in your Vaadin UI
. You do this by injecting
an instance of the I18N
interface. This instance contains information about the supported locales and
the currently selected locale. It is also used to change the locale.
The I18N instance is session scoped, meaning that multiple UI instances will use the same I18N instance (and thus the same locale).
It is possible to define supported locales in two ways: by using an annotation or by using code (the I18N.setSupportedLocales(Collection<Locale>)
method).
@VaadinUI
@Root
public class MyUI extends UI {
@I18nSupportedLocales({@Locale(language = "sv"), @Locale(language = "fi")})
@Inject
private I18N i18n;
@Override
protected void init(VaadinRequest request) {
// ...
}
// ...
}
In the example above, the supported locales will be sv
and fi
and the current locale
will be automatically set to the first locale in the list, i.e. sv
.
Now, it is time to add some messages by using the @Message
or @Messages
annotations. These annotations
can be placed on any class - it does not have to be a Vaadin class.
@VaadinView(value = "myView")
public class MyView extends CustomComponent implements View {
@Message(key = "resourceNotAvailable", value = "Resursen {0} är inte tillgänglig för alarmering")
private void aMethod(Resource resource) {
// ...
}
@Messages({
@Message(key = "ticketModifiedException", value = "Uppdraget har ändrats av en annan användare. Informationen har nu uppdaterats."),
@Message(key = "ticketClosedException", value = "Uppdraget har avslutats och kan inte längre ändras."),
@Message(key = "noSuchTicketException", value = "Uppdraget kunde inte hittas i databasen."),
@Message(key = "ticketSaved", value = "Uppdragsinformationen har sparats i databasen.")
})
private void anotherMethod() {
// ...
}
// ...
}
The messages should be written in the default language of your application - in this case Swedish. Also note, that you can use indexed parameters ({0}
, {1}
, etc)
in the message strings.
The annotation processor takes one configuration parameter:
-
bundleperclass=true|false
: If true, one bundle per annotated class will be generated. If false, one bundle per package will be generated (the default).
Please note, that it is best to always specify the parameters explicitly since the default values might change before the final release. For example, to generate
one bundle per class, pass the following option to the Java compiler: -Abundleperclass=true
If you are using Maven, you can use the CDI demo application as an example.
After you have compiled your project, you will now find a few auto-generated files in the same package as the annotated class (your IDE has probably placed them in a separate directory, though, since you should not commit them into your source code repository).
First, you will find a message bundle file MyViewmessages.properties
(i.e. the class name appended with messages.properties
)
that looks something like this:
#Auto-generated by com.github.peholmst.i18n4vaadin.ap.BundleFileGenerator
#Thu Feb 28 15:28:45 EET 2013
ticketModifiedException=Uppdraget har ändrats av en annan användare. Informationen har nu uppdaterats.
ticketSaved=Uppdragsinformationen har sparats i databasen.
ticketClosedException=Uppdraget har avslutats och kan inte längre ändras.
resourceNotAvailable=Resursen {0} är inte tillgänglig för alarmering
noSuchTicketException=Uppdraget kunde inte hittas i databasen.
Second, you will find a Java class file MyViewBundle.java
(i.e. the class name appended with Bundle.java
) that looks something like this:
Generated(value = "com.github.peholmst.i18n4vaadin.ap.JavaFileGenerator", date = "2013-02-28T15:28:45+0200")
@SessionScoped
public class MyViewBundle implements java.io.Serializable {
// ...
public String resourceNotAvailable(Object... args) {
return getMessage("resourceNotAvailable", args);
}
public String ticketClosedException(Object... args) {
return getMessage("ticketClosedException", args);
}
public String ticketModifiedException(Object... args) {
return getMessage("ticketModifiedException", args);
}
public String noSuchTicketException(Object... args) {
return getMessage("noSuchTicketException", args);
}
public String ticketSaved(Object... args) {
return getMessage("ticketSaved", args);
}
public static final class Keys {
private Keys() {
}
public static final String resourceNotAvailable = "resourceNotAvailable";
public static final String ticketClosedException = "ticketClosedException";
public static final String ticketModifiedException = "ticketModifiedException";
public static final String noSuchTicketException = "noSuchTicketException";
public static final String ticketSaved = "ticketSaved";
}
public String getMessage(String key, Object... args) {
// ...
}
public static String getMessage(String key, Locale locale, Object... args) {
// ...
}
}
Now you can inject this session scoped bundle instance into your view like this:
@Inject
MyViewBundle bundle;
... and start using your translated strings:
Notification.show(bundle.noSuchTicketException(), Notification.Type.WARNING_MESSAGE);
Notification.show(bundle.resourceNotAvailable("MyResource"));
Once your application is working in the default language, make copies of all the generated
text bundle files and add the proper locale suffixes (i.e. MyViewmessages_fi.properties
).
Then translate the contents of your copied files. Also remember to commit your translations
into your source code repository.
You change the language of your application by invoking the setLocale(Locale)
method of the I18N
instance.
If you are doing this on the fly, you have to remember to update all your UI components since this is not something
I18N4Vaadin can do automatically.
The easiest way of doing this is probably to have your views listen for the LocaleChangedEvent
fired by the I18N
instance. This event is fired
both as a CDI event and to registered LocaleChangedListener
s, but due to how the Vaadin CDI add-on works, you will have to use the latter approach since for example
the views in Vaadin CDI are dependent scoped. See the CDI demo application for details.