Documentation

Documentation versions (currently viewingVaadin 24.4 (pre))

Localization

Implementing localization and translation strings using I18NProvider.

To use localization and translation strings, the application needs only to have the translation properties available on the classpath under the directory, vaadin-i18n with the filename prefix, translations (e.g., src/main/resources/vaadin-i18n/translations.properties).

When using localization in an application, calling for a translation, or when the I18NProvider is used for the first time, the folder resource, vaadin-i18n is checked if it contains any translations.properties or translations_[langcode].properties files. Any language codes are collected from the available property files and added as provided locales in the DefaultI18NProvider.

The file translations.properties is a default translation file that’ll be used for any Locale that doesn’t have a specific translations file. Locale translation files are named, for example, like translations_fi_FI.properties or translations_de.properties. The automatic Locale creation supports from one to three parts (e.g., translations_language_country_variant.properties).

Note
DefaultI18NProvider is available as of version 24.3 of Vaadin Flow. For an earlier version, you’ll need to implement your own I18NProvider, as documented in Defining I18n Provider Property section.

Locale Selection for New Session

The initial locale is determined by matching the locales provided by the I18NProvider against the Accept-Language header in the initial response from the client.

If an exact match (i.e., language and country) is found, it’ll be used. Otherwise, it tries to match only on language. If neither is found, the locale is set to the first 'supported' locale from I18NProvider.getProvidedLocales(). If that’s empty, Locale.getDefault() is used.

Using Localization in Application

Implementing internationalization in an application is a combination of using I18NProvider and updating the translations on locale change.

To make this simple, the application classes that control the captions and texts that are localized, can implement LocaleChangeObserver to receive events related to locale change. This observer is also notified on navigation when the component is attached, but before onAttach() is called. Any URL parameters from the navigation are set so that they can be used to determine the state.

public class LocaleObserver extends Div implements LocaleChangeObserver {

    @Override
    public void localeChange(LocaleChangeEvent event) {
        setText(getTranslation("my.translation", getUserId()));
    }
}

Using Localization without LocaleChangeObserver

public class MyLocale extends Div {

    public MyLocale() {
        setText(getTranslation("my.translation", getUserId()));
    }
}

Defining I18n Provider Property

To use a custom I18N provider with more features than available by the default one, the application needs only to implement I18NProvider and define the fully qualified class name in the property, i18n.provider.

Note
For a Spring project, the property is not needed if the custom provider is a Bean of type I18NProvider.

The i18n.provider property can be set from the command-line as a system property, as a Servlet initial parameter in the web.xml file, or using the @WebServlet annotation.

As a system property, the parameter needs the vaadin prefix like this:

mvn jetty:run -Dvaadin.i18n.provider=com.vaadin.example.ui.TranslationProvider

When using the annotation, you could have the servlet class as something such as this:

@WebServlet(urlPatterns = "/*", name = "slot", asyncSupported = true, loadOnStartup = 1,
   initParams = { @WebInitParam(name = Constants.I18N_PROVIDER, value = "com.vaadin.example.ui.TranslationProvider") })
public class ApplicationServlet extends VaadinServlet {
}

Or, if you prefer to use the web.xml file, you might set it as this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  id="WebApp_ID" version="3.0"
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <servlet>
    <servlet-name>myservlet</servlet-name>
    <servlet-class>
        com.vaadin.flow.server.VaadinServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>

    <init-param>
      <param-name>i18n.provider</param-name>
      <param-value>com.vaadin.example.ui.TranslationProvider</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>myservlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

You can provide an I18NProvider as a bean if you’re using Spring. In that case, you need only annotate your implementation with @Component, so that it’s available as a Spring bean. The Spring add-on uses it if it’s available. See the class SimpleI18NProvider.java implemented in the tutorial project as an example.

Using I18NProvider for Translation

For this example, the use of Finnish and English is enabled, with Finnish being the default that’s used if the user client doesn’t specify English as an accepted language. The language .properties files start with "translate": for example, translate.properties for the default, as well as translate_fi_FI.properties, and translate_en_GB.properties.

Here the translation properties files are loaded using the class loader. Hence, they should be located on the classpath, for example in the resources folder. For a default Maven setup, this would be src/main/resources.

public class TranslationProvider implements I18NProvider {

    public static final String BUNDLE_PREFIX = "translate";

    public final Locale LOCALE_FI = new Locale("fi", "FI");
    public final Locale LOCALE_EN = new Locale("en", "GB");

    private List<Locale> locales = Collections
            .unmodifiableList(Arrays.asList(LOCALE_FI, LOCALE_EN));

    @Override
    public List<Locale> getProvidedLocales() {
        return locales;
    }

    @Override
    public String getTranslation(String key, Locale locale, Object... params) {
        if (key == null) {
            LoggerFactory.getLogger(TranslationProvider.class.getName())
                    .warn("Got lang request for key with null value!");
            return "";
        }

        final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_PREFIX, locale);

        String value;
        try {
            value = bundle.getString(key);
        } catch (final MissingResourceException e) {
            LoggerFactory.getLogger(TranslationProvider.class.getName())
                    .warn("Missing resource", e);
            return "!" + locale.getLanguage() + ": " + key;
        }
        if (params.length > 0) {
            value = MessageFormat.format(value, params);
        }
        return value;
    }
}

Supporting Right-to-Left Mode

Vaadin components have support for right-to-left languages. The components work out-of-the-box in this mode. However, to allow your application to support both left-to-right and right-to-left modes, you’ll need to make a few changes.

Continuing from the previous examples, suppose your application now has also been translated into a right-to-left Language, such as Arabic. As well as following the I18NProvider example, in your main layout you can add code such as the following:

public class MainLayout extends VerticalLayout {

    public MainLayout() {
        // ...
        final UI ui = UI.getCurrent();
        if (ui.getLocale().getLanguage() == "ar") {
            ui.setDirection(Direction.RIGHT_TO_LEFT);
        }
    }
}

This works if the change of locale is based only on the Accept-Language coming from the client. However, if the user can specify their language, for instance, on your application’s settings page, you can have your main layout implement the LocaleChangeObserver interface. In this way, it receives changes of locale, so you can then set the text direction based on the specified locale:

public class MainLayout extends VerticalLayout implements LocaleChangeObserver {

    @Override
    public void localeChange(LocaleChangeEvent event) {
        if (event.getLocale().getLanguage() == "ar") {
            event.getUI().setDirection(Direction.RIGHT_TO_LEFT);
        } else {
            event.getUI().setDirection(Direction.LEFT_TO_RIGHT);
        }
    }
}

Frontend Projects

For frontend applications only, to set right-to-left mode, you can specify, document.dir = 'rtl'.

Adding Right-to-Left Support

If you have custom elements, or if your application has custom styles, there are a few steps needed to add right-to-left support to them.

First, if your element extends Vaadin’s ElementMixin, no changes are needed. Otherwise, you can have the element extend it or DirMixin only (i.e., DirMixin is part of the @vaadin/component-base package).

import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';

class MyElement extends DirMixin(PolymerElement) {}

The DirMixin registers the element to respond to changes in the dir attribute at the document level and keeps it synchronized with the element’s dir attribute. This is helpful to adjust to the text-direction status in both CSS and JS code.

Second, make sure your styles are adjusted for right-to-left mode. For example, if you define values for the padding on the :host, as follows:

:host {
    padding-right: 1em;
    padding-left: 2em;
}

You may want to define the style for right-to-left, as follows:

:host([dir="rtl"]) {
    padding-right: 2em;
    padding-left: 1em;
}

Third, you should also review settings such as padding, margin, text-align, float and transform in your styles. If your custom element doesn’t need to support old browsers, you can replace some properties with CSS Logical Properties. The MDN web documentation has a full list of CSS Logical Properties and their available values, along with browser support for each property. Flex and Grid containers are usually handled well by the browser and don’t require anything extra. You can find more information in this comprehensive right-to-left styling guide.

For help with adjusting styles for right-to-left mode, you can use the tools available on the RTLCSS page. There, you can paste original styles and it’ll generate code that you can use for your element.

If your element uses icons or Unicode symbols to define direction (e.g., for a Back button), you may need to use the right icons or symbols for right-to-left mode.

If keyboard interactions are used — for example, to navigate between items with arrow keys — define the direction of the movement based on the dir attribute like so:

// somewhere in your code
const dirIncrement = this.getAttribute('dir') === 'rtl' ? -1 : 1;

switch (event.key) {
    // ...
    case 'ArrowLeft':
        idx = currentIdx - dirIncrement;
        break;
    case 'ArrowRight':
        idx = currentIdx + dirIncrement;
        break;
    // ...
}

Custom elements that rely on JavaScript calculations for sizing, position, or horizontal scroll, may need some adjustments for right-to-left.

If you have visual tests, you may want to add or update the current ones to run also in right-to-left mode.

722E7AE4-191E-4DE8-90F1-CAE8AE6CD3DF