Skip to content

I18N Maven Plugin

The Tentackle I18N Maven Plugin

The tentackle-i18n-maven-plugin synchronizes an application's resource bundles between its *.properties files and a database backend. Tentackle can serve localized texts from the database instead of (or in addition to) the property files baked into the jars, which lets translators edit texts at runtime and add languages not provided by the property files — typically through the BundleMonkey tool — without rebuilding and redeploying the application. This plugin is the build-time counterpart that moves translations in both directions and keeps the two representations consistent.

The texts live in the database as StoredBundle PDOs (table bundle), each holding the translations of one bundle for one locale, with the per-key entries kept in StoredBundleKey components. A StoredBundle with a null locale carries the default (fall-back) translations.

The goals share the prefix tentackle-i18n, so they can be invoked directly from the command line, e.g. mvn tentackle-i18n:push.

Prerequisites

The plugin requires the same JDK and Maven versions as the rest of the framework (JDK >= 25, Maven >= 3.9.0). Every goal connects to a live database, so a reachable backend and the matching JDBC driver on the plugin's classpath are required (add the driver to the plugin's <dependencies>).

How Bundles Are Discovered

None of the goals scan the source tree for *.properties files directly. Instead, they ask BundleSupport for every class that is marked as a resource bundle — that is, every class annotated with @Bundle or with another bundle-providing annotation such as @FxControllerService. These annotations are picked up during the analyze step and recorded under META-INF, so the plugin sees exactly the bundles the running application would see, in both modular and classpath mode.

For each discovered bundle the plugin derives the resource name from the bundle name and loads the corresponding property file from the project's compile classpath — first the default file (name.properties), then one file per extra locale configured via locales (name_de.properties, name_en-US.properties, …). Because the bundles are resolved through the compile classpath, the goals require dependency resolution and operate on compiled modules.

Overview of Goals

Goal Aggregator Direction Purpose
push no files → DB Insert the property-file translations into the database. Existing translations are kept unless override is set.
pull no DB → files Write translations found in the database back into the project's property files.
verify yes compare Report differing, missing and obsolete translations; fail the build on a missing default translation.
cleanup yes DB Delete obsolete bundles and keys from the database — but only when verify would report no errors or warnings.
help Print plugin usage information (generated by the maven-plugin-plugin).

push and pull run per module (they act on the bundles of the current project), whereas verify and cleanup are aggregators that look at the whole reactor at once and are therefore run on the root project.

Common Configuration

Like all Tentackle mojos, the goals inherit the common parameters verbosity, skip, charset and jdkToolchain (see the tentackle-maven-plugin docs). On top of that, every i18n goal needs the database connection and may take a locale list:

  • url (required): the JDBC URL of the backend holding the stored bundles.
  • user (required): the database user.
  • password: the database password (maybe omitted for password-less or externally authenticated connections).
  • locales: a comma/space/semicolon-separated list of the additional locale suffixes to process besides the default one, e.g. de, en_US, fr. Underscores are accepted and normalized to hyphens (en_USen-US). The default bundle (no suffix) is always processed.

A minimal configuration looks like this:

<plugin>
  <groupId>org.tentackle</groupId>
  <artifactId>tentackle-i18n-maven-plugin</artifactId>
  <version>${project.version}</version>
  <configuration>
    <url>jdbc:postgresql://localhost/muz</url>
    <user>muz</user>
    <password>secret</password>
    <locales>de, en</locales>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>${postgresql.version}</version>
    </dependency>
  </dependencies>
</plugin>

Every goal prints a summary line at the end — number of bundles processed, warnings, errors and updates — and fails the build if any errors were counted.

The push Goal

Loads the translations from the property files and writes them to the database. For each bundle it looks up the matching StoredBundle (by name and locale), creating it if it does not yet exist, and adds every key/value pair.

mvn tentackle-i18n:push
  • override (default false): by default, existing database translations are left untouched and only keys that are missing in the database are added — so manual edits made through BundleMonkey are preserved. Set override=true to overwrite the stored values with the ones from the property files wherever they differ.

Use push to seed a fresh database from the texts shipped in the sources, or to add newly introduced keys without disturbing existing translations.

The pull Goal

The reverse of push: it reads the translations from the database and updates the project's property files so that the sources reflect the texts edited at runtime.

mvn tentackle-i18n:pull

Only bundles whose package belongs to the current project are written (the target file is located via the project's resource roots). If a property file does not exist yet it is created. A key is written only when it is missing from the file or differs from the stored value; changed files are rewritten with a comment recording the source URL and the user/host that pulled them. Keys that exist in the file but not in the database are left in place — removing obsolete keys is the job of cleanup.

The verify Goal

An aggregator that compares the property files of the whole reactor against the database and reports the discrepancies without changing anything. It distinguishes:

  • differing translations — key present on both sides but with different text (info),
  • obsolete bundles — a StoredBundle whose bundle no longer exists in the application (warning),
  • obsolete keys — keys in the database that are no longer present in the property file (warning),
  • missing stored bundles — a bundle that has no StoredBundle at all (warning),
  • missing translations for a non-default locale (warning), and
  • missing default translations — a key absent from the null-locale bundle (error).
mvn tentackle-i18n:verify

A missing default translation is the only condition that fails the build, because at runtime it would cause a MissingResourceException. The other findings are reported so they can be resolved — typically by push/pull or by BundleMonkey — before running cleanup.

Note: the application's own resource bundles (keys referenced in code) are checked separately by the tentackle-check-maven-plugin during the build; verify focuses on the consistency between the property files and the database.

The cleanup Goal

An aggregator that removes obsolete bundles and obsolete keys from the database. As a safety measure it performs the same analysis as verify first and does nothing if that analysis would yield any errors or warnings — it then tells you to run tentackle-i18n:verify and resolve the pending refactorings (e.g., via BundleMonkey) first. Only when the database and the sources are otherwise in sync does it delete the obsolete keys and bundles, all within a single transaction.

mvn tentackle-i18n:cleanup

A Typical Workflow

  1. Developers add or change keys in the *.properties files and run tentackle-i18n:push to make the new keys available in the database (existing translations stay untouched).
  2. Translators edit the texts at runtime through BundleMonkey.
  3. tentackle-i18n:pull brings the edited texts back into the property files so they are committed to source control.
  4. tentackle-i18n:verify is run (e.g., in CI) to surface differing, missing or obsolete entries.
  5. Once verify is clean, tentackle-i18n:cleanup prunes the keys and bundles that have been removed from the application.

Further Reading