Reputation: 1400
Im trying to build my first Spring MVC 4 app with i18n support and was thinking how i can use a default/fallback locale in case of the user is manipulating the language uri parameter to a non existing or supported locale For example http://localhost.de?lang=abc
Im using the code
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(Locale.GERMAN);
return sessionLocaleResolver;
}
which works in general if i open the url the very first time but it seems not to work for the case i was describing. I know there is a mechanism which would use the default messages properties file but i would like to set a default/fallback locale for this case. Do i need to implement maybe a custom filter?
Upvotes: 11
Views: 1483
Reputation: 18507
A very late answer, but I thought the easiest way to set a default locale in spring mvc is simply set a i18n file properties with your default language.
For example if you have two languages available in your application (suppose english and deutsch), you've this files:
messages_de.properties
messages_en.properties
Then you can simply copy the messages_de.properties to messages.properties, then you've:
messages_de.properties
messages_en.properties
messages.properties
Spring mvc will fallback automatically to messages.properties
file, when the lang
parameter does not match with any of the i18n files availables in your application.
Upvotes: 0
Reputation: 253
My suggestion would be to subclass the SessionLocaleResolver and override the getLocale method:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
private static Set<Locale> allowedLocales;
static {
HashSet<Locale> allowed = new HashSet<>();
allowed.add(Locale.GERMAN);
allowed.add(Locale.CANADA);
allowedLocales = Collections.unmodifiableSet(allowed);
}
@Bean
LocaleResolver localeResolver() {
return new LimitedSessionLocaleResolver();
}
class LimitedSessionLocaleResolver extends SessionLocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
Locale locale = super.resolveLocale(request);
if (!allowedLocales.contains(locale)) {
return determineDefaultLocale(request);
}
return locale;
}
}
}
This does not modify the Spring classes in any major way and is probably going to work without issues for the foreseeable future.
Upvotes: 8
Reputation: 1400
Probably far from being perfect but this is what i built...
I also need to say that i changed the default language select mechanism a bit because of SEO needs and i decided to change the language not by using a get parameter but using instead the first part of my uri path for the selected language. For example: http://myurl.com/en/test.html instead of http://myurl.com/test.html?lang=de
In my annotation based configuration:
@Bean
public LocaleResolver localeResolver() {
UriLocaleResolver uriLocaleResolver = new UriLocaleResolver();
return uriLocaleResolver;
}
The locale resolver
public class UriLocaleResolver implements LocaleResolver {
private final Logger logger = LoggerFactory.getLogger(getClass());
private Locale locale = null;
@Autowired
private LocalizationService localizationService;
@Override
public Locale resolveLocale(final HttpServletRequest servletRequest) {
if (locale != null) {
return locale;
}
String languageIsoCode = null;
try {
languageIsoCode = ((String)servletRequest.getAttribute(RequestKey.LANGUAGE_ISO_CODE)).toLowerCase();
}
catch (Exception e) { }
if (StringUtils.isBlank(languageIsoCode) || !localizationService.getSupportedLocaleLanguageIsoCodes().contains(languageIsoCode)) {
logger.trace("Couldn't find valid language iso code. Using default locale '{}'", GlobalConstant.DEFAULT_LOCALE);
return GlobalConstant.DEFAULT_LOCALE;
}
logger.trace("Found language iso code '{}'", languageIsoCode);
return new Locale(languageIsoCode);
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
this.locale = locale;
}
}
The filter which checks for a valid language code in the uri...
@Component
public class UriLocalizationFilter extends OncePerRequestFilter {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private LocalizationService localizationService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String uri = request.getRequestURI().substring(request.getContextPath().length());
String[] pathParts = uri.split("/");
if (!uri.startsWith(GlobalConstant.FRONTEND_RESOURCE_PATH_PREFIX) && pathParts.length >= 1 && pathParts[1].length() == 2) {
String originalLanguageIsoCode = pathParts[1];
String lowerCaseLanguageIsoCode = originalLanguageIsoCode.toLowerCase();
if (localizationService.getSupportedLocaleLanguageIsoCodes().contains(lowerCaseLanguageIsoCode)) {
logger.debug("Found valid language iso code {}", lowerCaseLanguageIsoCode);
}
else {
logger.debug("Found invalid language iso code {}. Using default language iso code {}.", lowerCaseLanguageIsoCode, GlobalConstant.DEFAULT_LOCALE.getLanguage());
lowerCaseLanguageIsoCode = GlobalConstant.DEFAULT_LOCALE.getLanguage();
}
String newUrl = StringUtils.removeStart(uri, '/' + originalLanguageIsoCode);
request.setAttribute(RequestKey.LANGUAGE_ISO_CODE, lowerCaseLanguageIsoCode);
logger.debug("Dispatching to new url '{}'", newUrl);
request.getRequestDispatcher(newUrl).forward(request, response);
}
else {
filterChain.doFilter(request, response);
}
}
public void setLocalizationService(LocalizationService localizationService) {
this.localizationService = localizationService;
}
}
}
Frontend path is "resources" in my case where all static files like js, css, fonts etc are laying. localizationService.getSupportedLocaleLanguageIsoCodes() is a Set containing currently three language codes (en, ru, de). So in case of a wrong language code like abc im doing a forward with my default language "de". For me it was/is acceptable solution cause having a wrong language code in the uri means that the uri was manipulated by the user...
Like i said its maybe not "the" solution; for example im not sure how and if it works with cookies and/or "remember me" authentications (using spring security)...just had no time to test it yet...
Upvotes: 5