package org.vaadin.viritin.util;
import com.vaadin.server.*;
import com.vaadin.ui.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
/**
* This class handles the locale for a vaadin application. It negotiates the
* locale based on
* <ol>
* <li>a selected locale via {@link #setLocale(Locale)}</li>
* <li>the best fitting one by the Accept-Lanuage Header</li>
* <li>the first one from the supported ones</li>
* </ol>
* After a locale has been selected a call of
* {@link com.vaadin.ui.AbstractComponent#setLocale(Locale)} on all components
* in the current {@link com.vaadin.ui.UI} is triggered. You can update your
* strings there.
*
* @author Daniel Nordhoff-Vergien
*
*/
public class VaadinLocale {
public interface LocaleNegotiationStrategey {
/**
* Returns the best fitting supported locale depending on the http
* language accept header.
*
* @param supportedLocales the list of supported locales
* @param vaadinRequest the current VaadinRequest
* @return the best fitting supported locale
*/
public Locale negotiate(List<Locale> supportedLocales,
VaadinRequest vaadinRequest);
}
private static final String LOCALE_SESSION_ATTRIBUTE = "org.vaadin.viritin.selectedLocale";
private final List<Locale> supportedLocales = new ArrayList<>();
private Locale bestLocaleByAcceptHeader;
private final LocaleNegotiationStrategey localeNegotiationStrategey;
public VaadinLocale(LocaleNegotiationStrategey localeNegotiationStrategey,
Locale... supportedLocales) {
if (supportedLocales == null || supportedLocales.length == 0) {
throw new IllegalArgumentException(
"At least one locale must be supported");
}
if (localeNegotiationStrategey == null) {
throw new IllegalArgumentException(
"localeNegotiatinStrategy may not be null!");
}
this.localeNegotiationStrategey = localeNegotiationStrategey;
this.supportedLocales.addAll(Arrays.asList(supportedLocales));
}
/**
* Instantiates a new VaadinLocale object
*
* @param localeNegotiationStrategey the localeNegotiationStrategey the
* should be used to detect the most suitable locale
* @param vaadinRequest the current vaadinRequest, for detection
* @param supportedLocales At least one Locale which the application
* supports. The first locale is the default locale, if negotiation fails.
*
*
* @throws IllegalArgumentException if there is no locale.
*/
public VaadinLocale(LocaleNegotiationStrategey localeNegotiationStrategey,
VaadinRequest vaadinRequest, Locale... supportedLocales) {
this(localeNegotiationStrategey, supportedLocales);
setVaadinRequest(vaadinRequest);
updateVaadinLocale();
}
/**
* Creates a new instance with the {@link Java7LocaleNegotiationStrategy}.
*
* @param supportedLocales the list of supported locales
*/
public VaadinLocale(Locale... supportedLocales) {
this(new Java7LocaleNegotiationStrategy(), supportedLocales);
}
public void setVaadinRequest(VaadinRequest vaadinRequest) {
if (vaadinRequest == null) {
throw new IllegalArgumentException("VaadinRequest is needed!");
}
bestLocaleByAcceptHeader = localeNegotiationStrategey.negotiate(
supportedLocales, vaadinRequest);
updateVaadinLocale();
}
public void setLocale(Locale locale) {
if (locale != null && !supportedLocales.contains(locale)) {
throw new IllegalArgumentException("Locale " + locale
+ " is not supported.");
}
if (locale == null) {
VaadinSession.getCurrent().setAttribute(LOCALE_SESSION_ATTRIBUTE,
null);
} else {
VaadinSession.getCurrent().setAttribute(LOCALE_SESSION_ATTRIBUTE,
locale.toLanguageTag());
}
updateVaadinLocale();
}
public void unsetLocale() {
setLocale(null);
}
private void updateVaadinLocale() {
Locale locale = getLocale();
UI.getCurrent().setLocale(locale);
VaadinSession.getCurrent().setLocale(locale);
recursiveSetLocale();
}
private void recursiveSetLocale() {
Stack<Component> stack = new Stack<>();
stack.addAll(VaadinSession.getCurrent().getUIs());
while (!stack.isEmpty()) {
Component component = stack.pop();
if (component instanceof HasComponents) {
for (Iterator<Component> i = ((HasComponents) component)
.iterator(); i.hasNext();) {
stack.add(i.next());
}
}
if (component instanceof AbstractComponent) {
AbstractComponent abstractComponent = (AbstractComponent) component;
abstractComponent.setLocale(UI.getCurrent().getLocale());
}
}
}
public Locale getLocale() {
String locale = (String) VaadinSession.getCurrent().getAttribute(
LOCALE_SESSION_ATTRIBUTE);
if (locale != null) {
return Locale.forLanguageTag(locale);
} else if (bestLocaleByAcceptHeader != null) {
return bestLocaleByAcceptHeader;
} else {
return supportedLocales.get(0);
}
}
public Locale getBestLocaleByAcceptHeader() {
return bestLocaleByAcceptHeader;
}
public List<Locale> getSupportedLocales() {
return new ArrayList<>(supportedLocales);
}
}