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>
|
The configuration specifies that the message resource files should be named
messages_xx.properties (xx is the shortcut of the locale), are stored in the
messages folder in the classpath, and that the default encoding for the files is
UTF-8.

Message resource files in classpath
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 the accept-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,
http://www.podcastpedia.org/categories?lang=de
, 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<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 theorg.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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@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
|
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] codingpedia DOT org – thanks
If you liked this, please show your support by
helping us with
Podcastpedia.orgWe promise to only share high quality podcasts and episodes.
Post a Comment
Click to see the code!
To insert emoticon you must added at least one space before the code.