Last updated Feb 20, 2024

Internationalising your plugin's JavaScript

This is a document for developers wanting to provide internationalisation (i18n) support in their plugin's JavaScript code. The guide assumes developers already know how to internationalise your plugin and builds on the techniques described there.

How it works

The Web Resource Manager (WRM) provides an internationalisation transformer. When a web-resource is configured with this transformer, specific JavaScript function calls will be found and substituted with a translated value based on the user's or system's configured locale.

Getting started

If you're creating a new plugin, the easiest way to get started is by using our @atlassian/atlas-fe tool and reading the limitations sub-section below.

For plugins with existing code, there is a manual or automatic way to enable JavaScript internationalisation.

Manual configuration

Add the i18n transformer to any web-resource that uses translations:

1
2

<web-resource key="my-feature">
    <transformation extension="js">
        <transformer key="jsI18n"/>
    </transformation>
    <dependency>com.atlassian.plugins.atlassian-plugins-webresource-plugin:i18n</dependency>
    <resource type="download" name="my-feature.js" location="path/to/my-feature.js"/>
</web-resource>

Automatic configuration

The automatic approach uses the Atlassian Web-Resource Webpack Plugin. Read the webpack plugin's documentation for more information on how to use Webpack with the Atlassian P2 plugin system.

Internationalise your JavaScript code

In vanilla JavaScript

In your JavaScript files, you can use the following function calls:

  • WRM.I18n.getText('i18n.key.one') - At runtime, this expression will be replaced with the locale-specific translation for the key i18n.key.one.
  • WRM.I18n.getText('i18n.key.with.substitutions', 123, 'foo', ...) - This variant of the function will replace values to your translation string at runtime. Specifically, {0} placeholder in the translation string would be replaced with the number 123, {1} with the string foo, and so on.

To support older platform versions, the AJS.I18n.getText() function is also replaced, as is any function call that matches the form <Identifier>.I18n.getText(...).

Example usage

In MyPluginName.properties:

1
2
com.example.plugin.fruit.basket.add.button = Add to basket
com.example.plugin.fruit.basket.contains = Fruit basket item count: {0}

Simple message in vanilla JavaScript:

1
2
WRM.I18n.getText('com.example.plugin.fruit.basket.add.button')

Formatted message in vanilla JavaScript:

1
2
const fruitBasket = ['apple', 'banana', 'apricot'];
WRM.I18n.getText('com.example.plugin.fruit.basket.contains', fruitBasket.length);

Tip: You should never write i18n strings that depend on the cardinality of the values passed to it - for instance, "com.example.plugin.fruit.basket.contains.one" or "com.example.plugin.fruit.basket.contains.multiple" - as not all languages have the same pluralisation rules as English. See Pluralising internationalisation strings to find out more on how to write i18n strings that account for plurals.

In React components

If you use React and would like to format messages with React elements as parameters, the @atlassian/wrm-react-i18n package will connect your React components with the platform's i18n capabilities. For usage instructions, see the Node package's readme.

Speed up the runtime translation process

In more recent Server and Data Center product versions, the Web Resource Manager's i18n transform process can accept a pre-compiled list of used i18n keys per JavaScript file. The runtime translation process is significantly faster when the list is provided, which decreases cold cache load times for batch files and other JavaScript resources.

Prerequisites

AMPS 8.3 or higher will generate the used i18n keys list when the plugin is compiled.

The Server or Data Center product's platform must include Web Resource Manager version 5.3 or higher.

How it works

For every JavaScript file the WRM will serve to the UI, the WRM checks whether the plugin includes an .i18n.properties file with the same name. For example, if your atlassian-plugin.xml defined the following web-resource:

1
2

<web-resource key="my-feature">
    <transformation extension="js">
        <transformer key="jsI18n"/>
    </transformation>
    <dependency>com.atlassian.plugins.atlassian-plugins-webresource-plugin:i18n</dependency>
    <resource type="download" name="my-feature.js" location="path/to/my-feature.js"/>
</web-resource>

The JavaScript file path/to/my-feature.js is stored in and retrieved from your plugin JAR. If a path/to/my-feature.js.i18n.properties file exists, the WRM will read this file at runtime and opt in to the faster translation process.

Note that the .i18n.properties file does not need to be explicitly added to your XML; the WRM will automatically find it.

The .i18n.properties file uses the Java properties file format:

1
2
# Any comments will be ignored
i18n.key.one=1
i18n.key.two=1
i18n.key.three=2

Each line in the file is a key-value pair separated by an equals sign (=).

  • Each key is an i18n key used by the JavaScript file.
  • Each value is the number of times the key gets used within the JavaScript file.

How to generate the files

AMPS 8.3 will generate these files by default.

If you use a custom build tool, you can manually generate your own .i18n.properties files using the format described above. So long as the files end up in the plugin JAR in the same folder as the .js file it is for, the WRM will pick them up at runtime.

How to disable i18n usage generation in AMPS

The i18n usage file generation can be disabled in AMPS by adding <processI18nUsage>false</processI18nUsage> to the AMPS <configuration> block in your project's pom.xml file.

Limitations

All limitations stem from getText not being a real function. Retrieval of message value strings for given keys is done by the server prior to the JavaScript being served at request-time. This leads to the following limitations:

  • The message key parameter must be a string literal using either single ' or double quote marks " as the delimiters at serve-time.
  • The message key parameter cannot be a template string, nor an object reference, nor the result of a function call at serve-time.
  • If using a build process, the .I18n.getText must not be obfuscated.
  • If using a build process, the WRM or AJS object identifiers cannot be replaced with an obfuscated name that is longer than 100 characters.

To work around the message key limitations to enable switching messages at runtime, the easiest method is to conditionally use the message value at runtime like so:

Conditionally using message values in JavaScript:

1
2
fruitBasket.isFull ?
    WRM.I18n.getText('com.example.plugin.fruit.basket.delete.button') :
    WRM.I18n.getText('com.example.plugin.fruit.basket.add.button')

Rate this page: