Fix localization vaadin system messages (#807)

* Add customized SystemMessagesProvider
* Localize according to SystemMessagesInfo
* Localize vaadin 'Server connection lost' message
* Use available locale for system messages
* Add license header
* Fix PR findings
* Fix Sonar issues

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
Stefan Klotz
2019-03-14 12:43:47 +01:00
committed by Stefan Behl
parent c3843416b9
commit 75f66c9811
9 changed files with 168 additions and 13 deletions

View File

@@ -14,6 +14,7 @@ import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton; import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
import org.eclipse.hawkbit.ui.menu.DashboardMenu; import org.eclipse.hawkbit.ui.menu.DashboardMenu;
import org.eclipse.hawkbit.ui.push.EventPushStrategy; import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.vaadin.spring.events.EventBus.UIEventBus; import org.vaadin.spring.events.EventBus.UIEventBus;
@@ -44,9 +45,10 @@ public class MyUI extends AbstractHawkbitUI {
@Autowired @Autowired
MyUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus, final SpringViewProvider viewProvider, MyUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus, final SpringViewProvider viewProvider,
final ApplicationContext context, final DashboardMenu dashboardMenu, final ErrorView errorview, final ApplicationContext context, final DashboardMenu dashboardMenu, final ErrorView errorview,
final NotificationUnreadButton notificationUnreadButton, final UiProperties uiProperties) { final NotificationUnreadButton notificationUnreadButton, final UiProperties uiProperties,
final VaadinMessageSource i18n) {
super(pushStrategy, eventBus, viewProvider, context, dashboardMenu, errorview, notificationUnreadButton, super(pushStrategy, eventBus, viewProvider, context, dashboardMenu, errorview, notificationUnreadButton,
uiProperties); uiProperties, i18n);
} }
} }

View File

@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.themes.HawkbitTheme; import org.eclipse.hawkbit.ui.themes.HawkbitTheme;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@@ -76,10 +77,12 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
private final UiProperties uiProperties; private final UiProperties uiProperties;
private final VaadinMessageSource i18n;
protected AbstractHawkbitUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus, protected AbstractHawkbitUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus,
final SpringViewProvider viewProvider, final ApplicationContext context, final DashboardMenu dashboardMenu, final SpringViewProvider viewProvider, final ApplicationContext context, final DashboardMenu dashboardMenu,
final ErrorView errorview, final NotificationUnreadButton notificationUnreadButton, final ErrorView errorview, final NotificationUnreadButton notificationUnreadButton,
final UiProperties uiProperties) { final UiProperties uiProperties, final VaadinMessageSource i18n) {
this.pushStrategy = pushStrategy; this.pushStrategy = pushStrategy;
this.eventBus = eventBus; this.eventBus = eventBus;
this.viewProvider = viewProvider; this.viewProvider = viewProvider;
@@ -88,6 +91,7 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
this.errorview = errorview; this.errorview = errorview;
this.notificationUnreadButton = notificationUnreadButton; this.notificationUnreadButton = notificationUnreadButton;
this.uiProperties = uiProperties; this.uiProperties = uiProperties;
this.i18n = i18n;
} }
@Override @Override
@@ -115,7 +119,7 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
final HorizontalLayout rootLayout = new HorizontalLayout(); final HorizontalLayout rootLayout = new HorizontalLayout();
rootLayout.setSizeFull(); rootLayout.setSizeFull();
setLocale(HawkbitCommonUtil.getLocaleToBeUsed(uiProperties.getLocalization(), getUI())); HawkbitCommonUtil.initLocalization(this, uiProperties.getLocalization(), i18n);
dashboardMenu.init(); dashboardMenu.init();
dashboardMenu.setResponsive(true); dashboardMenu.setResponsive(true);

View File

@@ -8,16 +8,21 @@
*/ */
package org.eclipse.hawkbit.ui; package org.eclipse.hawkbit.ui;
import javax.servlet.ServletException;
import org.atmosphere.container.JSR356AsyncSupport; import org.atmosphere.container.JSR356AsyncSupport;
import org.atmosphere.cpr.ApplicationConfig; import org.atmosphere.cpr.ApplicationConfig;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import com.vaadin.server.VaadinServlet;
import com.vaadin.spring.boot.internal.VaadinServletConfiguration; import com.vaadin.spring.boot.internal.VaadinServletConfiguration;
import com.vaadin.spring.boot.internal.VaadinServletConfigurationProperties; import com.vaadin.spring.boot.internal.VaadinServletConfigurationProperties;
import com.vaadin.spring.server.SpringVaadinServlet;
/** /**
* {@link VaadinServletConfiguration} that sets the context path for * {@link VaadinServletConfiguration} that sets the context path for
@@ -29,6 +34,23 @@ import com.vaadin.spring.boot.internal.VaadinServletConfigurationProperties;
@Import(VaadinServletConfiguration.class) @Import(VaadinServletConfiguration.class)
public class AsyncVaadinServletConfiguration extends VaadinServletConfiguration { public class AsyncVaadinServletConfiguration extends VaadinServletConfiguration {
@Bean
public LocalizedSystemMessagesProvider localizedSystemMessagesProvider(final UiProperties uiProperties,
final VaadinMessageSource i18n) {
return new LocalizedSystemMessagesProvider(uiProperties, i18n);
}
@Bean
public VaadinServlet vaadinServlet(final LocalizedSystemMessagesProvider localizedSystemMessagesProvider) {
return new SpringVaadinServlet() {
@Override
public void servletInitialized() throws ServletException {
super.servletInitialized();
getService().setSystemMessagesProvider(localizedSystemMessagesProvider);
}
};
}
@Override @Override
@Bean @Bean
protected ServletRegistrationBean vaadinServletRegistration() { protected ServletRegistrationBean vaadinServletRegistration() {

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui;
import java.util.Locale;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.server.CustomizedSystemMessages;
import com.vaadin.server.SystemMessages;
import com.vaadin.server.SystemMessagesInfo;
import com.vaadin.server.SystemMessagesProvider;
/**
* {@link SystemMessagesProvider} that localizes Vaadin system messages.
*
*/
public class LocalizedSystemMessagesProvider implements SystemMessagesProvider {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private final UiProperties uiProperties;
/**
* @param uiProperties
* Properties to determine the available Locales
* @param i18n
* Message source used for localization
*/
public LocalizedSystemMessagesProvider(final UiProperties uiProperties, final VaadinMessageSource i18n) {
this.i18n = i18n;
this.uiProperties = uiProperties;
}
private SystemMessages getLocalizedSystemMessages(final VaadinMessageSource i18n, final Locale local) {
final CustomizedSystemMessages messages = new CustomizedSystemMessages();
final Locale desiredLocale = HawkbitCommonUtil.getLocaleToBeUsed(uiProperties.getLocalization(), local);
messages.setSessionExpiredCaption(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_SESSIONEXPIRED_CAPTION));
messages.setSessionExpiredMessage(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_SESSIONEXPIRED_MESSAGE));
messages.setCommunicationErrorCaption(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_COMMUNICATIONERROR_CAPTION));
messages.setCommunicationErrorMessage(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_COMMUNICATIONERROR_MESSAGE));
messages.setInternalErrorCaption(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_INTERNALERROR_CAPTION));
messages.setInternalErrorMessage(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_INTERNALERROR_MESSAGE));
return messages;
}
@Override
public SystemMessages getSystemMessages(final SystemMessagesInfo systemMessagesInfo) {
return getLocalizedSystemMessages(i18n, systemMessagesInfo.getLocale());
}
}

View File

@@ -120,7 +120,7 @@ public abstract class AbstractHawkbitLoginUI extends UI {
@Override @Override
protected void init(final VaadinRequest request) { protected void init(final VaadinRequest request) {
setLocale(HawkbitCommonUtil.getLocaleToBeUsed(uiProperties.getLocalization(), getUI())); HawkbitCommonUtil.initLocalization(this, uiProperties.getLocalization(), i18n);
SpringContextHelper.setContext(context); SpringContextHelper.setContext(context);
params = UriComponentsBuilder.fromUri(Page.getCurrent().getLocation()).build().getQueryParams(); params = UriComponentsBuilder.fromUri(Page.getCurrent().getLocation()).build().getQueryParams();

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.UiProperties; import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.UiProperties.Localization;
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon; import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery; import org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery;
@@ -563,24 +564,41 @@ public final class HawkbitCommonUtil {
/** /**
* Determine the language that should be used considering localization * Determine the language that should be used considering localization
* properties and UI settings * properties and a desired Locale
* *
* @param localizationProperties * @param localizationProperties
* UI Localization settings * UI Localization settings
* @param ui * @param desiredLocale
* UI which settings are considered * desired Locale
* @return Locale to be used according to UI and properties * @return Locale to be used according to UI and properties
*/ */
public static Locale getLocaleToBeUsed(final UiProperties.Localization localizationProperties, final UI ui) { public static Locale getLocaleToBeUsed(final UiProperties.Localization localizationProperties,
final Locale desiredLocale) {
final List<String> availableLocals = localizationProperties.getAvailableLocals(); final List<String> availableLocals = localizationProperties.getAvailableLocals();
final Locale uiLocale = ui.getSession().getLocale();
// ckeck if language code of UI locale matches an available local. // ckeck if language code of UI locale matches an available local.
// Country, region and variant are ignored. "availableLocals" must only // Country, region and variant are ignored. "availableLocals" must only
// contain language codes without country or other extensions. // contain language codes without country or other extensions.
if (availableLocals.contains(uiLocale.getLanguage())) { if (availableLocals.contains(desiredLocale.getLanguage())) {
return uiLocale; return desiredLocale;
} }
return new Locale(localizationProperties.getDefaultLocal()); return new Locale(localizationProperties.getDefaultLocal());
} }
/**
* Set localization considering properties and UI settings.
*
* @param ui
* UI to setup
* @param localizationProperties
* UI localization settings
* @param i18n
* Localization message source
*/
public static void initLocalization(final UI ui, final Localization localizationProperties,
final VaadinMessageSource i18n) {
ui.setLocale(HawkbitCommonUtil.getLocaleToBeUsed(localizationProperties, ui.getSession().getLocale()));
ui.getReconnectDialogConfiguration()
.setDialogText(i18n.getMessage(UIMessageIdProvider.VAADIN_SYSTEM_TRYINGRECONNECT));
}
} }

View File

@@ -183,6 +183,20 @@ public final class UIMessageIdProvider {
public static final String MESSAGE_TARGET_BULKUPLOAD_RESULT_FAIL = "message.bulk.upload.result.fail"; public static final String MESSAGE_TARGET_BULKUPLOAD_RESULT_FAIL = "message.bulk.upload.result.fail";
public static final String VAADIN_SYSTEM_SESSIONEXPIRED_CAPTION = "vaadin.system.sessionexpired.caption";
public static final String VAADIN_SYSTEM_SESSIONEXPIRED_MESSAGE = "vaadin.system.sessionexpired.message";
public static final String VAADIN_SYSTEM_COMMUNICATIONERROR_CAPTION = "vaadin.system.communicationerror.caption";
public static final String VAADIN_SYSTEM_COMMUNICATIONERROR_MESSAGE = "vaadin.system.communicationerror.message";
public static final String VAADIN_SYSTEM_INTERNALERROR_CAPTION = "vaadin.system.internalerror.caption";
public static final String VAADIN_SYSTEM_INTERNALERROR_MESSAGE = "vaadin.system.internalerror.message";
public static final String VAADIN_SYSTEM_TRYINGRECONNECT = "vaadin.system.tryingreconnect";
public static final String TOOLTIP_ROLLOUT_STATUS_PREFIX = "tooltip.rollout.status."; public static final String TOOLTIP_ROLLOUT_STATUS_PREFIX = "tooltip.rollout.status.";
/** /**

View File

@@ -55,8 +55,26 @@ public class VaadinMessageSource implements Serializable {
* @see HawkbitCommonUtil#getCurrentLocale() * @see HawkbitCommonUtil#getCurrentLocale()
*/ */
public String getMessage(final String code, final Object... args) { public String getMessage(final String code, final Object... args) {
return getMessage(HawkbitCommonUtil.getCurrentLocale(), code, args);
}
/**
* Tries to resolve the message based on the provided Local. Returns message
* code if fitting message could not be found.
*
* @param local
* to determinate the Language.
* @param code
* the code to lookup up.
* @param args
* Array of arguments that will be filled in for params within
* the message.
*
* @return the resolved message, or the message code if the lookup fails.
*/
public String getMessage(final Locale local, final String code, final Object... args) {
try { try {
return source.getMessage(code, args, HawkbitCommonUtil.getCurrentLocale()); return source.getMessage(code, args, local);
} catch (final NoSuchMessageException ex) { } catch (final NoSuchMessageException ex) {
LOG.error("Failed to retrieve message!", ex); LOG.error("Failed to retrieve message!", ex);
return code; return code;

View File

@@ -707,3 +707,12 @@ character.whitespace = whitespace
character.digits = digits character.digits = digits
character.quotationMarks = quotation marks character.quotationMarks = quotation marks
character.slashes = slashes character.slashes = slashes
# Vaadin system messages
vaadin.system.sessionexpired.caption=Session Expired
vaadin.system.sessionexpired.message=Take note of any unsaved data, and click here or press ESC key to continue.
vaadin.system.communicationerror.caption=Communication problem
vaadin.system.communicationerror.message=Take note of any unsaved data, and click here or press ESC to continue.
vaadin.system.internalerror.caption=Internal error
vaadin.system.internalerror.message=Please notify the administrator. Take note of any unsaved data, and click here or press ESC to continue.
vaadin.system.tryingreconnect=Server connection lost, trying to reconnect...