Usages
2009-08-22

How it works

The i18n plugin works in at least two phases :

  • first, it parses some sources to build for each bundle a called getter file which contains all keys found in sources.
  • in a second time, the getter files are merged with the existing translations files.
  • at last, we can make a optimized bundle which merge the module i18n with all his dependencies (this is good idea when the module is a final application... see below section)

directory layout

Here is the directory layout convention used by the plugin

mymodule/
|-- src
|   `-- main
|       `-- resources
|           `-- i18n
|               |-- mymodule-en_GB.properties
|               `-- mymodule-fr_FR.properties
`-- target
    |-- classes
    |   `-- META-INF
    |       |-- mymodule-en_GB.properties
    |       |-- mymodule-fr_FR.properties
    |       `-- mymodule-i18n-definition.properties
    `-- generated-sources
        `-- i18n
            |-- mymodule-en_GB.properties
            `-- mymodule-fr_FR.properties

Parse files

The plugin offers some build-in parsers, each parser has his goal prefix by parser :

  • parserJava : parse some java source files to detect I18n._ and I18n.n_ invocations in code
  • parserValidation : parse some xWorks validation files

    Each parser goal has some default values, if you respect the plugin conventions, you should have nothing to configure.

    <plugin>
        <groupId>org.nuiton.i18n</groupId>
        <artifactId>i18n-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>parserJava</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    will parse all java files in src/main/java and will generate the getter files in target/generated-sources/i18n.

    Moreover, it is possible to defined more directories to be scanned, like in next example, where we also scan the src/main/java2 :

    <plugin>
        <groupId>org.nuiton.i18n</groupId>
        <artifactId>i18n-maven-plugin</artifactId>
        <configuration>
            <entries>
                <entry>
                    <basedir>src/main/java2/</basedir>
                </entry>
            </entries>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>parserJava</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    The entries can be more complex.

    For example, it is possible to filter via some includes/excludes, or attach the entry only for a specific parser via the specificGoal property.

    When using an entry, the default entry for the parser is not used, but it can be activated via the treateDefaultEntry property.

    <plugin>
        <groupId>org.nuiton.i18n</groupId>
        <artifactId>i18n-maven-plugin</artifactId>
        <configuration>
            <treateDefaultEntry>true</treateDefaultEntry>
            <entries>
                <entry>
                    <basedir>src/main/java2/</basedir>
                    <includes>
                      <include>**/*.guix</include>
                    </includes>
                    <specificGoal>parserJaxx</specificGoal>
                </entry>
            </entries>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>parserJava</goal>
                    <goal>parserJaxx</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    Consult the javadoc of the org.nuiton.util.SourceEntry class in maven-helper-plugin library.

Build bundles

After the files were parsed, it is time to build the i18n bundles of the module.

  • The default location of those files are in src/main/resources/i18n.
  • The default file names of the bundles are artifactId-bundle.properties

The gen goal

the gen goal rebuild those files, using the getter files previously builded.

<plugin>
    <groupId>org.nuiton.i18n</groupId>
    <artifactId>i18n-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>gen</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The bundle goal

The bundle goal build the bundles for a final application which aggregate all i18n bundles of all dependencies of the module.

This is a good idea to do it, since the loading of the runtime i18n system is much more faster with only one file to deal with.

The final bundles builded will be placed directly in target/classes/META-INF since this is an only runtime bundle and it should never to add in module's sources.

<plugin>
    <groupId>org.nuiton.i18n</groupId>
    <artifactId>i18n-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>bundle</goal>
            </goals>
        </execution>
    </executions>
</plugin>

All in one

<plugin>
    <groupId>org.nuiton.i18n</groupId>
    <artifactId>i18n-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>parserJava</goal>
                <goal>gen</goal>
                <goal>bundle</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Csv Bundle (since 3.3)

Generate a csv bundle

You can generate a single csv file with the bundles via the generate-csv-bundle (after a bundle invocation).

<plugin>
    <groupId>org.nuiton.i18n</groupId>
    <artifactId>i18n-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>bundle</goal>
                <goal>generate-csv-bundle</goal>
            </goals>
        </execution>
    </executions>
</plugin>

You can then give the csv file to people to edit it.

Split or merge a csv bundle

Having them the csv file filled by people you can then split it back to some i18n bundle files with the split-csv-bundle mojo.

Event better you can merge it back to the i18n files of a module using the merge-back-csv-bundle mojo.

And there is more for you!

There is some other interesting properties in the plugin, for example it is possible to translate the new i18n key detected while parsing via a swing ui.

Generate I18n keys for enumerations (since 3.6)

You can generate a java file, with i18n keys based on some enumerations constants.

To do this, you need to describe how to generate i18n keys from you enumeration.

The following example explains how to do this:

<plugin>
  <groupId>org.nuiton.i18n</groupId>
  <artifactId>i18n-maven-plugin</artifactId>
  <executions>
      <execution>
          <goals>
            <goal>generateI18nEnumHelper</goal>
          </goals>
          <configuration>
            <enumerationSets>
              <enumerationSet>
                <name>label</name> <!-- property to generate methods to translate your keys -->
                <pattern>observe.enum.@CLASS_NAME@.@NAME@</pattern> <!-- How to generate your keys (available tokens are CLASS_NAME, SIMPLE_CLASS_NAME, NAME and ORDINAL)-->
                <enums>
                  <enum>fr.ird.observe.services.dto.constants.GearType</enum>
                  <enum>fr.ird.observe.application.swing.configuration.constants.CreationMode</enum>
                </enums>
              </enumerationSet>
              <enumerationSet>
                <name>description</name>
                <pattern>observe.enum.@CLASS_NAME@.@NAME@.description</pattern>
                <enums>
                  <enum>fr.ird.observe.application.swing.configuration.constants.CreationMode</enum>
                  <enum>fr.ird.observe.application.swing.configuration.constants.DbMode</enum>
                </enums>
              </enumerationSet>
            </enumerationSets>
          </configuration>
        </execution>
  </executions>
</plugin>

will generate:

public class I18nEnumHelper {

    public static <E extends Enum<E>> String getLabel(E e) {
        return t(getLabelKey(e));
    }

    public static <E extends Enum<E>> String getLabel(Locale locale, E e) {
        return l(locale, getLabelKey(e));
    }

    protected static <E extends Enum<E>> String getLabelKey(E e) {
        return "observe.enum." + e.getClass().getName() + "." + e.name();
    }

    public static <E extends Enum<E>> String getDescription(E e) {
        return t(getDescriptionKey(e));
    }

    public static <E extends Enum<E>> String getDescription(Locale locale, E e) {
        return l(locale, getDescriptionKey(e));
    }

    protected static <E extends Enum<E>> String getDescriptionKey(E e) {
        return "observe.enum." + e.getClass().getName() + "." + e.name() + ".description";
    }

    static {

        n("observe.enum.fr.ird.observe.services.dto.constants.GearType.longline");
        n("observe.enum.fr.ird.observe.services.dto.constants.GearType.seine");
        n("fr.ird.observe.application.swing.configuration.constants.CreationMode.no");
        n("fr.ird.observe.application.swing.configuration.constants.CreationMode.no.description");
        ...

    }
}

To see all the features of the plugin, consult the goals details page.