Tag Archives: i18N

Practical i18n in Vaadin: Resource Bundles, Locale Handling and UI Language Switching

Modern web applications are rarely used only by users with the same language. Even internal tools often reach international teams or are used in different countries. A multilingual user interface is therefore not a luxury feature, but an important part of the user experience.

The open-source project URL-Shortener also benefits from a clear internationalisation strategy. The application is intended for developers, administrators, and other users who want to manage, analyse, or distribute links. To ensure that the interface remains understandable regardless of the user’s origin, the application supports multiple languages.

Screenshot of a URL shortener interface displaying a list of shortened URLs, their codes, original links, creation dates, and status indicators.

The project can be found on GitHub at the URL: https://3g3.eu/url

This article shows how the URL shortener UI has been enhanced with simple, robust internationalisation. The implementation is based entirely on Vaadin Flow’s capabilities and deliberately uses only a few additional helper classes to keep the architecture clear.

The solution has several key objectives. On the one hand, the users’ language is to be automatically recognised based on the locale transmitted by the browser. In addition, it must be possible to manage multiple translations via resource bundles without creating additional administrative overhead in the application code. At the same time, the user should be able to change the language at any time during a running session. Another important goal is to keep the implementation lean and deliberate and to dispense with additional frameworks so that internationalisation can be implemented directly within the existing application without complex infrastructure.

Currently, the application supports three languages:

  • English
  • German
  • Finnish

The choice of these languages is deliberately pragmatic. English serves as the standard language, while German and Finnish depict real-life usage scenarios from the project’s environment.

The focus of this article is not only on the technical implementation but also on how internationalisation can be integrated into a Java web application in a way that keeps the source code clearly structured and maintainable. To do this, we examine both the organisation of translation resources and the handling of locales within the application.

In the following course, it is explained step by step how Vaadin recognises and loads translation resources, how translation keys can be structured sensibly, and how the user’s language is determined based on the browser locale. In addition, it shows how simple language switching can be integrated directly into the user interface, allowing users to switch the desired language during a running session.

This creates an internationalisation solution that is deliberately kept simple but can be easily expanded if other languages are added later.

Internationalisation in Vaadin

Vaadin Flow already provides basic support for internationalisation. Applications can provide translations via so-called resource bundles, which are automatically recognised and loaded by the runtime environment. In this way, user interfaces can be operated in several languages without much additional effort.

The central mechanism relies on translation files stored in a special directory within the project. By default, Vaadin searches for translation resources in the vaadin-i18n folder within the classpath. All files stored there are automatically recognised and are available to the application at runtime.

The translation files follow the familiar structure of Java Resource Bundles. A base file contains the standard translations, while additional files provide language-specific variants. The language is defined by a language suffix in the file name.

A typical setup looks like this, for example:

vaadin-i18n/

  translations.properties

  translations_de.properties

  translations_fi.properties

The file without a language suffix serves as the default resource. In many projects, it contains the English texts. As soon as Vaadin determines an active locale, the framework automatically attempts to load the appropriate translation file. If a language-specific variant exists, it is used. Otherwise, Vaadin falls back on the default resource.

This behaviour corresponds to the classic fallback mechanism of Java Resource Bundles. This means that the application remains functional even if individual translations are not yet complete.

For the user interface, this means that text is no longer defined directly in the source code but is referenced via unique translation keys. These keys are then resolved at runtime via the active locale.

Vaadin provides the getTranslation() method for this purpose, which can be used directly in UI components. This method is used to pass a translation key to the framework, after which Vaadin determines the appropriate text from the loaded resources.

Thus, the resource bundle system forms the basis for all other internationalisation mechanisms within the application. On this basis, additional concepts such as language switching, session-based locale management or structured translation keys can then be developed.

Structuring Translation Resources

After looking at Vaadin’s basic internationalisation support in the previous chapter, an important question quickly arises in practice: How should translation resources be organised within a project to remain maintainable in the long term?

In the URL shortener project, all translations are stored in so-called resource bundles. These are located in the directory src/main/resources/vaadin-i18n/. Vaadin automatically detects this folder and loads the translation files it contains at runtime.

The structure of the files follows the conventions of Java Resource Bundles. A base file contains the standard translations, while additional files provide language-specific variants.

src/main/resources/vaadin-i18n/

  translations.properties

  translations_de.properties

  translations_fi.properties

The translations.properties file serves as the default resource. This project contains the English texts. For other languages, additional files with a language suffix are created. The language is defined by the ISO language code in the file name.

For example, the German version contains the file translations_de.properties, while the Finnish version contains translations_fi.properties.

Within these files, the actual translations are defined via key-value pairs. Each key corresponds to a specific text in the user interface.

main.appTitle=URL Shortener

main.logout=Logout

nav.overview=Overview

nav.create=Create

nav.youtube=Youtube

nav.about=About

The keys themselves follow a simple naming convention. They are often built according to the pattern bereich.element. This allows texts that belong together to be logically grouped.

This structure makes it easier to keep track of a large number of translations. At the same time, it prevents name conflicts between different areas of the application.

Another advantage of this structure is that translations remain completely separate from the application code. The source code only references the keys, while the actual texts are defined in the resource bundles.

This allows translations to be expanded or corrected later without changes to the application code.

This clear separation between code and translation resources provides an important basis for further internationalisation of the application. The next step will therefore look at how these translation keys can be used comfortably within the user interface.

Simplified access to translations with I18nSupport

Once the structure of the translation resources has been determined, another question arises in practical development: How can these translations be used as comfortably as possible within the user interface?

Vaadin basically provides the getTranslation() method, which can be used to resolve translation keys at runtime. This method is available, for example, within UI components and allows you to use a key to determine the appropriate text from the loaded resource bundles.

In practice, however, direct use of this method often results in recurring boilerplate code. Especially in larger user interfaces, translations have to be resolved in many different places. This quickly results in redundant calls and less readable code.

To make this access easier, the URL shortener project uses a small helper interface called I18nSupport. This interface encapsulates access to the translation function and provides a compact method for querying translations within the UI components.

A simplified example of this interface looks like this:

public interface I18nSupport {
  default String tr(String key, String fallback) {
    return UI.getCurrent().getTranslation(key);
  }
}

This auxiliary method allows translations to be used much more compactly within the application. Instead of working directly with the Vaadin API, a single method call suffices.

An example from the application’s MainLayout illustrates this:

H1 appTitle = new H1(tr(“main.appTitle”, “URL Shortener”));

This keeps the source code clear and the actual text completely separate from the user interface implementation.

Another advantage of this solution is that access to translations can be adjusted centrally. If the implementation changes later – for example, due to additional fallback mechanisms or logging – this can be done within the helper interface without having to adapt all UI components.

I18nSupport thus forms a small but effective abstraction layer on top of the Vaadin i18n API. It ensures that translations can be used consistently throughout the application with as little boilerplate code as possible.

Determining the user locale

Once translation resources have been structured and convenient access has been provided via I18nSupport, the next step is to ask a central question: What language should the application use when it is first launched?

In web applications, this decision is usually made based on the browser’s language preferences. Modern browsers send a so-called Accept-Language header with every HTTP request that contains a prioritised list of preferred languages. Based on this information, the application can decide which locale to use initially.

Vaadin Flow already takes this information into account during user interface initialisation. When building a new UI, the browser’s locale is automatically detected and set as the current locale. This allows an application to select the appropriate language when the interface is first rendered.

In practice, however, it rarely makes sense to support every language reported by the browser fully. Many applications only offer a limited number of translations. Therefore, the browser-reported locale must first be compared with the application’s actually supported languages.

In the URL shortener project, this matching is implemented via a small helper class called LocaleSelection. This class defines the application’s supported languages and provides methods to map a requested locale to an available variant.

A simplified example looks like this:

public static Locale match(Locale requested) {
  if (requested == null) {
    return EN;
  }
  String language = requested.getLanguage();
  return SUPPORTED.stream()
      .filter(l -> l.getLanguage().equals(language))
      .findFirst()
      .orElse(EN);
}

The method first checks which language the browser requested. It then checks whether this language is among the application’s supported languages. If this is the case, the corresponding locale is adopted. Otherwise, the application’s default language is used.

This strategy ensures that the application remains consistent even if a browser reports a language for which there are no complete translations. At the same time, the implementation remains clear and easily expandable.

The next step is how to keep the chosen language stable during a session. Therefore, in the following chapter, we will look at how a user’s locale is stored and managed within the Vaadin session.

Session-based voice management

After describing in the previous chapter how the initial language of an application can be determined based on the browser locale, another important question arises in practice: How does this decision remain stable throughout the application’s use?

In a typical web application, a user session consists of multiple HTTP requests. During this time, the user expects the interface to be consistently displayed in the same language. If the language were to be determined exclusively by the browser locale for each request, this could lead to unexpected changes – especially if a user manually switches languages within the application.

For this reason, the URL shortener project stores the selected language within the Vaadin session. The session represents a server-side context that is retained across multiple requests and is therefore well-suited to storing user-specific settings, such as the current locale.

Vaadin itself already offers basic support for this. Each VaadinSession has an associated locale that can be set and queried by the application. If this locale is changed, it directly affects the resolution of translation keys in the user interface.

In the project, the session locale is also managed using the LocaleSelection helper class. In addition to the previously shown method for selecting a supported language, this class also provides methods to store or read the locale in the session.

A simplified example for storing the locale looks like this:

public static void setToSession(VaadinSession session, Locale locale) {
  session.setAttribute(SESSION_KEY, locale);
}

When changing the language, the selected locale is saved in the session and set directly on the current UI. This ensures that the new language becomes active immediately and is retained for all subsequent interactions within the same session.

This approach has several advantages. For one, a user’s language remains consistent throughout the session. On the other hand, the language can be changed at any time by a user action without the need for additional persistence mechanisms such as cookies or database entries.

In addition, the implementation remains deliberately simple. The application uses only the existing Vaadin mechanisms and adds only a small helper class for central management of the supported locales.

The next chapter shows how this session-based locale is eventually linked to the user interface and how users can switch languages directly within the application.

Language switching in the user interface

After describing in the previous chapter how to store the selected language in the Vaadin session, the practical question now arises: how can users change this language in the first place? Internationalisation is only useful if users can actively switch the interface language.

In the URL shortener project, language switching has been integrated directly into the MainLayout. This layout forms the central structure of the user interface and includes, among other things, the navigation bar and various status and control elements. This makes it ideal for placing a compact language switch.

Instead of a classic drop-down menu, the application uses a small group of buttons, each representing a language. The buttons are displayed as flags, making the desired language recognisable at a glance.

The user interface shows three options:

  • German
  • English
  • Finnish
User interface showing language options with German, English, and Finnish flags, the name 'EclipseStore,' and a logout button.

Each of these buttons changes the current locale when clicked. Technically, the first step is to check which language has been chosen. This language is then set in both the current UI and the Vaadin session.

The switch’s specific design is deliberately kept small and does not require any additional components or dependencies. Instead of a ComboBox, a horizontal button group is rendered, which acts like a “segmented control”: three round buttons in a slightly separated bar. The bar itself is merely a horizontal layout, with styling handled via Lumo CSS variables, so the look blends harmoniously with the rest of the theme.

When the switch is created, the currently effective locale is first determined. It is crucial that not only the browser locale is considered, but that a value already stored in the session takes precedence. This is exactly what LocaleSelection.resolveAndStore(…) is used for. The result is the “current” locale, which is used to mark the active button.

private Component createLanguageSwitch() {
  Locale current = LocaleSelection.resolveAndStore(
      VaadinSession.getCurrent(),
      UI.getCurrent().getLocale()
  );
  Button de = flagButton(LocaleSelection.DE, current);
  Button en = flagButton(LocaleSelection.EN, current);
  Button fi = flagButton(LocaleSelection.FI, current);
  HorizontalLayout bar = new HorizontalLayout(de, en, fi);
  bar.setSpacing(false);
  bar.getStyle()
      .set("gap", "6px")
      .set("padding", "2px")
      .set("border-radius", "999px")
      .set("background", "var(--lumo-contrast-5pct)");
  return bar;
}

The actual logic lies in creating a single button. Each button only gets a chip with an emoji flag as content. This seems trivial, but it’s practical: it requires no assets, no additional files, and no build steps. Styling and interaction take place directly on the button.

Three points are important here: First, the buttons are shaped into a compact, round form so that they are perceived as a group that belongs together. Second, the active state is calculated based on the language (getLanguage()), because regional variants such as de-DE or de-AT should not affect the UI. Third, a click triggers the actual locale switch.

private Button flagButton(Locale locale, Locale current) {
  String flag = flagEmoji(locale);
  Button b = new Button(new Span(flag));
  b.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
  b.getStyle()
      .set("width", "38px")
      .set("height", "32px")
      .set("min-width", "38px")
      .set("border-radius", "999px")
      .set("padding", "0")
      .set("line-height", "1")
      .set("font-size", "18px");
  boolean active = locale.getLanguage().equalsIgnoreCase(current.getLanguage());
  applyActiveStyle(b, active);
  b.addClickListener(e -> switchLocale(locale));
  Tooltip (optional)
  b.getElement().setProperty("title", locale.getLanguage().toUpperCase());
  return b;
}

For the active state, no additional theme variant is deliberately introduced; instead, a minimal style is applied: a slight background tint and an outline ring in the primary colour. Thus, the component remains visually restrained but unambiguous.

private void applyActiveStyle(Button b, boolean active) {
  if (active) {
    b.getStyle()
        .set("background", "var(--lumo-primary-color-10pct)")
        .set("outline", "2px solid var(--lumo-primary-color-50pct)");
  } else {
    b.getStyle()
        .remove("background")
        .remove("outline");
  }
}

The locale change itself is deliberately implemented “robustly”. First, the selected locale is matched to a supported language. It is then set in both the session and the UI. The final reload() ensures that all views, dialogues, and components resolve their texts from the resource bundles again. This avoids the additional complexity that would otherwise be caused by LocaleChangeObserver implementations across many components.

private void switchLocale(Locale selected) {
  UI ui = UI.getCurrent();
  VaadinSession session = VaadinSession.getCurrent();
  Locale effective = LocaleSelection.match(selected);
  LocaleSelection.setToSession(session, effective);
  session.setLocale(effective);
  ui.setLocale(effective);
  ui.getPage().reload();
}

Finally, the display of the flags is encapsulated via a small mapping method. This keeps the display in a central place and can be easily adapted later – for example, if US is to be used instead of EN or if other languages are added.

<IMG DE>  – this is a replacement of the emoji —

private string flagEmoji(Locale locale) {
  return switch (locale.getLanguage()) {
    case "de" -> "<IMG DE>";
    case "fi" -> "<IMG FI>";
    default -> "<IMG EN>"; EN
  };
}

The process consists of several steps. First, the desired language is compared with the application’s supported languages. Then the locale is set in both the session and the current UI. As a result, the new language is immediately available.

The final page reload ensures that all UI components are re-rendered and that all translations are consistently resolved with the new locale. This approach is deliberately kept simple and avoids additional complexity within the component logic.

By integrating language switching into the MainLayout, this feature is available in every view of the application. Users can switch languages at any time without leaving the current page.

This means that the internationalisation of the user interface is fully integrated into the application. Translation resources, locale discovery, session management, and language switching are now intertwined, enabling a multilingual interface with comparatively low implementation effort.

Conclusion and outlook

With internationalisation, the URL shortener has reached a point where good user-friendliness and clean architecture converge. The application supports multiple languages without the source code becoming confusing or requiring additional dependencies. Instead, the existing Vaadin Flow mechanisms are relied on, and only added where they make sense for the project.

The essential building blocks mesh neatly. Translations are stored as resource bundles in the vaadin-i18n directory so that Vaadin recognises them automatically. Clearly structured keys are used to extract texts from the interface and manage them centrally. I18nSupport reduces access to translations to a compact, anywhere-to-use method, keeping UI classes readable.

The locale determination follows a pragmatic principle. By default, the browser’s locale is used, but limited to the languages that are actually supported. This keeps the system predictable and avoids incomplete translation states. At the same time, the selected language is stored on a per-session basis, so that users retain a consistent interface during a session and their selection does not have to be “renegotiated” with each request.

Finally, the whole thing becomes particularly visible in the user interface. The language switch in the MainLayout is deliberately minimalist, but on the UX side, it is much more pleasant than a nested menu. Three flag buttons are enough to quickly change the language, and the active state is immediately recognisable. The technical change to the locale is implemented robustly across the session and UI. The final reload is not a workaround, but a conscious design decision: It ensures that all views, dialogues, and components are consistently rendered in the new language without each component having to implement additional observer logic.

This creates a solid foundation that can be expanded if necessary. An obvious next step would be to add more languages or refine translations without changing the code. For more complex language cases – such as pluralisation, number and date formatting, or language-dependent sentence modules – ICU-based formatting could be added later. It would also be possible to save the language selection not only on a session basis, but also to link it to a user profile permanently.

For the current state of the URL shortener, however, the solution is deliberately kept to the essentials: It is small enough to remain maintainable, but complete enough to deliver real benefits in everyday life. This is precisely the practical value of good internationalisation – it is hardly noticeable in the code but immediately noticeable to users.

Building More Complex Apps with Flow

In this part of the series about Vaadin Flow, I will show how I can create the basic framework for the graphic design of a work application. The focus here is on the design of the work area and the organisation of the individual logical application groups. In other words, we create the application layout that can be used for an industrial project.

Of course, this also includes dealing with different languages ​​based on i18N.

One of the first steps in an application is often to think about how everything should be presented on the screen. If menus are used, headers and footers should be used for elements, and what about the basic design of the workspace? The questions here are to be understood as examples, as they will, of course, always depend on the context and the target group.

AppLayout

AppLayout is a reasonably robust and easy-to-use solution that comes with the Vaadin Flow framework. This class provides the entry point for quickly building an application’s framework. We looked at this class briefly in the first part and will now go into more detail here.

A classic Applayout consists of a header, where part of the navigation is usually housed. There is also a corresponding footer, which is usually used for lower-priority status messages. The middle is then divided into one to three parts. We will choose a classic two-column design here. The left side is the main navigation, the detailed navigation of which will then be visible in the header like a menu bar.

The layout consists of three sections: a horizontal navigation bar (called Navbar), a fold-out navigation bar (drawer), and a content area. An application’s main navigation blocks should be positioned in the navigation bar and/or drawer while rendering views in the content area.

The app layout is responsive and automatically adapts to the screen size of desktops, tablets, and mobile devices. This behaviour saves us a lot of customisation work that we would otherwise have to implement ourselves.

The navigation structure depends mainly on the number of elements to be shown and whether a sub-navigation is required. 

The navigation bar is a good choice for multiple items (3-5) as they fit in the viewport without scrolling. If you need to display more items or small screen support is a priority, the Drawer is a better choice. It can accommodate a longer list of links without scrolling and collapses into a hamburger menu on small screens. Additionally, a vertical list of items is easier for the user to scan. If multi-level or hierarchical navigation is required, Draver is the first level. The secondary (and tertiary) navigation elements can be placed using the drawer or in the navigation bar (Navbar).

The implementation can then look like this. 

We create the basic framework in MainLayout from the class AppLayout is derived. Here, we have to use the methods for setting the individual navigation areas. Let’s start by building the main navigation, which is on the left side in this example. Here you will see a combination of icon and descriptions for the main areas of the application. The necessary graphical elements are displayed along with the application title via the method addToDrawer(…) set.

The application title is an instance of the class H1. Here the text to be displayed is simply selected using the method setText() handover.

The navigation elements are created using the class SideNavItem realised. The transfer parameters are a label. a target view and an icon. All SideNavItem – Instances are in the instance of the class SideNav summarised and transferred to the layout. In case the number of entries is larger and you want the user to be able to scroll through this list, the instance of the class SideNav is embedded into an instance of the class Scroller

In the source code, it looks like this:

To complete the layout, we will put all the elements together.

This is implemented in the constructor.

In this example, you can see that the labels are all stored directly in the source code. We will change this later so that we can make the application multilingual. I ask for a bit of patience here. We also see the specification of the targets using the class name. We’ll look at that a little later, too. 

In the previous post, I showed how the MainLayout class is used.

Screen with the created menu items

If you want to create a sub-navigation, you can make additional menu entries in the header on the right. This is often used when you want to divide a somewhat more complex process into different views. For example, let’s take the illustration for dealing with orders. Let’s just assume that there are the sub-areas “All orders”, “Open orders”, “Completed orders” and “Abandoned orders” must give. This results in another four navigation destinations, which are, however, summarised under the item Orders.

Screenshot after navigating to the Orders menu item

These submenu items are the same for all views that deal with orders. This immediately raises the question of how to extract this menu. Great mechanisms from inheritance come into play here. We create a class AbstractHeaderView and AbstractOrdersView. All constructs required for a generic implementation of secondary navigation are stored in the first class mentioned. This includes, for example, how the second navigation bar should be positioned, what graphic properties it has and whether there is a hamburger symbol that can be used to show or hide the main navigation.

Ultimately, all that needs to be added is which navigation points must be created for each implementation. The respective implementation of the method secondaryNavigationsLinks() defines these menu items.  

The following listing shows the implementation for the screenshot shown, divided into the generic part AbstractHeaderView and the specific one for the orders AbstractOrdersView.

Here, you can clearly see that the source text is greatly reduced when there are a large number of navigation elements. A minimal basic framework is created to implement the variations for the individual views. I have intentionally refrained from including functions for processing orders in this example because I want to focus on the structure here.

With the basic framework shown here, you can build quite complex navigations. Now, let’s get to the topic of i18n. A web application usually needs to support multiple languages. I will not discuss languages ​​here that require a change in reading direction. In this example, I’ll focus on supporting any number of languages ​​with a left-to-right reading order. Examples of languages ​​here will be German and English. The primary function here is quite simple

What is i18N – Internationalization in Java

The basic concept of i18n (internationalisation) in Java is to design and develop an application that can be easily adapted to different languages ​​and regions without requiring significant changes to the code. 

Resource bundle

A resource bundle is a set of key-value pairs that store country-specific data, such as B. Strings for messages, labels and other UI components. In Java, resource bundles are usually property files named after the locale they represent (e.g. “messages_en_US.properties” for US English, “messages_de.properties“ for general German).

When the application runs, it dynamically loads the appropriate resource bundle based on the user’s locale. This allows the application to display content in the user’s preferred language without hard-coding the text in the source code.

Locale

A `locale` in Java is an object that represents a specific geographical, political or cultural region. It includes language, country and sometimes variant codes. For example, `Locale.ENGLISH` represents the English language and `Locale.US` represents the United States.

The class `Local` customises information for the user, such as B. Text, dates, numbers and currencies, according to its region.

Message Formatting

Java provides classes like `MessageFormat` to handle complex message formatting that allows dynamic insertion of values ​​into localised messages (e.g. “Welcome, {0}!”, where `{0}` can be replaced with the user’s name).

You define message templates in your resource bundles, and at runtime, the class replaces `MessageFormat` Placeholders with actual values ​​to ensure messages are appropriately localised and formatted.

Date, number and currency formatting

Dates, numbers, and currencies are often represented differently in different locales (e.g. `MM/DD/YYYY` vs. `DD/MM/YYYY` for dates). Java provides classes like `DateFormat`, `NumberFormat` and `Currency` to process these deviations.

These classes format data according to locale settings and ensure users see information in the expected format.

Fallback mechanism

If a specific locale’s resource package is unavailable, Java uses a fallback mechanism to select a more general package (e.g., falling back from `messages_fr_CA.properties` to `messages_fr.properties`).

This ensures that the application remains functional even if a full set of localised resources is unavailable for each locale.

The basic concept of i18n in Java is to create applications that can support multiple languages ​​and regional settings with minimal changes to the code base. This includes using resource bundles, locale-dependent classes for formatting, and a fallback mechanism to ensure a seamless user experience across different locales.

i18N in Vaadin Flow

To use i18N, the application only needs to have the corresponding text files with the keys and contents available in the classpath under the vaadin-i18n directory with the filename prefix translations (e.g. src/main/resources/vaadin-i18n/translations.properties).

When a translation is requested or when the I18NProvider is used for the first time, the vaadin-i18n directory is checked to see if it contains any translations.properties or translations_[langcode].properties files. All language codes are collected from the available files and added as provided locales in the DefaultI18NProvider.

The translations.properties file is a standard translation file used for any locale that does not have a specific translation file. For example, locale translation files are called translations_de.properties or translations_en.properties. Automatic locale creation supports one to three parts (e.g. translations_language_country_variant.properties).

The locale to use is determined by matching the locales provided by the I18NProvider with the Accept-Language header in the client’s initial response. It will be used if an exact match (i.e., language and country) is found. Otherwise, it will just try to find a match by language. If neither is found, the locale defaults to the first “supported” locale from I18NProvider.getProvidedLocales() set. If this is empty, will Locale.getDefault() used.

Implementing internationalisation in an application is a combination of using I18NProvider and updating translations when locale changes. This can be done, for example, by the user if he wants to change the language. To simplify this, the application classes that control the localised captions and text can LocaleChangeObserver implement to receive events related to locale changes. During navigation, this observer will also be notified when the component is attached, but before onAttach() is called. All URL parameters from navigation are set so that they can be used to determine status.

If you want to set the texts explicitly, you can use this method: getTranslation(..).

In this example project, the listing for creating the main menu entries is rewritten. For clarity, here are both versions for a menu entry.

High Version:

New version:

translation.properties:

mainlayout.menuitem.orders=Orders

Conclusion

With these two elements, the ApplLayout and the realisation or implementation of i18N, two fundamental building blocks for developing a web application have been laid. From here, the application can now be built step by step. We will deal with the individual topics in the next parts, so it remains exciting.

Happy Coding

Sven