Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default locale should be the clients locale and not the servers locale #15947

Open
SebastianDietrich opened this issue Feb 17, 2023 · 14 comments

Comments

@SebastianDietrich
Copy link

SebastianDietrich commented Feb 17, 2023

Describe your motivation

Default locale should be the users locale. This is even written in the documentation (see e.g. "By default, Date Picker displays and parses dates using the user’s locale"). Unfortunately this works only for the locales provided by an I18NProvider. If no I18NProvider is available, the servers locale is used.

Many applications don't need I18N but still want to display fields based on the users locale. They are forced to implement an I18NProvider and guess all possible locales the users might be using, falling back to the servers locale if the guess is wrong.

Describe the solution you'd like

The default locale should be the users locale even if no I18NProvider is available - i.e. same functionality as if an I18NProvider was given without translations but all possible locales provided.

Describe alternatives you've considered

Getting the locale from VaadinRequest.getCurrent().getLocale() and setting it (e.g. in a VaadinServiceInitListener) as proposed in https://discord.com/channels/732335336448852018/1075373133290283189 - a possible workaround

Additional context

According to Frettman the workaround works (I've not tested it), so a similar request mentioned in discord (#5377) is probably fixed and can be closed.

@Legioth
Copy link
Member

Legioth commented Feb 17, 2023

You cannot assume that the browser locale is the same as the user's locale. It's more likely that a consistent user experience is achieved if the locale is the same for all users. See #12203 (comment) for more discussion on that topic.

At the same time, I agree that it it would be good to have an easier way for the application to opt in to use the browser locale.

@SebastianDietrich
Copy link
Author

SebastianDietrich commented Feb 17, 2023

That is true, but if I provide an I18NProvider then it is assumed that the browser locale is the same as the user's locale. So at least it is inconsistent behaviour

@SebastianDietrich
Copy link
Author

SebastianDietrich commented Feb 18, 2023

To sum up the inconsistent default behaviour:

  • users locale, according to documentation of DatePicker
  • current locale, according to documentation of DateTimePicker
  • servers locale, if there is no I18NProvider
  • servers locale, if the provided I18NProviders getProvidedLocales() returns an empty list
  • first locale in list, if the provided I18NProvider getProvidedLocales() doesn't include the browsers locale
  • browsers locale, if the provided I18NProviders getProvidedLocales() does include the browsers locale

IMHO most developers would expect the browsers locale to be the default locale and most ops would not expect the ui to change when they change the servers locale. Having to reset the locale via a VaadinServiceInitListener or providing an I18NProvider with all possible locales is advanced and too much work to achieve such behaviour.

@Frettman
Copy link

I think the current system makes things very consistent: only pick from locales that the application supports.
Picking a locale to format some things that doesn't match the text of the application doesn't make much sense to me.

Even when there's no I18NProvider, the application implicitly supports a specific language/locale - a locale that might not match the current system's locale. So maybe a configurable default locale would make sense here?

This would even be useful with an I18NProvider: Instead of just picking the first locale returned by I18NProvider#getProvidedLocales() (which currently happens when the browser locale doesn't match any provided locale and in cases where no other locale is available), pick the explicitly configured one.

Btw, DatePicker and DateTimePicker - like all other Components - have the same default behavior: Use the UI's locale if set (based on provided locales and browser locale); otherwise use first locale of I18NProvider.

@SebastianDietrich
Copy link
Author

I suppose that most or at least many applications would like to support all locales, even if they don't support multiple or all languages. This behavior is currently not supported and would not be supported by a cofigurable default locale either (unless one can configure the default locale to be the browsers locale).

e.g. my customer is in aero industy, they communicate in English with worldwide customers (of different/unknown nationalities / languages), so their application is purely in English. But when it comes to enter or display numbers, thir users expect them to be according to their users locale - so e.g "1,00" for german speaking users and "1.00" for english speaking users. The enter numbers via the numeric keyboard, which on a german keyboard has a "," where an english keyboard has a ".".

@Frettman
Copy link

Hmm, then Vaadin would need two separate locales. Basically in the same way that Java itself can have a default DISPLAY locale (for the text) that can be different from the default FORMAT locale.

@SebastianDietrich
Copy link
Author

That would be correct, if ones assumes that a user willingly wants the DISPLAY locale to be different from the FORMAT locale. I don't think that will ever be the case:

  • If users selects a language, then they would expect both the DISPLAY and FORMAT locale to be according to their selected language.
  • If there is no selection since the application is in one language only (like it is the case with many UIs, including my situation but as well the Vaadin homepage), then setting the locale can only affect the FORMAT locale which should IMHO be the browsers locale (this RFE) and not the servers locale (current situation) which is often different from the language of the application.

@Legioth
Copy link
Member

Legioth commented Feb 26, 2023

then setting the locale can only affect the FORMAT locale which should IMHO be the browsers locale (this RFE) and not the servers locale (current situation) which is often different from the language of the application.

My claim is that the format locale should by default be the same as the (implicit) display locale. That's the only way of having an application that is deterministic and consistent.

There's still room for Vaadin to make things easier for application developers. There should be an easy way for the application to override the server locale (e.g. for the cases where it's shared between multiple applications) and there should also be an easy way for the application to opt in to using the browser locale.

@SebastianDietrich
Copy link
Author

There should be an easy way for the application to override the server locale (e.g. for the cases where it's shared between multiple applications) and there should also be an easy way for the application to opt in to using the browser locale.

+1 for that

My claim is that the format locale should by default be the same as the (implicit) display locale.

What do you mean by "(implicit) display locale". What if the servers locale is en-US, the application is in German (no I18NProvider, no translation) and the browsers locale is fi-FI? There is no way to ensure consistency between display and format locale.

But we need a deterministic and consistent way to determine the default locale. Right now this is not consistent (see my 3rd post). The only way to make that consistent would be to have the browsers locale as default:

  • browsers locale, if there is no I18NProvider (currently servers locale)
  • browsers locale, if the provided I18NProviders getProvidedLocales() doesn't include the browsers locale (currently servers locale)
  • browsers locale, if the provided I18NProviders getProvidedLocales() does include the browsers locale

@Frettman
Copy link

Correction to your 3rd post: The server locale is only used when getProvidedLocales() returns an empty list. If it provides at least one locale, the first locale in the list is used as the default, if no other locale matches.
I'd prefer an explicit configurable default locale instead of the implicit "just pick the first from the list". But my I18NProvider just sorts them accordingly based on a property.
Either way, it makes a lot more sense to me than choosing the browser locale if it's not among the provided ones. That would defeat the whole purpose of having a getProvidedLocales() in the first place.
The only gray area is a missing I18NProvider or an empty getProvidedLocales(). Then both the server or browser locale would just be best effort guesses to have any locale at all. Both are suboptimal, but as a default I would prefer something that doesn't change between users. (After re-reading, a clarification: My thinking is based on the assumption that the UI's locale which is determined by this process should generally represent the language/locale of its displayed text).

BUT I can see a use case where e.g. you would want to use the date and number format of the browser locale, regardless of the displayed language. Currently, if your application does not have an I18NProvider you should be able to solve this by providing the suggested VaadinServiceInitListener. As the UI's locale is not used for translating, it will effectively only be used for formatting.
If there is an I18NProvider I would find it incredibly confusing and inconsistent if the UI's locale is not one of the provided locales. That's why I suggested having a separate format locale. This would provide the technical basis to allow that customization.
Other than that, I'm all for making things easier for developers. Like providing an interface that allows to more easily customize the logic that determines a UI's (display and format) locale. But the defaults seem good to me.

But that's just my 2 cents. I don't make the decisions around here ;)

@SebastianDietrich
Copy link
Author

Correction to your 3rd post: The server locale is only used when getProvidedLocales() returns an empty list.

That is correct - I've corrected my post. Unfortunately this makes things even less consistent:

  • servers locale, if there is no I18NProvider
  • servers locale, if the provided I18NProviders getProvidedLocales() returns an empty list
  • first locale in list, if the provided I18NProvider getProvidedLocales() doesn't include the browsers locale
  • browsers locale, if the provided I18NProviders getProvidedLocales() does include the browsers locale

I'd prefer an explicit configurable default locale instead of the implicit "just pick the first from the list".

I am not sure how this could work - how to force the developer to explicitly configure a default locale. And even if that could work, wouldn't it contradict the concept of "default"?

To sum it up: We need a better way to implicitly or easily explicitly set the locale (without explicitly setting it via a VaadinServiceInitListener). This should be as consistent as possible, work in all the situations mentioned above and be reflected in the documentation.

Since I cannot think of a situation, when the servers locale should determine the locale I would suggest:

  • browsers locale, if there is no I18NProvider
  • browsers locale, if the provided I18NProviders getProvidedLocales() returns an empty list
  • first locale in list, if the provided I18NProvider getProvidedLocales() doesn't include the browsers locale
  • browsers locale, if the provided I18NProviders getProvidedLocales() does include the browsers locale

@Legioth
Copy link
Member

Legioth commented Feb 28, 2023

Let's keep assuming that the API in Vaadin will be enhanced to make it trivial to define a single hardcoded UI locale or make the UI locale always use the browser locale. In this situation, it's convenient enough to make the application work in any way and the main design question is how to reduce the risk of surprises for someone who just keeps using the default without realizing that there is a choice to be made.

Assumptions

The first thing to realize is that Vaadin doesn't take care of all formatting in the application. Any text labels that include numbers or dates will be formatted by application logic. The next thing to realize is that only developers that come to think of browser locales would consider testing with different browser settings.

Unaware developers

Many developers have their OS set to a familiar locale and then their browser and their JVM is automatically using the same locale. They conveniently use the JVM locale for their own formatting needs and they never even consider the possibility that Vaadin might use some other locale. Their application logic uses String.format("Value: %.2f: ", value). If Vaadin would use the browser locale by default, then these developers would not notice until one of their users complains that the application has inconsistent decimal separators: (en-US browser with de-DE JVM):
Screenshot 2023-02-28 at 6 44 41

This surprise is avoided if Vaadin uses the JVM locale.

Aware developers

If we instead have a developer who is aware of browser locales and wants the application to use the browser locale for formatting, then I assume that they will explicitly test for that case. They would instead be surprised if Vaadin uses the JVM locale by default. The big difference is that this surprise occurs during development rather than in production. Furthermore, the developer would in this case need to use a longer pattern for values that are formatted by the application if they want their application to be consistent: String.format(UI.getCurrent().getLocale(), "Value: %.2f", value). If we assume there's a convenient API for making Vaadin use the browser locale, then the effort needed for enabling that option is much smaller than the effort needed for the application's own formatting.

Unexpected server settings

We finally have the case of an unexpected JVM locale on the production server. The fully aware developer would not be affected since they would already have configured Vaadin to use the browser locale if that wouldn't be the default. The unaware developer would have surprises regardless of how Vaadin works by default since the JVM locale is used in the cases where formatting is performed by application logic. The issue is probably easier to spot and understand if Vaadin uses the JVM locale by default since the same problem would be apparent in all parts of the application.

The convenient solution for the unaware developer would be to simply configure the server JVM locale to be consistent with their expectations. If that is not possible (e.g. because the JVM is shared with other applications), then they would have to go through all places where application logic formats values to make it use a hardcoded locale: String.format(applicationLocale, "Value: %.2f: ", value). If we assume there's a convenient API for making Vaadin use a hardcoded locale, then the effort needed for enabling that option is much smaller than the effort needed for the application's own formatting.

In-between developers

Finally, there's the case in between where the developer wants Vaadin to use the browser locale while they accept the inconsistency with values formatted by the application using the JVM locale (or a hardcoded locale). The reasoning behind this is usually that it's easier for the end user when they can see familiar month and weekday names in e.g. date pickers. I don't mind making it easy for the application developer to explicitly configure their application to have this inconsistency, but I don't think we should encourage it by using the browser locale by default.

@Frettman
Copy link

I am not sure how this could work - how to force the developer to explicitly configure a default locale. And even if that could work, wouldn't it contradict the concept of "default"?

My Spring-based library automatically picks up all available locales (based on the found resource bundles) during startup. And the application's default locale can be any one of them. It can be chosen implicitly based on the system locale (this is basically the default way to choose a default locale...) or explicitly via property. All this is logged so it's easy to see what's going on. In both cases, if there is no match in the available locales, there's a helpful error during startup with info on how to fix it.
This application-wide default locale is then used for all sorts of fallbacks.
To me this creates a predictable and consistent state and is neatly flexible (compared to e.g. having the default translations in the locale-less root bundle).
It's nice when defaults just always work. But in this case, the slight inconvenience of potentially having to configure one of the available locales as default is nothing compared to having a clearly defined and known state as far as locales are concerned.

@SebastianDietrich
Copy link
Author

SebastianDietrich commented Feb 28, 2023

Ok - that works for spring but can't be set (per default) to the browsers locale. We need a simple way to overwrite the UI locale (that is per default the servers-locale) with a specific locale or the browsers locale.

The first thing to realize is that Vaadin doesn't take care of all formatting in the application

That is something I have never cared of. Have never developed an application with formatted output - results were usually displayed in read-only text fields. But of course, this might be the case.

We could ask ourselves the following question:

  • Are users aware and capable of the necessity to enter dates and values according to the display language?
    IMHO the answer is definitively "no". If the application was in English most German speaking users would nevertheless enter 1,00 and then be surprised that this might result in 1,000.00

If so, then the default servers locale leading to "wrong locale, even if consistent to wrongly formatted output" is a much more frequent and painful error than a default browsers locale would lead to "correct input locale, but inconsistent wrongly formatted output".

That is why I would opt in for default browsers locale.

But of course, if we get an easy and documented functionality to set this, that would be an improvement to the current situation, using the (undocumented) VaadinServiceInitListener technique.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

3 participants