Internationalization Support
Internationalization support in Sling consists of four methods in the SlingHttpServletRequest interface:
- getLocale() – Returns the primary Locale for the current request. This method is inherited from the javax.servlet.ServletRequest interface.
- getLocales() – Returns the Locale instances for the current request. This method is inherited from the javax.servlet.ServletRequest interface.
- getResourceBundle(Locale) – Returns a ResourceBundle for the given Locale. This method is specific to Sling.
- getResourceBundle(String, Locale) – Returns a ResourceBundle of a given base name for the given Locale. This method is specific to Sling.
These methods have a default implementation in the org.apache.sling.core bundle and an extended and extensible implementation in the org.apache.sling.i18n bundle.
Default Implementation in the org.apache.sling.core Bundle
The default implementation of the above mentioned four methods in the sling.core bundle is contained in the bundle-private class org.apache.sling.impl.SlingHttpServletRequestImpl which is the primary implementation of the SlingHttpServletRequest interface:
- getLocale() – Returns the Locale from the request object of the servlet container in which Sling is running. As per the Servlet API specification, this is either the primary Locale of the Accept-Language request header or the server default locale.
- getLocales() – Returns the Enumeration from the request object of the servlet container in which Sling is running. As per the Servlet API specification, this is either based on the Accept-Language request header or just the server default locale.
- getResourceBundle(Locale) – Returns a ResourceBundle whose getString(String key) method returns the key as the message and whose getKeys() method returns an empty Enumeration.
- getResourceBundle(String, Locale) – Returns a ResourceBundle whose getString(String key) method returns the key as the message and whose getKeys() method returns an empty Enumeration.
NOTE: Unlike the default implementations of the ResourceBundle abstract class in the Java Runtime – PropertyResourceBundle and ListResourceBundle – the ResourceBundle returned by the default implementation of the getResourceBundle(Locale) and getResourceBundle(String, Locale) always returns a string message for any key, which is the key itself. This prevents throwing MissingResourceException.
Extensible Implementation in the org.apache.sling.i18n Bundle
The org.apache.sling.i18n Bundle implements a request level Filter providing extensible implementations of the above mentioned three methods. Extensibility is attained by defining two service interfaces:
- LocaleResolver – The LocaleResolver interface defines a method which may be implemented by a service outside of the sling.i18n bundle. If no such service is registered the default behaviour is as described above for the sling.core bundle. The service described by this interface is used to implement the getLocale() and getLocales() method.
- ResourceBundleProvider – The ResourceBundleProvider interface defines two methods to acquire a ResourceBundle for any Locale and an optional base name. This service interface is not intended to be implemented outside of the sling.i18n bundle: A JCR Repository based implementation is contained in the sling.i18n bundle. The ResourceBundleProvider service is not only used within the sling.i18n bundle to implement the SlingHttpServletRequest.getResourceBundle(Locale) and SlingHttpServletRequest.getResourceBundle(String, Locale) methods. The service may also be used by Sling applications to acquire ResourceBundle instances without having a request object by getting the service and calling its getResourceBundle(Locale) or getResourceBundle(String, Locale) method directly.
JCR Repository based ResourceBundleProvider
The sling.i18n Bundle provides the implementation of the ResourceBundleProvider interface, which may also be used outside of Sling requests for service tasks. This implementation gets the messages from a JCR Repository stored below nodes of the mixin node type mix:language or sling:Language. These language nodes have a jcr:language property naming the language of the resources. In the context of the JCR based ResourceBundleProvider this is of course expected to be the string value of respective Locale.
The (direct) child nodes of the mix:language node must contain two special properties naming the key string and the message:
- sling:key – The sling:key property is a string property being the key for which the node contains the message(s).
- sling:message – The sling:message property represents the resource for the key.
The exact location of these nodes is not relevant as the ResourceBundleProvider finds them by applying a JCR search. It is only required that the message nodes are located below mix:language or sling:Language nodes. Such structures may also be scattered in the repository to allow storing message resources next to where they are most likely used, such as request scripts.
ResourceBundle with base names
Similar to standard Java ResourceBundle instances, Sling ResourceBundle instances may be created for base names through any of the getResourceBundle(String, Locale) methods. These methods use the base name parameter as a selector for the values of the sling:basename property of the mix:language or sling:Language nodes.
The base name argument can take one three values:
Value | ResourceBundle selection |
---|---|
null | Selects messages of mix:language nodes ignoring the existence or absence of sling:basename properties |
Empty String | Selects messages of mix:language nodes which have sling:basename properties, ignoring the actual values |
Any other Value | Selects messages of mix:language nodes whose sling:basename properties has any value which matches the base name string |
The sling:basename property may be multi-valued, that is the messages of a mix:language nodes may belong to multiple base names and thus ResourceBundle instances.
Sample Resources
Consider the following repository content:
/libs/languages +-- English (nt:folder, mix:language) | +-- jcr:language = en | +-- m1 (sling:messageEntry) | | +-- sling:key = "msg001" | | +-- slign:message = "This is a message" | +-- m2 (sling:messageEntry) | +-- sling:key = "msg002" | +-- slign:message = "Another message" +-- Deutsch (nt:folder, mix:language) +-- jcr:language = de +-- m1 (sling:messageEntry) | +-- sling:key = "msg001" | +-- slign:message = "Das ist ein Text" +-- m2 (sling:messageEntry) +-- sling:key = "msg002" +-- slign:message = "Ein anderer Text" /apps/myApp +-- English (nt:folder, mix:language) | +-- jcr:language = en | +-- mx (sling:messageEntry) | +-- sling:key = "msgXXX" | +-- slign:message = "An Application Text" +-- Deutsch (nt:folder, mix:language) +-- jcr:language = de +-- mx (sling:messageEntry) +-- sling:key = "msgXXX" +-- slign:message = "Ein Anwendungstext"
This content defines two languages en and de with three messages msg001, msg002 and msgXXX each. The names of the respective nodes have no significance at all because all information required is extracted from the jcr:language, sling:key and sling:message properties.
JCR Node Types supporting the JCR Repository based ResourceBundleProvider
The sling.i18n bundle asserts the following node types:
[mix:language] mixin - jcr:language (string)
The mix:language mixin node type allows setting the jcr:language property required by the ResourceBundleProvider implementation to identify the message Locale.
[sling:Language] mixin - sling:basename (string) - sling:basename (string) multiple
The sling:Language mixin node type extends the jcr:language mixin node type and in addition to the language allows the specification of one more more base names to which the contained messages belong. This property is accessed by the getResourceBundle(String, Locale) methods.
[sling:message] mixin - sling:key (string) - sling:message (undefined) [sling:messageEntry] > nt:hierarchyNode, sling:message
The sling:message and slign:messageEntry are helper node types which may be used to create the nodes with the sling:key and sling:message properties required by the ResourceBundleProvider. The node types themselves are not required but by defining the required properties, they may be of use.