Why does spring-vaadin forgets my set locale, but suddenly remembers it after a page refresh?

595 Views Asked by At

Situation: I have a vaadin-spring application in which I have to let the user change the language at login. I use a combo box at the login page to switch between locales. The spring locale resolver implementation is CookieLocaleResolver because I'd like to store the selected option for the next visit in a cookie.

@Bean
public LocaleResolver localeResolver() {
    CookieLocaleResolver localeResolver = new CookieLocaleResolver();
    localeResolver.setDefaultLocale(new Locale("de", "DE"));
    localeResolver.setCookieName("locale");
    localeResolver.setCookieMaxAge( 60 * 60 * 24 * 31);
    return localeResolver;
}

View:

@SpringView(name = "login")
public class LoginView implements View {
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private LocaleResolver localeResolver;

    ComboBox<LanguageOption> languageField;
    // ...
    languageField.addValueChangeListener(option -> {
        localeResolver.setLocale(request, response, option.getValue().getLocale());
    });
    // ...
}

Changing the combobox sets a cookie called locale to the desired language locale (for example de_DE). The default language in the locale resolver is de_DE. At the login, I can change between two options: de_DE and en_US.

The caption and text translation in the vaadin views is done by spring messageSource:

someCompoenent.setCaption(messageSource.getMessage("someComponent.caption", args, LocaleContextHolder.getLocale()));

In the Vaadin UI, I call the following to set the locale on the session and on the UI:

public class MyUI extends UI implements ViewDisplay, ViewAccessControl {
    @Autowired
    private HttpServletRequest httpServletRequest;

    // ...
    @Override
    protected void init(VaadinRequest request) {
        // ...
        Locale currentLocale = localeResolver.resolveLocale(httpServletRequest);
        LocaleContextHolder.setLocale(currentLocale);

        setLocale(currentLocale);
        VaadinSession.getCurrent().setLocale(currentLocale);

        // ...
    }

}

My problem is: when I choose the de_DE locale in the language combobox on the login page and I login, the LocaleContextHolder.getLocale() returns en_US and the UI is in english. However, if I hit F5 on the browser and refresh the page, the UI becomes de_DE.

Why?

A note: I noticed that before login and after login the JSESSONID cookie changes. I don't know if it matters in resolving the locale while the locale cookie is present and it's the same before and after login.

2

There are 2 best solutions below

0
kruzexx On BEST ANSWER

The problem was that there is a RequestContextFilter in the filter chain which overwrites the locale resolved by the localeResolver with a default value in every request.

The quick solution is to resolve the locale manually in the message service:

Locale locale = localeResolver.resolveLocale(SpringVaadinServletRequest.getCurrent());

And use this locale for translation.

4
Steffen Harbich On

Your problem is that - once the Vaadin UI is created - you do not change the locale on the UI object. You only change it on the LocaleResolver which is a Spring component. Hitting F5 for refresh page in browser creates a new UI and therefore applies the new language.

I am not 100% sure but I think it doesn't help to invoke additionally yourUi.setLocale(currentLocale) when your language selection changes. This is because Vaadin components like Label are already created and set with translated text. So, if you really want to change the language in-place without recreating the whole UI, you must update all Vaadin components to show texts in new language. However, this is a lot of effort I guess.

My solution was to inform user and recreate the session:

Page.getCurrent().setLocation("");
VaadinSession.getCurrent().close();

Anyway, when the user visits your site the first time (without cookie), the browser sends the preferred language of the user which is picked up by Vaadin as default language. This will be sufficient for most of the users.