diff --git a/articles/building-apps/forms-data/create-custom-field/index.adoc b/articles/building-apps/forms-data/create-custom-field/index.adoc index ce6f57ceb4..bd1932bbcc 100644 --- a/articles/building-apps/forms-data/create-custom-field/index.adoc +++ b/articles/building-apps/forms-data/create-custom-field/index.adoc @@ -652,7 +652,7 @@ Always call `updateI18n()` whenever texts should be refreshed, for example, insi === Further Reading -For more details on localization in Vaadin, see the <<{articles}/flow/advanced/i18n-localization#,Localization>> article. +For more details on localization in Vaadin, see the <<{articles}/flow/i18n#,Localization>> article. == Accessibility diff --git a/articles/components/date-picker/date-formats.adoc b/articles/components/date-picker/date-formats.adoc index cbf1d3d4a9..12e69e0e77 100644 --- a/articles/components/date-picker/date-formats.adoc +++ b/articles/components/date-picker/date-formats.adoc @@ -17,7 +17,7 @@ Two-digit year formats are supported, and you can set the <>). Setting a specific locale ensures that all users see the same format. +By default, Date Picker displays and parses dates using the user's locale (<<{articles}/flow/i18n#locale-selection,reference>>). Setting a specific locale ensures that all users see the same format. In the example here, the Date Picker is set to the date format used in Finland: diff --git a/articles/flow/advanced/i18n-localization.adoc b/articles/flow/advanced/i18n-localization.adoc deleted file mode 100644 index 01528ac5fa..0000000000 --- a/articles/flow/advanced/i18n-localization.adoc +++ /dev/null @@ -1,282 +0,0 @@ ---- -title: Localization -page-title: How to localize Vaadin apps with i18n -description: Implementing localization and translation strings using I18NProvider. -meta-description: Set up internationalization in Vaadin for multilingual support. -order: 20 ---- - - -= Localization - -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 [classname]`DefaultI18NProvider`. - -The file `translations.properties` is a default translation file that'll be used for any [classname]`Locale` that doesn't have a specific translations file. Locale translation files are named, for example, like [filename]`translations_fi_FI.properties` or [filename]`translations_de.properties`. The automatic [classname]`Locale` creation supports from one to three parts (e.g., `translations_language_country_variant.properties`). - -[NOTE] -[classname]`DefaultI18NProvider` is available as of version 24.3 of Vaadin Flow. For an earlier version, you'll need to implement your own [interfacename]`I18NProvider`, as documented in <<#defining-i18n-provider-property,Defining I18n Provider Property>> section. - - -== Locale Selection for New Session - -The initial locale is determined by matching the locales provided by the [classname]`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 [methodname]`I18NProvider.getProvidedLocales()`. If that's empty, [methodname]`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 [interfacename]`LocaleChangeObserver` to receive events related to locale change. This observer is also notified on navigation when the component is attached, but before [methodname]`onAttach()` is called. Any URL parameters from the navigation are set so that they can be used to determine the state. - -[source,java] ----- -public class LocaleObserver extends Div implements LocaleChangeObserver { - - @Override - public void localeChange(LocaleChangeEvent event) { - setText(getTranslation("my.translation", getUserId())); - } -} ----- - - -==== Using Localization without LocaleChangeObserver - -.I18NProvider without [interfacename]`LocaleChangeObserver` -[source,java] ----- -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 [interfacename]`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 [interfacename]`I18NProvider`. - -The `i18n.provider` property can be set from the command-line as a system property, as a Servlet initial parameter in the [filename]`web.xml` file, or using the `@WebServlet` annotation. - -As a system property, the parameter needs the `vaadin` prefix like this: - -[source,terminal] ----- -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: - -[source,java] ----- -@WebServlet(urlPatterns = "/*", name = "slot", asyncSupported = true, loadOnStartup = 1, - initParams = { @WebInitParam(name = "i18n.provider", value = "com.vaadin.example.ui.TranslationProvider") }) -public class ApplicationServlet extends VaadinServlet { -} ----- - -Or, if you prefer to use the [filename]`web.xml` file, you might set it as this: - -[source,xml] ----- - - - - - myservlet - - com.vaadin.flow.server.VaadinServlet - - 1 - - - i18n.provider - com.vaadin.example.ui.TranslationProvider - - - - - myservlet - /* - - ----- - -You can provide an [interfacename]`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 https://github.com/vaadin/flow-spring-tutorial/blob/master/src/main/java/org/vaadin/spring/tutorial/SimpleI18NProvider.java[`SimpleI18NProvider.java`] implemented in the tutorial project as an example. - - -[[provider-sample-for-translation]] -== 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 [filename]`.properties` files start with "translate": for example, [filename]`translate.properties` for the default, as well as [filename]`translate_fi_FI.properties`, and [filename]`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`. - -.I18NProvider Implementation Example -[source,java] ----- -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 locales = Collections - .unmodifiableList(Arrays.asList(LOCALE_FI, LOCALE_EN)); - - @Override - public List 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 <>, in your main layout you can add code such as the following: - -[source,java] ----- -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 [interfacename]`LocaleChangeObserver` interface. In this way, it receives changes of locale, so you can then set the text direction based on the specified locale: - -[source,java] ----- -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 [classname]`ElementMixin`, no changes are needed. Otherwise, you can have the element extend it or [classname]`DirMixin` only (i.e., [classname]`DirMixin` is part of the `@vaadin/component-base` package). - -[source,javascript] ----- -import { PolymerElement } from '@polymer/polymer/polymer-element.js'; -import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js'; - -class MyElement extends DirMixin(PolymerElement) {} ----- - -The [classname]`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: - -[source,css] ----- -:host { - padding-right: 1em; - padding-left: 2em; -} ----- - -You may want to define the style for right-to-left, as follows: - -[source,css] ----- -: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 https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties[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 https://rtlstyling.com/posts/rtl-styling/[comprehensive right-to-left styling guide]. - -For help with adjusting styles for right-to-left mode, you can use the tools available on the https://rtlcss.com/playground/#[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: - -[source,javascript] ----- -// 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. - -[discussion-id]`722E7AE4-191E-4DE8-90F1-CAE8AE6CD3DF` diff --git a/articles/flow/configuration/properties.adoc b/articles/flow/configuration/properties.adoc index c476c1756b..93c3de3327 100644 --- a/articles/flow/configuration/properties.adoc +++ b/articles/flow/configuration/properties.adoc @@ -228,7 +228,7 @@ Default: 300 seconds (i.e., 5 minutes) + Mode: Runtime `**i18n.provider**`:: -Sets the fully-qualified name for the internationalization provider class. To translate strings for localization, the application should implement the `I18NProvider` interface and define the class name in the `i18n.provider` property. See the <<{articles}/flow/advanced/i18n-localization#, Localization documentation>> for details. + +Sets the fully-qualified name for the internationalization provider class. To translate strings for localization, the application should implement the `I18NProvider` interface and define the class name in the `i18n.provider` property. See the <<{articles}/flow/i18n#, Localization documentation>> for details. + Default: `null` + Mode: Runtime diff --git a/articles/flow/i18n/custom-element-rtl.adoc b/articles/flow/i18n/custom-element-rtl.adoc new file mode 100644 index 0000000000..f6a785cf55 --- /dev/null +++ b/articles/flow/i18n/custom-element-rtl.adoc @@ -0,0 +1,90 @@ +--- +title: RTL Support for Custom Elements +page-title: RTL Support for Custom Elements - Vaadin Docs +description: Adding right-to-left support to custom web components and styles. +meta-description: Learn how to add right-to-left (RTL) support to custom web components, styles, icons, and keyboard navigation in Vaadin applications. +order: 20 +--- + + += RTL Support for Custom Elements + +Vaadin components support right-to-left (RTL) text direction out of the box. If you have custom elements or custom styles, there are additional steps to enable RTL support. + + +== DirMixin for Custom Elements + +If your element extends Vaadin's `ElementMixin`, no changes are needed. Otherwise, have the element extend `DirMixin` (from `@vaadin/component-base`): + +[source,javascript] +---- +import { LitElement } from 'lit'; +import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js'; +import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js'; + +class MyElement extends DirMixin(PolylitMixin(LitElement)) {} +---- + +`DirMixin` synchronizes the element's `dir` attribute with the document-level `dir` attribute, allowing CSS and JS code to respond to text direction changes. + + +== Adjusting Styles for RTL + +Review properties like `padding`, `margin`, `text-align`, `float`, and `transform`. For example, if your styles define directional padding: + +[source,css] +---- +:host { + padding-right: 1em; + padding-left: 2em; +} +---- + +Add an RTL override: + +[source,css] +---- +:host([dir="rtl"]) { + padding-right: 2em; + padding-left: 1em; +} +---- + +You can replace directional properties with https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties[CSS Logical Properties]. Flex and Grid containers are handled well by the browser and typically don't require adjustments. + +For help adjusting styles, you can use the tools at https://rtlcss.com/playground/#[RTLCSS]. See also this https://rtlstyling.com/posts/rtl-styling/[comprehensive right-to-left styling guide]. + + +== Icons and Directional Symbols + +If your element uses icons or Unicode symbols that indicate direction (e.g., a _Back_ button arrow), use the appropriate icons for RTL mode. + + +== Keyboard Navigation + +If keyboard interactions use arrow keys for navigation, adjust the direction based on the `dir` attribute: + +[source,javascript] +---- +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 also need adjustments for RTL. + +If you have visual tests, consider adding or updating them to run in RTL mode as well. + + +== Frontend-Only RTL + +For frontend-only applications, set `document.dir = 'rtl'` to enable right-to-left mode. diff --git a/articles/flow/i18n/custom-i18n-provider.adoc b/articles/flow/i18n/custom-i18n-provider.adoc new file mode 100644 index 0000000000..6907c6fc4e --- /dev/null +++ b/articles/flow/i18n/custom-i18n-provider.adoc @@ -0,0 +1,92 @@ +--- +title: Custom I18N Provider +page-title: Custom I18N Provider for Vaadin - Vaadin Docs +description: Implementing a custom I18NProvider for advanced localization needs. +meta-description: Learn how to implement a custom I18NProvider in Vaadin for loading translations from databases, using custom file structures, or other advanced i18n needs. +order: 10 +--- + + += Custom I18N Provider + +The built-in `DefaultI18NProvider` loads translations from property files in `src/main/resources/vaadin-i18n/`. If you need more control -- loading translations from a database, using a different file structure, or applying custom fallback logic -- implement the `I18NProvider` interface. + + +== Implementing I18NProvider + +The following example enables Finnish and English, with Finnish as the default. Translation files use the `translate` prefix (e.g., `translate.properties`, `translate_fi_FI.properties`, `translate_en_GB.properties`) and are loaded from the classpath (e.g., `src/main/resources/`): + +[source,java] +---- +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 locales = Collections + .unmodifiableList(Arrays.asList(LOCALE_FI, LOCALE_EN)); + + @Override + public List 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; + } +} +---- + + +== Configuring the Provider + +For Spring Boot projects, annotate your provider with `@Component` and it's automatically detected -- no further configuration needed: + +[source,java] +---- +@Component +public class TranslationProvider implements I18NProvider { + // ... +} +---- + +CDI-based projects can use a similar approach with CDI beans. + +For other setups, set the `i18n.provider` property to the fully qualified class name of your provider, either as a system property: + +[source,terminal] +---- +mvn jetty:run -Dvaadin.i18n.provider=com.vaadin.example.ui.TranslationProvider +---- + +Or via the `@WebServlet` annotation: + +[source,java] +---- +@WebServlet(urlPatterns = "/*", name = "slot", asyncSupported = true, loadOnStartup = 1, + initParams = { @WebInitParam(name = "i18n.provider", value = "com.vaadin.example.ui.TranslationProvider") }) +public class ApplicationServlet extends VaadinServlet { +} +---- diff --git a/articles/flow/i18n/index.adoc b/articles/flow/i18n/index.adoc new file mode 100644 index 0000000000..edd26a872c --- /dev/null +++ b/articles/flow/i18n/index.adoc @@ -0,0 +1,316 @@ +--- +title: Localization +page-title: How to Localize Vaadin Applications - Vaadin Docs +description: Translate strings, switch languages, localize numbers and dates. +meta-description: Learn how to internationalize and localize Vaadin applications with translation strings, locale selection, component i18n, and number and date formatting. +order: 75 +--- + + += Localization + +Vaadin has built-in support for localizing applications. This page covers translating strings, letting users pick a language, translating Vaadin component labels, and formatting numbers and dates for different locales. + + +== Translation Strings + +Call `getTranslation()` from any Vaadin component to look up a translation key for the current locale. Parameters are substituted into `{0}`, `{1}`, etc. placeholders using `MessageFormat`: + +[source,java] +---- +Span title = new Span(getTranslation("app.title")); +Span greeting = new Span(getTranslation("greeting", user.getName())); +---- + + +=== Where Translations Are Stored + +By default, translations are loaded from property files in `src/main/resources/vaadin-i18n/`, with the filename prefix `translations`: + +- `translations.properties` -- default translations (fallback) +- `translations_en.properties` -- English +- `translations_es.properties` -- Spanish +- `translations_de.properties` -- German + +The filename supports up to three parts: `translations_language_country_variant.properties` (e.g., `translations_en_US.properties`). + +.translations.properties +[source,properties] +---- +app.title=My Application +greeting=Hello, {0}! +items.count=You have {0} items. +---- + +.translations_es.properties +[source,properties] +---- +app.title=Mi Aplicación +greeting=¡Hola, {0}! +items.count=Tienes {0} artículos. +---- + +[NOTE] +Translation files are discovered automatically at runtime. You don't need to register them -- just place them in `src/main/resources/vaadin-i18n/`. + +To load translations from another source -- such as a database, a remote service, or a different file structure -- implement a custom `I18NProvider`. See <> for details. + + +=== Reacting to Locale Changes + +Implement `LocaleChangeObserver` to update translations when the locale changes. The observer is called on navigation when the component is attached, but before `onAttach()`: + +[source,java] +---- +public class MainView extends VerticalLayout implements LocaleChangeObserver { + + private final Span title = new Span(); + private final Span greeting = new Span(); + + public MainView() { + add(title, greeting); + } + + @Override + public void localeChange(LocaleChangeEvent event) { + title.setText(getTranslation("app.title")); + greeting.setText(getTranslation("greeting", "World")); + } +} +---- + +[TIP] +Use Copilot to automate extraction of static strings into translation files. See <<{articles}/tools/copilot/i18n#,Internationalization in Copilot>>. + + +[[locale-selection]] +== Language Selection + +=== Automatic Locale from Browser + +When a session starts, Vaadin picks an initial locale by matching the browser's `Accept-Language` header against the locales reported by the active `I18NProvider` via `getProvidedLocales()`: + +1. If an exact match (language + country) is found, it's used. +2. Otherwise, a language-only match is tried. +3. If neither matches, `I18NProvider.getDefaultLocale()` is used, which by default is the first locale in `getProvidedLocales()`. + +With the built-in `DefaultI18NProvider`, the provided locales are discovered automatically from the `translations_*.properties` filenames in `src/main/resources/vaadin-i18n/` -- there's no separate list to declare. With a custom `I18NProvider`, you control both lists by implementing `getProvidedLocales()` and optionally `getDefaultLocale()`. + + +=== Changing the Locale Programmatically + +Set the locale for the current session with: + +[source,java] +---- +UI.getCurrent().setLocale(new Locale("es")); +---- + +This triggers a `LocaleChangeEvent` on all attached components that implement `LocaleChangeObserver`. + + +=== Language Switcher Example + +A language switcher lets users choose their preferred language: + +[source,java] +---- +public class LanguageSwitcher extends Select { + + public LanguageSwitcher() { + setItems( + Locale.ENGLISH, + Locale.FRENCH, + Locale.GERMAN, + new Locale("es") + ); + setItemLabelGenerator(locale -> locale.getDisplayLanguage(locale)); + setValue(UI.getCurrent().getLocale()); + + addValueChangeListener(event -> + UI.getCurrent().setLocale(event.getValue()) + ); + } +} +---- + + +== Translating Vaadin Component Strings + +Many Vaadin components have built-in strings for labels, error messages, and accessibility text (e.g., Upload, Login, Date Picker). These are localized using a component-specific i18n object passed to `setI18n()`. + +Each component defines its own i18n class. Create an instance, set the translated strings, and apply it: + +[source,java] +---- +Upload upload = new Upload(); + +UploadI18N i18n = new UploadI18N(); +i18n.getAddFiles().setOne(getTranslation("upload.add.file")); +i18n.getAddFiles().setMany(getTranslation("upload.add.files")); +i18n.getDropFiles().setOne(getTranslation("upload.drop.file")); +i18n.getDropFiles().setMany(getTranslation("upload.drop.files")); +i18n.getError().setFileIsTooBig(getTranslation("upload.error.file.too.big")); +upload.setI18n(i18n); +---- + +To update component i18n when the locale changes, do it inside `localeChange()`: + +[source,java] +---- +@Override +public void localeChange(LocaleChangeEvent event) { + UploadI18N i18n = new UploadI18N(); + i18n.getAddFiles().setOne(getTranslation("upload.add.file")); + // ... set other strings + upload.setI18n(i18n); +} +---- + +See the documentation for each component for its specific i18n properties and keys. + + +[[formatting-numbers-dates]] +== Formatting Numbers and Dates + +Java provides comprehensive locale-aware formatting for numbers, currency, and dates. + + +=== Number Formatting + +Use `NumberFormat` to format numbers according to locale conventions (decimal separators, grouping, etc.): + +[source,java] +---- +Locale locale = UI.getCurrent().getLocale(); + +NumberFormat numberFormat = NumberFormat.getInstance(locale); +String formatted = numberFormat.format(1234567.89); +// en_US: "1,234,567.89" +// de_DE: "1.234.567,89" +// es_ES: "1.234.567,89" +---- + + +=== Currency Formatting + +[source,java] +---- +NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale); +String price = currencyFormat.format(49.99); +// en_US: "$49.99" +// de_DE: "49,99 €" +// ja_JP: "¥50" +---- + +For a specific currency regardless of locale: + +[source,java] +---- +NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale); +currencyFormat.setCurrency(Currency.getInstance("EUR")); +String price = currencyFormat.format(49.99); +// en_US: "€49.99" +// de_DE: "49,99 €" +---- + + +=== Custom Number Patterns + +Use `DecimalFormat` for custom patterns: + +[source,java] +---- +DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale); +DecimalFormat format = new DecimalFormat("#,##0.00", symbols); +String result = format.format(1234.5); +// Uses locale-specific grouping and decimal separators +---- + + +=== Date and Time Formatting + +Use `DateTimeFormatter` with locale for localized date and time output: + +[source,java] +---- +LocalDate date = LocalDate.now(); +Locale locale = UI.getCurrent().getLocale(); + +// Localized styles +DateTimeFormatter shortDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) + .withLocale(locale); +DateTimeFormatter longDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG) + .withLocale(locale); + +String shortFormatted = date.format(shortDate); +// en_US: "3/10/26" +// de_DE: "10.03.26" + +String longFormatted = date.format(longDate); +// en_US: "March 10, 2026" +// de_DE: "10. März 2026" +---- + +For date-time values: + +[source,java] +---- +LocalDateTime dateTime = LocalDateTime.now(); + +DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) + .withLocale(locale); +String formatted = dateTime.format(formatter); +---- + + +=== Custom Date Patterns + +[source,java] +---- +DateTimeFormatter custom = DateTimeFormatter.ofPattern("dd MMM yyyy", locale); +String formatted = LocalDate.now().format(custom); +// en_US: "10 Mar 2026" +// de_DE: "10 Mär 2026" +---- + +pass:[] + +=== Vaadin Components and Formatting + +pass:[] + +Some Vaadin components, such as Date Picker and Date Time Picker, handle their own date format localization through their i18n objects. You don't typically need to format dates manually for those components -- configure them through `setI18n()` and the component's locale. See the component documentation for details. + + +== Right-to-Left Languages + +Vaadin components support right-to-left (RTL) text direction out of the box. To enable it, set the UI direction based on the locale: + +[source,java] +---- +UI ui = UI.getCurrent(); +if ("ar".equals(ui.getLocale().getLanguage())) { + ui.setDirection(Direction.RIGHT_TO_LEFT); +} else { + ui.setDirection(Direction.LEFT_TO_RIGHT); +} +---- + +For reactive locale switching, set the direction inside `localeChange()`: + +[source,java] +---- +@Override +public void localeChange(LocaleChangeEvent event) { + if ("ar".equals(event.getLocale().getLanguage())) { + event.getUI().setDirection(Direction.RIGHT_TO_LEFT); + } else { + event.getUI().setDirection(Direction.LEFT_TO_RIGHT); + } +} +---- + +For details on adding RTL support to custom elements and custom styles, see <>. + +[discussion-id]`722E7AE4-191E-4DE8-90F1-CAE8AE6CD3DF` diff --git a/articles/tools/copilot/i18n.adoc b/articles/tools/copilot/i18n.adoc index ab726908e1..dc91f2d796 100644 --- a/articles/tools/copilot/i18n.adoc +++ b/articles/tools/copilot/i18n.adoc @@ -42,7 +42,7 @@ The panel also provides a button for clearing the currently stored screenshots. == Limitations -The internationalization feature expects translation property files to be stored in the standard Vaadin <<{articles}/flow/advanced/i18n-localization#, translation file folder>>, [filename]`src/main/resources/vaadin-i18n`. +The internationalization feature expects translation property files to be stored in the standard Vaadin <<{articles}/flow/i18n#, translation file folder>>, [filename]`src/main/resources/vaadin-i18n`. The default translation property file is expected to be called [filename]`translations.properties`. Files for other locales are expected to be named according to the [filename]`translations\_\[langcode\].properties` format, such as [filename]`translations\_en\_US.properties` for U.S. English.