Spring 3 MVC: Internationalization & localization of Podcastpedia.org

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏
Podcastpedia.org can be accessed today in four languages – English, German, French and Romanian, with Spanish planned for the near future. In computing this is called internationalization (i18n). The post presents how this is configured under the hood with the help of Spring 3 MVC.
Application Context Configuration
Message Resource Files
Normally in the Java world, the locale-specific data is stored in message resource files. In Spring you configure it by adding the following bean org.springframework.context.support.ReloadableResourceBundleMessageSource
to the application context:
<!-- Application Message Bundle -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages/messages" />
<property name="defaultEncoding" value="UTF-8"/>
</bean>
Spring’s DispatcherServlet
enables you to automatically resolve messages using the client’s locale. This is done with LocaleResolver
objects. You can select between
-
an
AcceptHeaderLocaleResolver
, which inspects theaccept-language
header in the request that was sent by the client (e.g., a web browser). Usually this header field contains the locale of the client’s operating system. -
a
CookieLocaleResolver
, -
and a
SessionLocaleResolver
, which allows you to retrieve locales from the session that might be associated with the user’s reques
CookieLocaleResolver
The CookieLocaleResolver
made the most sense for Podcastpedia.org . It inspects a cookie named podcastpediaPreferredLanguage
, that might exist on the client to see if a locale is specified:
<bean id="localeResolver">
<property name="cookieName" value="podcastpediaPreferredLanguage"/>
<property name="defaultLocale" value="en_US" />
<property name="cookieMaxAge" value="604800"/>
</bean>
If the cookie is not found, then the defaultLocale
is set to American English. The cookieMaxAge
(the maximum time a cookie will stay persistent on the client) is set to 604800 seconds (one month).
LocaleChangeInterceptor
The LocaleResolver
is normally used in combination with the LocaleChangeInterceptor
, which allows you to change of the current locale by using a defined parameter in the request (in this case the lang
parameter). So, for example, a request for the following URL, <a title="Podcastpedia - categories" href="https://github.com/CodepediaOrg/podcastpedia/categories?lang=de" target="_blank">https://github.com/CodepediaOrg/podcastpedia/categories?<strong>lang=de</strong></a>
, will change the site language to German:
<mvc:interceptors>
<!-- Changes the locale when a 'lang' request parameter is sent; e.g. /?lang=de -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"/>
</bean>
</mvc:interceptors>
Relevant code in Podcastpedia.org
JSP
On Podcastpedia.org you can change the language by selecting the corresponding flag :
Behind the scenes, the jsp file, which common to all pages, looks something like the following:
<div id="flags">
<a href="?lang=en">
<img alt="en" title="English" src="<c:url value="/static/images/flags/en.png"/>">
</a>
<a href="?lang=de">
<img alt="de" title="German" src="<c:url value="/static/images/flags/de.png"/>">
</a>
<a href="?lang=fr">
<img alt="fr" title="French" src="<c:url value="/static/images/flags/fr.png"/>">
</a>
<!-- TODO uncomment when the translation in Spanish is available
<a href="?lang=es">
<c:url value="/static/images/flags/es.png" var="url_flag_image" />
<img alt="es" title="Spanish" src="${url_flag_image}">
</a>
-->
<a href="?lang=ro">
<img alt="ro" title="Romanian" src="<c:url value="/static/images/flags/ro.png"/>">
</a>
</div>
Basically by clicking on the flag the page is reloaded with the corresponding lang
parameter, as presented above.
Access the Locale in Spring
If you need to access the current locale in Spring you can use the org.springframework.context.i18n.LocaleContextHolder.LocaleContextHolder.getLocale()
, which returns the Locale associated with the current thread, if any, or the system default Locale else. In the following code snippet you can see how I use this in the start page’s controller to display the newest and most popular podcasts based on the language selected:
@ModelAttribute
public void addDataToModel(ModelMap model){
...............
Locale locale = LocaleContextHolder.getLocale();
String language = locale.getLanguage();
List<String> preferredLanguagesList = Arrays.asList(preferredLanguages);
if(preferredLanguagesList.contains(language)){
model.put("newestPodcasts", startPageService.getNewestPodcasts(LanguageCode.get(language)));
model.put("topRatedPodcasts", startPageService.getTopRatedPodcastsWithLanguage(LanguageCode.get(language), NUMBER_OF_PODCASTS_IN_CHART));
} else {
model.put("newestPodcasts", startPageService.getNewestPodcasts());
model.put("topRatedPodcasts", startPageService.getTopRatedPodcasts(NUMBER_OF_PODCASTS_IN_CHART));
}
}
Watch out for…
Browser Caching optimization
If you have enabled browser caching, as specified for example in the post How To: Enable compression and leverage browser caching with Apache Server, make sure you set the expiring
and cache control
for the html pages to 0 seconds:
ExpiresByType text/html "access plus 0 seconds"
....
Header set Cache-Control "max-age=0, private"
, so that changing the locale is effective immediately for the page – otherwise if you come back later to the same page, but without the locale parameter in the url, you would have the page displayed in the old locale, if the expiration time was not reached yet.
Well, that’s All Folks! If you would like to have Podcastpedia.org localized in your language, you can download the message resource file for English – messages_en.properties, and contact me at ama [AT] codepedia dot org – thanks
If you liked this, please show your support by helping us with Podcastpedia.org
We promise to only share high quality podcasts and episodes.