About the I18N Framework

This module provides a framework for embedding and using localizable messages in applications. It includes the following sub-modules:

  • i18n-maven-plugin : A Maven plugin which generates I18N messages from property files.
  • i18n-core : Core Java APIs for embedding and using localizable messages in applications.
  • i18n-jul : An interface for efficiently writing localized messages out to a Java Logger.
  • i18n-slf4j : An interface for efficiently writing localized messages out to a SLF4J Logger.

Usage

This page provides instructions on how to use the I18N Framework.

Create a properties file

Before using the I18N framework you first need to define some localizable messages. Lets create the properties file "src/main/resources/com/example/my_tool.properties"" containing the single property "PURCHASE_ITEM":

PURCHASE_ITEM=Purchasing "%s" for %d %s?

This property has three parameters: the item name, the price (float), and the currency string.

Localized versions of the property file should be created next and these should be named such that the locale appears before the ".properties" suffix. For example, the file "my_tool_fr.properties" should contain the same messages localized in French.

Prepare your pom.xml for the I18N Framework

In order to use the I18N Framework you'll need to ensure that the ForgeRock repositories are listed in your pom.xml file:

<repositories>
  <repository>
    <id>forgerock-staging-repository</id>
    <name>ForgeRock Release Repository</name>
    <url>http://maven.forgerock.org/repo/releases</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
  <repository>
    <id>forgerock-snapshots-repository</id>
    <name>ForgeRock Snapshot Repository</name>
    <url>http://maven.forgerock.org/repo/snapshots</url>
    <releases>
      <enabled>false</enabled>
    </releases>
  </repository>
<repositories>
<pluginRepositories>
  <pluginRepository>
    <id>forgerock-plugins-repository</id>
    <name>ForgeRock Plugin Repository</name>
    <url>http://maven.forgerock.org/repo/repo</url>
  </pluginRepository>
</pluginRepositories>

Generate the message descriptors using the Maven plugin

The next step is to generate the messages descriptors using the I18N Maven Plugin. Add the following lines to your Maven pom.xml file:

<build>
  <plugins>
    <plugin>
      <groupId>org.forgerock.commons</groupId>
      <artifactId>i18n-maven-plugin</artifactId>
      <version>1.4.3-SNAPSHOT</version>
      <executions>
        <execution>
          <phase>generate-sources</phase>
          <goals>
            <goal>generate-messages</goal>
          </goals>
          <configuration>
            <messageFiles>
              <messageFile>com/example/my_tool.properties</messageFile>
            </messageFiles>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

It is possible to process many message files in one go. Note that you only need to reference the non-localized message file.

After saving the changes to the pom.xml file, generate the message descriptors by invoking "mvn generate-sources". Once mvn completes you should find that a new Java source file has been generated and put in "target/generated-sources/messages/com/example/MyToolMessages.java".

NOTE: depending on your IDE, you may need to explicitly configure "target/generated-sources/messages" as a source folder for your project.

Once generated, the MyToolMessages.java should look like this:

package com.example;

import org.forgerock.i18n.LocalizableMessageDescriptor;

/**
 * This file contains localizable message descriptors having the resource
 * name {@code com.example.my_tool}. This file was generated
 * automatically by the {@code i18n-maven-plugin} from the property file
 * {@code com/example/my_tool.properties} and it should not be manually edited.
 */
public final class MyToolMessages
{
  // The name of the resource bundle.
  private static final String RESOURCE = "com.example.my_tool";

  // Prevent instantiation.
  private MyToolMessages()
  {
    // Do nothing.
  }
  
  /**
   * Returns the name of the resource associated with the messages contained
   * in this class. The resource name may be used for obtaining named loggers,
   * e.g. using SLF4J's {@code org.slf4j.LoggerFactory#getLogger(String name)}.
   *
   * @return The name of the resource associated with the messages contained
   *         in this class.
   */
  public String resourceName()
  {
    return RESOURCE;
  }

  /**
   * Purchasing "%s" for %d %s?
   */
  public static final LocalizableMessageDescriptor.Arg2<CharSequence,Number,CharSequence> PURCHASE_ITEM =
          new LocalizableMessageDescriptor.Arg2<CharSequence,Number,CharSequence>(MyToolMessages.class,RESOURCE,"PURCHASE_ITEM",-1);

}

Use the generated message from within your application

Now that the message descriptors are generated, you can reference them directly from within your application code. First though you need to declare a dependency on the I18N Framework core APIs in your pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.forgerock.commons</groupId>
    <artifactId>i18n-core</artifactId>
    <version>1.4.3-SNAPSHOT</version>
  </dependency>
</dependencies>

The following example shows how the generated messages may be used:

import org.forgerock.i18n.LocalizableMessage;

import java.util.Locale;
import java.util.logging.Logger;
import java.util.logging.Level;
        
// Messages generated using i18n-maven-plugin.         
import com.example.MyToolMessages;
import static com.example.MyToolMessages.PURCHASE_ITEM;

// Create a parameterized error message: PURCHASE_ITEM is the descriptor for
// the message "Purchasing "%s" for %d %s?" and it will be strongly
// typed <String, Number, String>, so invalid message parameters will
// result in a compilation error.
String item     = "bicycle";
float price     = 199.99;
String currency = "USD";

LocalizableMessage message = PURCHASE_ITEM.get(item, price, currency);

// Get a logger for this tool (the resource name can be used in order to
// categorize messages) and log the message using the US locale. Note that
// Java logging integration can make this easier - see below.
Logger logger = Logger.getLogger(MyToolMessages.resourceName());
logger.log(Level.INFO, message.toString(Locale.US));

// Now display the message to the user in their locale.
System.out.println(message.toString()); // Default locale.

Clean up unused messages

As your project gets bigger the property files will become harder to maintain. Whilst missing messages will be spotted very quickly due to the resulting compilation failures, tracking unused messages can become quite difficult. Not only that, but unused messages waste localization effort.

Help is at hand through the use of the I18N Maven plugin's clean-messages goal which can be invoked as follows:

mvn org.forgerock.commons:i18n-maven-plugin:1.4.3-SNAPSHOT:clean-messages -DmessageFile=src/main/resources/com/example/my_tool.properties

Java logging integration

If your application needs to log localized messages to a java.util.logging.Logger then consider using the i18n-jul module. To use the i18n-jul module include the following dependency in your pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.forgerock.commons</groupId>
    <artifactId>i18n-jul</artifactId>
    <version>1.4.3-SNAPSHOT</version>
  </dependency>
</dependencies>

The following example shows how the I18N Java Logging module may be used to log a localized message:

import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.jul.LocalizedLogger;
        
// Message generated using i18n-maven-plugin.        
import static com.example.MyMessages.MY_MESSAGE;

// Get a localized logger wrapping A Java Logger for the current
// class and the default locale.
LocalizedLogger logger = LocalizedLogger.getLocalizedLogger(this.class.getName());
        
// Log a parameterized error message.
LocalizableMessage message = MY_MESSAGE.get("a message parameter");
logger.warning(message);
        
// This is more efficient because it will only construct (format) the
// message if error logging is enabled for this logger.
logger.warning(MY_MESSAGE, "a message parameter");

SLF4j integration

If your application needs to log localized messages to SLF4J then consider using the i18n-slf4j module. To use the i18n-slf4j module include the following dependency in your pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.forgerock.commons</groupId>
    <artifactId>i18n-slf4j</artifactId>
    <version>1.4.3-SNAPSHOT</version>
  </dependency>
</dependencies>

The following example shows how the I18N SLF4J module may be used to log a localized message:

import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
        
// Message generated using i18n-maven-plugin.        
import static com.example.MyMessages.MY_MESSAGE;

// Get a localized logger wrapping the SLF4J logger for the current
// class for the default locale.
LocalizedLogger logger = LocalizedLogger.getLocalizedLogger(this.class);
        
// Log a parameterized error message.
LocalizableMessage message = MY_MESSAGE.get("a message parameter");
logger.error(message);
        
// This is more efficient because it will only construct (format) the
// message if error logging is enabled for this logger.
logger.error(MY_MESSAGE, "a message parameter");