Liferay DXP Core and portlet module language*.properties
files implement site
internationalization. They’re fully customizable, too. This tutorial
demonstrates this in the following topics:
- Overriding Global Language Keys
- Overriding a Module’s Language Keys
Modifying Global Language Keys
Language files contain translations of your application’s user interface messages. But you can also override the default language keys globally and in other applications (including your own). Here are the steps for overriding language keys:
- Determine the language keys to override
- Override the keys in a new language properties file
- Create a Resource Bundle service component
Determine the language keys to override
So how do you find global language keys? They’re in the Language[xx_XX].properties
files in the source code or your Liferay DXP bundle.
-
From the source:
/portal-impl/src/content/Language[_xx_XX].properties
-
From a bundle:
portal-impl.jar
All language properties files contain properties you can override, like the language settings properties:
##
## Language settings
##
...
lang.user.name.field.names=prefix,first-name,middle-name,last-name,suffix
lang.user.name.prefix.values=Dr,Mr,Ms,Mrs
lang.user.name.required.field.names=last-name
lang.user.name.suffix.values=II,III,IV,Jr,Phd,Sr
...
There are also many simple keys you can override to update default messages and labels.
##
## Category titles
##
category.admin=Admin
category.alfresco=Alfresco
category.christianity=Christianity
category.cms=Content Management
...
For example, Figure 1 shows a button that uses Liferay’s publish
default
language key.
publish=Publish
Next, you’ll learn how to override this key.
Override the keys in a new language properties file
Once you know the keys to override, create a language properties file for the
locale you want (or the default Language.properties
file) in your module’s
src/main/resources/content
folder. In your file, define the keys your way. For
example, you could override the publish
key.
publish=Publish Override
To enable your change, you must create a resource bundle service component to reference your language file.
Create a Resource Bundle service component
In your module, create a class that extends java.util.ResourceBundle
for the
locale you’re overriding. Here’s an example resource bundle class for the
en_US
locale:
@Component(
property = { "language.id=en_US" },
service = ResourceBundle.class
)
public class MyEnUsResourceBundle extends ResourceBundle {
@Override
protected Object handleGetObject(String key) {
return _resourceBundle.getObject(key);
}
@Override
public Enumeration<String> getKeys() {
return _resourceBundle.getKeys();
}
private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(
"content.Language_en_US", UTF8Control.INSTANCE);
}
The class’s _resourceBundle
field is assigned a ResourceBundle
. The call to
ResourceBundle.getBundle
needs two parameters. The content.Language_en_US
parameter is the language file’s qualified name with respect to the module’s
src/main/resources
folder. The second parameter is a control
that sets the
language syntax of the resource bundle. To use language syntax identical to
Liferay’s syntax, import Liferay’s
com.liferay.portal.kernel.language.UTF8Control
class and set the second
parameter to UTF8Control.INSTANCE
.
The class’s @Component
annotation declares it an OSGi ResourceBundle
service
component. It’s language.id
property designates it for the en_US
locale.
@Component(
property = { "language.id=en_US" },
service = ResourceBundle.class
)
The class overrides these methods:
-
handleGetObject
: Looks up the key in the module’s resource bundle (which is based on the module’s language properties file) and returns the key’s value as anObject
. -
getKeys
: Returns anEnumeration
of the resource bundle’s keys.
Your resource bundle service component redirects the default language keys to your module’s language key overrides.
Important: If your module uses language keys from another module and overrides any of that other module’s keys, make sure to use OSGi headers to specify the capabilities your module requires and provides. This lets you prioritize resource bundles from the modules.
To see your Liferay language key overrides in action, deploy your module and visit the portlets and pages that use the keys.
That’s all there is to overriding global language keys.
Overriding a Module’s Language Keys
What do you do if the language keys you want to modify are in one of Liferay’s applications or another module whose source code you don’t control? Since module language keys are in the respective module, the process for overriding a module’s language keys is different from the process of overriding global language keys.
Here is the process:
- Find the module and its metadata and language keys
- Write your custom language key values
- Prioritize your module’s resource bundle
Find the module and its metadata and language keys
In Gogo shell, list the bundles and grep for keyword(s) that match the portlet’s display name. Language keys are in the portlet’s web module (bundle). When you find the bundle, note its ID number.
To find the Blogs portlet, for example, your Gogo commands and output might look like this:
g! lb | grep Blogs
152|Active | 1|Liferay Blogs Service (1.0.2)
184|Active | 1|Liferay Blogs Editor Config (2.0.1)
202|Active | 1|Liferay Blogs Layout Prototype (2.0.2)
288|Active | 1|Liferay Blogs Recent Bloggers Web (1.0.2)
297|Active | 1|Liferay Blogs Item Selector Web (1.0.2)
374|Active | 1|Liferay Blogs Item Selector API (2.0.1)
448|Active | 1|Liferay Blogs API (3.0.1)
465|Active | 1|Liferay Blogs Web (1.0.6)
true
List the bundle’s headers by passing its ID to the headers
command.
g! headers 465
Liferay Blogs Web (465)
-----------------------
Manifest-Version = 1.0
Bnd-LastModified = 1459866186018
Bundle-ManifestVersion = 2
Bundle-Name = Liferay Blogs Web
Bundle-SymbolicName = com.liferay.blogs.web
Bundle-Version: 1.0.6
...
Web-ContextPath = /blogs-web
g!
Note the Bundle-SymbolicName
, Bundle-Version
, and Web-ContextPath
. The
Web-ContextPath
value, following the /
, is the servlet context name.
Important: Record the servlet context name, bundle symbolic name and version, as you’ll use them to create the resource bundle loader later in the process.
For example, here are those values for Liferay Blogs Web module:
- Bundle symbolic name:
com.liferay.blogs.web
- Bundle version:
1.0.6
- Servlet context name:
blogs-web
Next find the module’s JAR file so you can examine its language keys. Liferay follows this module JAR file naming convention:
[bundle symbolic name]-[version].jar
For example, the Blogs Web version 1.0.6 module is in
com.liferay.blogs.web-1.0.6.jar
.
Here’s where to find the module JAR:
- Liferay’s Nexus repository
[Liferay Home]/osgi/modules
- Embedded in an application’s or application suite’s LPKG file in
[Liferay Home]/osgi/marketplace
.
The language property files are in the module’s
src/main/resources/content
folder. Identify the language keys you want to
override in the Language[_xx].properties
files.
Checkpoint: Make sure you have the required information for overriding the module’s language keys:
- Language keys
- Bundle symbolic name
- Servlet context name
Next you’ll write new values for the language keys.
Write custom language key values
Create a new module to hold a resource bundle loader and your custom language keys.
In your module’s src/main/resources/content
folder, create
language properties files
for each locale whose keys you want to override. In each language properties
file, specify your language key overrides.
Next you’ll prioritize your module’s language keys as a resource bundle for the target module.
Prioritize Your Module’s Resource Bundle
Now that your language keys are in place, use OSGi manifest headers to specify
the language keys are for the target module. To compliment the target module’s
resource bundle, you’ll aggregate your resource bundle with the target module’s
resource bundle. You’ll list your module first to prioritize its resource bundle
over the target module resource bundle. Here’s an example of module
com.liferay.docs.l10n.myapp.lang
prioritizing its resource bundle over target
module com.liferay.blogs.web
’s resource bundle:
Provide-Capability:\
liferay.resource.bundle;resource.bundle.base.name="content.Language",\
liferay.resource.bundle;resource.bundle.aggregate:String="(bundle.symbolic.name=com.liferay.docs.l10n.myapp.lang),(bundle.symbolic.name=com.liferay.blogs.web)";bundle.symbolic.name=com.liferay.blogs.web;resource.bundle.base.name="content.Language";service.ranking:Long="2";\
servlet.context.name=blogs-web
Let’s examine the example Provide-Capability
header.
-
liferay.resource.bundle;resource.bundle.base.name="content.Language"
declares that the module provides a resource bundle whose base name iscontent.language
. -
The
liferay.resource.bundle;resource.bundle.aggregate:String=...
directive specifies the list of bundles whose resource bundles are aggregated, the target bundle, the target bundle’s resource bundle name, and this service’s ranking:"(bundle.symbolic.name=com.liferay.docs.l10n.myapp.lang),(bundle.symbolic.name=com.liferay.blogs.web)"
: The service aggregates resource bundles from bundlescom.liferay.docs.l10n.myapp.lang
andcom.liferay.blogs.web
. Aggregate as many bundles as desired. Listed bundles are prioritized in descending order.bundle.symbolic.name=com.liferay.blogs.web;resource.bundle.base.name="content.Language"
: Override thecom.liferay.blogs.web
bundle’s resource bundle namedcontent.Language
.service.ranking:Long="2"
: The resource bundle’s service ranking is2
. The OSGi framework applies this service if it outranks all other resource bundle services that targetcom.liferay.blogs.web
’scontent.Language
resource bundle.servlet.context.name=blogs-web
: The target resource bundle is in servlet contextblogs-web
.
Deploy your module to see the language keys you’ve overridden.
Now you can modify the language keys of modules in Liferay’s OSGi runtime. Remember, language keys you want to override might actually be in Liferay’s core. You can override global language keys too.
Related Topics
Resource Bundle Override Sample Project