From 923985b5587268ff819ad71168458dc23d55e90e Mon Sep 17 00:00:00 2001 From: Luciano Vernaschi Date: Tue, 29 Apr 2025 11:24:42 +0200 Subject: [PATCH 1/5] First document version --- articles/hilla/guides/i18n.adoc | 153 ++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 articles/hilla/guides/i18n.adoc diff --git a/articles/hilla/guides/i18n.adoc b/articles/hilla/guides/i18n.adoc new file mode 100644 index 0000000000..d47e212b1f --- /dev/null +++ b/articles/hilla/guides/i18n.adoc @@ -0,0 +1,153 @@ +--- +title: Internationalization (i18n) +page-title: Adding Internationalization (i18n) to Hilla Applications +description: Enable multilingual support in Hilla applications by configuring and using the Hilla i18n system. +meta-description: Guide to setting up and using internationalization (i18n) with Hilla applications. +order: 140 +--- + += [since:com.vaadin:vaadin@V24.6]#Internationalization (i18n) Support# + +You can easily add internationalization (i18n) support to your Hilla applications using the `@vaadin/hilla-react-i18n` package. This guide walks you through setting up and using the feature effectively to create multilingual user interfaces. + +[NOTE] +==== +Internationalization in Hilla is still under active development and is not yet suitable for production. Therefore, to use it in Vaadin projects, you'll need to enable explicitly the experimental feature in Copilot, or add `com.vaadin.experimental.hillaI18n=true` to the [filename]`src/main/resources/vaadin-featureflags.properties` file. +==== + +== Add and Configure `i18n` + +First, import the `i18n` module and call the `configure` method during your application setup or in your main view initialization. + +[source,typescript] +---- +import { effect } from '@vaadin/hilla-react-signals'; +import { i18n } from '@vaadin/hilla-react-i18n'; + +effect(() => { + i18n.configure(); +}); +---- + +=== Behavior Details + +By default, the system uses the browser's language (`navigator.language`). If a user has previously selected a language, it will be remembered in a cookie. You can also explicitly configure the language during setup: + +[source,typescript] +---- +i18n.configure({ language: 'de-DE' }); +---- + +Configuration marks the system as initialized, allowing your UI to react accordingly. + +== Create and Place Translation Files + +Translation files must be placed in the following file: + +---- +src/main/resources/vaadin-i18n/translations.properties +---- + +These files follow the standard Java `.properties` file format, where each line contains a key-value pair separated by an equals sign (`=`). Keys represent the translation identifiers, and values are the corresponding translations. + +Example of a `translations.properties` file for English: + +---- +addresses.form.city.label=City +addresses.form.street.label=Street +---- + +To add support for other languages, create additional `.properties` files with the language code appended to the filename. For example, to add German translations, create a file named `translations_de.properties`: + +---- +addresses.form.city.label=Stadt +addresses.form.street.label=Straße +---- + +The system automatically selects the appropriate file based on the active language. Language codes are structured to represent the language and optional regional variations, such as `en` for English or `en-US` for American English. + +If a translation is missing in the most specific file (e.g., `translations_de_DE.properties`), the system gracefully falls back to a less specific file (e.g., `translations_de.properties`). If no match is found, it defaults to the base file (`translations.properties`), ensuring the application remains functional even when translations are incomplete. + +== Use the `translate` Function + +The `translate` function retrieves translated strings based on the active language. + +[source,tsx] +---- +import { translate } from '@vaadin/hilla-react-i18n'; + +return
{translate('addresses.form.city.label')}
; +---- + +If a translation is missing, the key will be shown as-is. + +== React Integration + +i18n is deeply integrated into the reactive programming model of Hilla. Components automatically update when the language changes. Signal-based reactivity (`useSignalEffect`, `useComputed`) works seamlessly. + +Example using computed signals: + +[source,tsx] +---- +import { useComputed } from '@vaadin/hilla-react-signals'; +import { translate } from '@vaadin/hilla-react-i18n'; + +function OrderSummary({ itemCount }: { itemCount: number }) { + const orderMessage = useComputed(() => { + if (itemCount === 0) { + return translate('order.empty'); + } else { + return translate('order.details', { count: itemCount }); + } + }); + + return
{orderMessage.value}
; +} +---- + +You can also show placeholders before i18n is initialized: + +[source,tsx] +---- +{i18n.initialized.value ? : } +---- + +== Dynamically Changing the Language + +You can switch the language at runtime to adapt to user preferences. + +[source,typescript] +---- +i18n.setLanguage('de-DE'); +---- + +== ICU Message Format Support + +Hilla's i18n system supports the ICU Message Format, enabling advanced translation scenarios like pluralization, selection, and number/date formatting. + +Example in `translations.properties`: + +[source,properties] +---- +messages.count=You have {count, plural, one {# message} other {# messages}}. +---- + +Usage example: + +[source,typescript] +---- +translate('messages.count', { count: 5 }); // Output: "You have 5 messages." +---- + +Supported ICU features include: + +- dynamic number and date formatting; +- plural forms; +- gender and value-based selections; +- escaping special characters. + +== Hot Module Replacement (HMR) in Development + +During development, translation files update automatically through Hot Module Replacement (HMR). No manual reload is needed: when translations change, they are automatically fetched and applied. + +With these tools, building responsive and adaptable multilingual applications with Hilla becomes intuitive and efficient. From 0de429263d03397be3583472cc48dc91909b7ff0 Mon Sep 17 00:00:00 2001 From: Luciano Vernaschi Date: Thu, 5 Jun 2025 12:03:41 +0200 Subject: [PATCH 2/5] Add `key` and `translateDynamic` --- articles/hilla/guides/i18n.adoc | 67 ++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/articles/hilla/guides/i18n.adoc b/articles/hilla/guides/i18n.adoc index d47e212b1f..bbbc753fde 100644 --- a/articles/hilla/guides/i18n.adoc +++ b/articles/hilla/guides/i18n.adoc @@ -6,14 +6,9 @@ meta-description: Guide to setting up and using internationalization (i18n) with order: 140 --- -= [since:com.vaadin:vaadin@V24.6]#Internationalization (i18n) Support# += [since:com.vaadin:vaadin@V24.6]#Internationalization (I18n) Support# -You can easily add internationalization (i18n) support to your Hilla applications using the `@vaadin/hilla-react-i18n` package. This guide walks you through setting up and using the feature effectively to create multilingual user interfaces. - -[NOTE] -==== -Internationalization in Hilla is still under active development and is not yet suitable for production. Therefore, to use it in Vaadin projects, you'll need to enable explicitly the experimental feature in Copilot, or add `com.vaadin.experimental.hillaI18n=true` to the [filename]`src/main/resources/vaadin-featureflags.properties` file. -==== +You can add internationalization (i18n) support to your Hilla applications using the `@vaadin/hilla-react-i18n` package. This guide walks you through setting up and using the feature effectively to create multilingual user interfaces. == Add and Configure `i18n` @@ -70,13 +65,13 @@ If a translation is missing in the most specific file (e.g., `translations_de_DE == Use the `translate` Function -The `translate` function retrieves translated strings based on the active language. +The `translate` function retrieves translated strings based on the active language. Those strings must be marked with the `key` tag, so that Hilla can identify them and include in the right chunk when building the application for production. [source,tsx] ---- -import { translate } from '@vaadin/hilla-react-i18n'; +import { key, translate } from '@vaadin/hilla-react-i18n'; -return
{translate('addresses.form.city.label')}
; +return
{translate(key`addresses.form.city.label`)}
; ---- If a translation is missing, the key will be shown as-is. @@ -90,14 +85,14 @@ Example using computed signals: [source,tsx] ---- import { useComputed } from '@vaadin/hilla-react-signals'; -import { translate } from '@vaadin/hilla-react-i18n'; +import { key, translate } from '@vaadin/hilla-react-i18n'; function OrderSummary({ itemCount }: { itemCount: number }) { const orderMessage = useComputed(() => { if (itemCount === 0) { - return translate('order.empty'); + return translate(key`order.empty`); } else { - return translate('order.details', { count: itemCount }); + return translate(key`order.details`, { count: itemCount }); } }); @@ -112,6 +107,50 @@ You can also show placeholders before i18n is initialized: {i18n.initialized.value ? : } ---- +== File Router Integration + +The file router allows you to define a <> for each view. This configuration contains elements that are good targets for translation, such as the page title and the menu link title. + +Because translation keys need to be discoverable by the build system, use the `key` tag to mark these elements: + +[source,tsx] +.`src/main/frontend/views/about.tsx` +---- +import type { ViewConfig } from '@vaadin/hilla-file-router/types.js'; +import { key } from '@vaadin/hilla-react-i18n'; + +export default function AboutView() { + return ( + /* ... */ + ); +} + +export const config: ViewConfig = { + title: key`about.title`, + menu: { + title: key`about.menuTitle`, + }, +}; +---- + +When creating the menu, use the `translateDynamic` function to retrieve translated values. Unlike `translate`, `translateDynamic` does not require the `key` tag and returns a `Signal` instead of a string. + +[source,tsx] +---- +import { i18n } from '@vaadin/hilla-react-i18n'; + +{createMenuItems().map(({ to, title, icon }) => ( + + {icon ? : <>} + {i18n.translateDynamic(title)} + +))} +---- + +A similar approach can be used for the page title. + +If the value passed to `translateDynamic` is not a translation key, a server call is made to retrieve the translation. To avoid performance issues, use `translateDynamic` only with known keys. If the received string is a key, `translateDynamic` behaves like `translate` and returns the translation efficiently. + == Dynamically Changing the Language You can switch the language at runtime to adapt to user preferences. @@ -136,7 +175,7 @@ Usage example: [source,typescript] ---- -translate('messages.count', { count: 5 }); // Output: "You have 5 messages." +translate(key`messages.count`, { count: 5 }); // Output: "You have 5 messages." ---- Supported ICU features include: From b01771c1f580affbee25e7ee82a49004b4e9c57e Mon Sep 17 00:00:00 2001 From: Luciano Vernaschi Date: Thu, 5 Jun 2025 12:13:25 +0200 Subject: [PATCH 3/5] Address Vale --- articles/hilla/guides/i18n.adoc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/articles/hilla/guides/i18n.adoc b/articles/hilla/guides/i18n.adoc index bbbc753fde..d43807c1de 100644 --- a/articles/hilla/guides/i18n.adoc +++ b/articles/hilla/guides/i18n.adoc @@ -1,6 +1,6 @@ --- -title: Internationalization (i18n) -page-title: Adding Internationalization (i18n) to Hilla Applications +title: Internationalization (I18n) +page-title: Adding Internationalization (I18n) to Hilla Applications description: Enable multilingual support in Hilla applications by configuring and using the Hilla i18n system. meta-description: Guide to setting up and using internationalization (i18n) with Hilla applications. order: 140 @@ -26,7 +26,7 @@ effect(() => { === Behavior Details -By default, the system uses the browser's language (`navigator.language`). If a user has previously selected a language, it will be remembered in a cookie. You can also explicitly configure the language during setup: +By default, the system uses the browser's language (`navigator.language`). If a user has previously selected a language, it is remembered in a cookie. You can also explicitly configure the language during setup: [source,typescript] ---- @@ -74,7 +74,7 @@ import { key, translate } from '@vaadin/hilla-react-i18n'; return
{translate(key`addresses.form.city.label`)}
; ---- -If a translation is missing, the key will be shown as-is. +If a translation is missing, the key is shown as-is. == React Integration @@ -160,6 +160,7 @@ You can switch the language at runtime to adapt to user preferences. i18n.setLanguage('de-DE'); ---- +[[icu]] == ICU Message Format Support Hilla's i18n system supports the ICU Message Format, enabling advanced translation scenarios like pluralization, selection, and number/date formatting. From 6ed220b0720fb4b2f3a1f28c9db73939f979ba7b Mon Sep 17 00:00:00 2001 From: Luciano Vernaschi Date: Thu, 5 Jun 2025 12:22:08 +0200 Subject: [PATCH 4/5] Address Vale (again) --- articles/hilla/guides/i18n.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/articles/hilla/guides/i18n.adoc b/articles/hilla/guides/i18n.adoc index d43807c1de..43a74521e7 100644 --- a/articles/hilla/guides/i18n.adoc +++ b/articles/hilla/guides/i18n.adoc @@ -160,10 +160,9 @@ You can switch the language at runtime to adapt to user preferences. i18n.setLanguage('de-DE'); ---- -[[icu]] == ICU Message Format Support -Hilla's i18n system supports the ICU Message Format, enabling advanced translation scenarios like pluralization, selection, and number/date formatting. +Hilla's i18n system supports the ICU (International Components for Unicode) Message Format, enabling advanced translation scenarios like pluralization, selection, and number/date formatting. Example in `translations.properties`: From c6219ee4104b16c68f1c6ac0d7b526c6470a5190 Mon Sep 17 00:00:00 2001 From: Luciano Vernaschi Date: Thu, 5 Jun 2025 12:42:00 +0200 Subject: [PATCH 5/5] Change acronym definition format --- articles/hilla/guides/i18n.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/articles/hilla/guides/i18n.adoc b/articles/hilla/guides/i18n.adoc index 43a74521e7..47e4f6d4f0 100644 --- a/articles/hilla/guides/i18n.adoc +++ b/articles/hilla/guides/i18n.adoc @@ -162,7 +162,7 @@ i18n.setLanguage('de-DE'); == ICU Message Format Support -Hilla's i18n system supports the ICU (International Components for Unicode) Message Format, enabling advanced translation scenarios like pluralization, selection, and number/date formatting. +Hilla's i18n system supports the International Components for Unicode (ICU) Message Format, enabling advanced translation scenarios like pluralization, selection, and number/date formatting. Example in `translations.properties`: