为啥 spring-vaadin 忘记了我设置的 locale,但在页面刷新后突然记住了?

Posted

技术标签:

【中文标题】为啥 spring-vaadin 忘记了我设置的 locale,但在页面刷新后突然记住了?【英文标题】:Why does spring-vaadin forgets my set locale, but suddenly remembers it after a page refresh?为什么 spring-vaadin 忘记了我设置的 locale,但在页面刷新后突然记住了? 【发布时间】:2018-07-16 23:44:21 【问题描述】:

情况:我有一个 vaadin-spring 应用程序,我必须让用户在登录时更改语言。我在登录页面使用组合框在语言环境之间切换。春季语言环境解析器实现是 CookieLocaleResolver 因为我想将选择的选项存储在 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;

查看:

@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());
    );
    // ...

更改组合框会将名为 locale 的 cookie 设置为所需的语言区域设置(例如 de_DE)。语言环境解析器中的默认语言是 de_DE。在登录时,我可以在两个选项之间进行切换:de_DE 和 en_US。

vaadin 视图中的标题和文本翻译由 spring messageSource 完成:

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

在 Vaadin UI 中,我调用以下命令在会话和 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);

        // ...
    


我的问题是:当我在登录页面的语言组合框中选择 de_DE 语言环境并登录时,LocaleContextHolder.getLocale() 返回 en_US 并且 UI 为英文。但是,如果我在浏览器上按 F5 并刷新页面,则 UI 变为 de_DE。

为什么?

注意:我注意到登录前和登录后 JESSSONID cookie 发生了变化。我不知道在区域设置 cookie 存在时解析区域设置是否重要,并且在登录之前和之后是相同的。

【问题讨论】:

你看过PortletListener接口吗? 【参考方案1】:

问题在于过滤器链中有一个 RequestContextFilter,它会在每个请求中用默认值覆盖由 localeResolver 解析的语言环境。

快速的解决方案是在消息服务中手动解析语言环境:

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

并使用此语言环境进行翻译。

【讨论】:

【参考方案2】:

您的问题是 - 一旦创建了 Vaadin UI - 您不会更改 UI 对象的区域设置。您只需在 LocaleResolver 上更改它,它是一个 Spring 组件。在浏览器中按 F5 刷新页面会创建一个新的 UI,因此会应用新语言。

我不是 100% 确定,但我认为当您的语言选择发生变化时,额外调用 yourUi.setLocale(currentLocale) 并没有帮助。这是因为像 Label 这样的 Vaadin 组件已经创建并设置了翻译文本。因此,如果您真的想就地更改语言而不重新创建整个 UI,则必须更新所有 Vaadin 组件以显示新语言的文本。不过,我猜这是一个很大的努力。

我的解决方案是通知用户并重新创建会话:

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

无论如何,当用户第一次访问您的网站时(没有 cookie),浏览器会发送用户的首选语言,该语言被 Vaadin 选择为默认语言。这对大多数用户来说已经足够了。

【讨论】:

我尝试刷新页面,将页面位置设置为 "" 并关闭 Vaadin 会话,但最初 UI 仍以错误的语言显示。 我还设置了 UI 区域设置。在 Vaadin 会话 setLocale 调用之前,我有一个 setLocale(currentLocale); 调用。看起来我的问题是LocaleContextHolder.getLocale()。它返回 en_US,但如果我刷新页面,它会正确返回 de_DE。登录页面以正确的语言显示(在我在 cookie 中设置的语言)。 你能试试msgSource.getMessage("someComponent.caption", args, UI.getCurrent().getLocale())吗?有什么改变吗? 有一个过滤器覆盖了每个请求中的语言环境。在我的回答中解释了。感谢您的帮助!

以上是关于为啥 spring-vaadin 忘记了我设置的 locale,但在页面刷新后突然记住了?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的设置切断了我对边距的限制?

VS 2010 忘记了我自定义的字体和颜色

为啥我没设置任何锁屏,PIN码,安卓就显示手机已加密了

为啥输入TP-LINK初始的密码总是错误

为啥 Android Studio 将我所有的引用从 R 更改为 android.R?

为啥 Android Studio 将我所有的引用从 R 更改为 android.R?