Chapter 10. Localization Configuration

10.1. Pluggable Locale Policy

Every request processed by every portlet is invoked within a context of the current Locale.
The current Locale can be retrieved by calling the getLocale() method of javax.portlet.PortletRequest interface.
The exact algorithm for determining the current Locale is not specified by Portlet Specification. Portlet containers implement this the way they deem most appropriate.
In JBoss Portal Platform, each portal instance has a default language which can be used to present content for new users. Another option is to use each user’s browser language preference, provided it matches one of the available localizations that JBoss Portal Platform supports, and only fallback to the portal's default language if no match is found.
Every user, while visiting a portal, has an option to change the language of the user interface by using a Language chooser. The choice can be remembered for the duration of the session, or it can be remembered for a longer period using a browser cookie, or, for registered and logged-in users, it can be saved into the user’s profile.
As there is more than one way to determine the Locale to be used for displaying a portal page, the mechanism for determining the current Locale of the request is pluggable in JBoss Portal Platform, and the exact algorithm can be customized.

10.1.1. LocalePolicy API

Customization is achieved by using LocalePolicy API, which is a simple API consisting of one interface, and one class:
  • org.exoplatform.services.resources.LocalePolicy interface
  • org.exoplatform.services.resources.LocaleContextInfo class
The LocalePolicy interface defines a single method that is invoked on the installed LocalePolicy service implementation:
public interface LocalePolicy
   {
      public Locale determineLocale(LocaleContextInfo localeContext);
   }
The Locale returned by determineLocale() method is the Locale that will be returned to portlets when they call javax.portlet.PortletRequest.getLocale() method.
The returned Locale has to be one of the locales supported by portal, otherwise it will fall back to the portal default Locale.
The supported locales are listed in JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/common/locales-config.xml file as described in Section 9.2, “Locales Configuration” .
The determineLocale() method takes a parameter of type LocaleContextInfo, which represents a compilation of preferred locales from different sources; user’s profile, portal default, browser language settings, current session, browser cookie.
All these different sources of Locale configuration or preference are used as input to LocalePolicy implementation that decides which Locale should be used.

10.1.2. Default LocalePolicy

By default, org.exoplatform.portal.application.localization.DefaultLocalePolicyService, an implementation of LocalePolicy, is installed to provide the default behavior. This, however, can easily be extended and overridden. A completely new implementation can also be written from scratch.
DefaultLocalePolicyService treats logged-in users slightly differently than anonymous users. Logged-in users have a profile that can contain language preference, while anonymous users do not.
Here is an algorithm used for anonymous users.

Procedure 10.1. An algorithm for anonymous users

  1. Iterate over LocaleContextInfo properties in the following order:
    • cookieLocales
    • sessionLocale
    • browserLocales
    • portalLocale
  2. Get each property's value. If it's a collection, get the first value.
  3. If value is one of the supported locales return it as a result.
  4. If the value is not in the supported locales set, try to remove country information and check if a language matching locale is in the list of supported locales. If so, return it as a result.
  5. Otherwise, continue with the next property.
If no supported locale is found the return locale eventually defaults to portalLocale.
The algorithm for logged-in users is virtually the same except that the first Locale source checked is user's profile.

Procedure 10.2. An algorithm for logged-in users

  1. Iterate over LocaleContextInfo properties in the following order:
    • userProfile
    • cookieLocales
    • sessionLocale
    • browserLocales
    • portalLocale

10.1.3. Custom LocalePolicy

The easiest way to customize the LocalePolicy is to extend DefaultLocalePolicyService. A study of the source code is required. JavaDocs provide thorough information on this.
Most customizations will involve simply overriding one or more of its protected methods.
An example of a customization is an already provided NoBrowserLocalePolicyService. By overriding just one method, it skips any use of browser language preference.
public class NoBrowserLocalePolicyService extends DefaultLocalePolicyService
   {
      /**
       * Override super method with no-op.
       *
       * @param context locale context info available to implementations in order to determine appropriate Locale
       * @return null
       */
      @Override
      protected Locale getLocaleConfigFromBrowser(LocaleContextInfo context)
      {
         return null;
      }
   }

10.1.4. LocalePolicy Configuration

The LocalePolicy framework is enabled for portlets by configuring LocalizationLifecycle class in portal's webui configuration file: JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/webui-configuration.xml:
<application-life-cycle-listeners>
   ...
   <listener>org.exoplatform.portal.application.localization.LocalizationLifecycle</listener>
</application-life-cycle-listeners>
The default LocalePolicy implementation is installed as an eXo Kernel portal service via JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/web-configuration.xml.
The following excerpt is responsible for installing the service:
<component>
    <key>org.exoplatform.services.resources.LocalePolicy</key>
    <type>org.exoplatform.portal.application.localization.DefaultLocalePolicyService</type>
</component>
Besides implementing LocalePolicy, the service class also needs to implement org.picocontainer.Startable interface in order to get installed.

10.1.5. Keeping non-bridged resources in sync with current Locale

All the resources in portals that are not portlets themselves, but are accessed through portlets - reading data through PortletRequest, and writing to PortletResponse - are referred to as 'bridged'. Any resources that are accessed directly, bypassing portal filters and servlets, are referred to as non-bridged.
Non-bridged servlets, and .jsps have no access to PortalRequest. They do not use PortletRequest.getLocale() to determine current Locale. Instead, they use ServletRequest.getLocale() which is subject to precise semantics defined by Servlet specification - it reflects browser's language preference.
In other words, non-bridged resources do not have a notion of current Locale in the same sense that portlets do. The result is that when mixing portlets and non-bridged resources there may be a localization mismatch, an inconsistency in the language used by different resources composing your portal page.
This problem is addressed by LocalizationFilter. This is a filter that changes the behavior of ServletRequest.getLocale() method so that it behaves the same way as PortletRequest.getLocale().
That way even localization of servlets, and .jsps accessed in a non-bridged manner can stay in sync with portlet localization.
LocalizationFilter is installed through the portal's web.xml file: JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/web.xml.
<filter>
   <filter-name>LocalizationFilter</filter-name>
   <filter-class>org.exoplatform.portal.application.localization.LocalizationFilter</filter-class>
</filter>

...

<filter-mapping>
    <filter-name>LocalizationFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
There is a minor limitation with this mechanism in that it is unable to determine the current portal,and consequently, its default language. As a result the portalLocale defaults to English, but can be configured to something else by using the filter's PortalLocale init param. For example:
<filter>
   <filter-name>LocalizationFilter</filter-name>
   <filter-class>org.exoplatform.portal.application.localization.LocalizationFilter</filter-class>
   <init-param>
      <param-name>PortalLocale</param-name>
      <param-value>fr_FR</param-value>
   </init-param>
</filter>
By default, LocalizationFilter is applied very broadly to cover all the resources automatically.
JBoss Portal Platform uses some non-bridged .jsps that require LocalizationFilter, so narrowing the mapping to *.jsp is enough for JBoss Portal Platform to function correctly.
Additionally deployed portlets, and portal applications, however, may require broader mapping to cover their non-bridged resources.
Narrowing the mapping might improve performance. This is something to consider, when optimizing for speed.