flow icon indicating copy to clipboard operation
flow copied to clipboard

Add an alternative API for getTranslation

Open tomivirkki opened this issue 3 months ago • 1 comments

Describe your motivation

The current getTranslation API is convenient when used inside a parent layout because it's inherited from Component. However, if you need to get a translation for a key somewhere where this API isn't inherited there aren't convenient options available. One such case is a static factory method for creating components:

private static TextField createField() {
    return new TextField("Your name");
}

In this scenario, you could access the getTranslation API, for example, via VaadinService.getCurrent().getInstantiator().getI18NProvider() but a helper method would be required to avoid verbosity.

Another approach could be not setting the field's label in the constructor and using the instance itself to access getTranslation.

var field = new TextField();
field.setLabel(field.getTranslation("yourname.label"));

However, this method requires referencing a component instance, even though obtaining a localized string isn't a task inherently tied to a specific instance.

Describe the solution you'd like

Introduce a method for obtaining translations through an API not bound to a component instance but available universally.

I don't have a well-thought-out API suggestion at this time, but perhaps a static method would work here, so the usage could be similar to that of @vaadin/hilla-react-i18n:

import static com.vaadin.flow.i18n.I18NProvider.translate;

...

private static TextField createField() {
    return new TextField(translate("yourname.label"));
}

Additional context

The absence of such an API poses challenges with the Copilot i18n plugin, which automatically transforms static strings to getTranslate calls. Since it's not context-aware, in the worst-case scenario, it might produce a view class that doesn't compile. See the workaround under consideration for more details.

tomivirkki avatar May 08 '24 12:05 tomivirkki

Alternative suggestion: Add a constructor/methods that takes in some kind of custom class e.g. "Translateable(String template, Object...)" so that the components can translate it on demand.


private static TextField createField(User user) {
    return new TextField(Translatable.of("yourname.label", user.getName()));
}

knoobie avatar May 08 '24 12:05 knoobie

I suggest to add two new static methods in I18NProvider interface:

static String translate(String key, Object... params)
static String translate(String key, Locale locale, Object... params)

These methods would only work within an active Vaadin service. Without it, these would either throw exception or return empty String.

In addition, in some future version there could be also new type like Translateable, it could contain at minimum a key. Optionally also array of Object params and Locale object. Adding one would mean that i18n API needs new set of methods that supports the new type. And later components could be updated to fully support it.

tltv avatar May 24 '24 09:05 tltv