Overriding Global Language Translations with Language Properties
Liferay DXP/Portal implements headings, labels, and messages for many locales using language translations. You can override these translations for any of the locales using new language translation values in a module.
The Language Override tool is the recommended approach for overriding language translations. This tool is available in Liferay DXP 7.4 U4 (Update 4) and above or Liferay Portal 7.4 GA8 and above. Continue reading for the previous way.
Examining the Global Language Translations
The global language translations are in the source code and the DXP/Portal bundle.
In the source:
liferay-[dxp|portal]/portal-impl/src/content/Language[_xx_XX].properties
liferay-[dxp|portal]/modules/apps/portal-language/portal-language-lang/src/main/resources/content/Language[_xx_XX].properties
In the bundle:
portal-impl.jar#content/Language[_xx_XX].properties
Liferay Foundation - Liferay Portal Language - Impl.lpkg
→com.liferay.portal.language.lang-[version].jar#content/Language[_xx_XX].properties
Language translations for different languages and locales can be identified by the filename ending. For example, Language_ja.properties
is for Japanese.
These language translation files contain properties that you can override, like the language settings properties:
...
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 translations you can override for messages and labels.
...
category.admin=Admin
category.alfresco=Alfresco
category.christianity=Christianity
category.cms=Content Management
...
Overriding Language Translations Programmatically
In Liferay DXP/Portal 7.4+, you can declare overrides using metadata. In earlier versions, Java classes declare the overrides.
If your version is earlier than 7.4, skip ahead to Overriding in Earlier Versions.
Deploy the Example for 7.4+
This example changes the home
language translation setting to this:
home=I2F4 Home
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.120-ga120
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps to deploy the example:
-
Download and unzip the
liferay-i2f4.zip
example project.curl https://resources.learn.liferay.com/dxp/latest/en/liferay-internals/extending-liferay/liferay-i2f4.zip -O
unzip liferay-i2f4.zip
-
Build and deploy the project module.
cd liferay-i2f4
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
NoteThis command is the same as copying the deployed jars to
/opt/liferay/osgi/modules
on the Docker container. -
Confirm the deployment in the Liferay Docker container console.
STARTED com.acme.i2f4.impl_1.0.0 [3209]
-
Verify the example module’s customization. Open your browser to
https://localhost:8080
. -
Click the menu icon (). The home icon label uses the custom language translation value.
-
The example includes custom language translation values for multiple locales. For example, use the language selector to select Brazilian Portuguese or Japanese to see the customization in that locale. The module overrides language translations for these locales too.
Now that you’ve seen the example, here’s how it works.
Create a Language Properties File
Select the translations you want to override. The example module overrides the home
language translation.
home=I2F4 Home
The values for the language translations you declare override the values for those existing translations. All other existing language translation settings are preserved.
Once you’ve decided which translations to override, create a language properties file in your module’s src/main/resources/content
folder. Use the file name Language.properties
to override the default locale’s language translations. To override a specific locale’s translations, use the language properties file naming convention: Language[_xx_XX].properties
.
For example, if you’re overriding Japanese, use Language_ja.properties
.
Declare the Override in the Bnd File
In your module’s bnd.bnd
file, specify your language resource provider capability. Here is the example’s Provide-Capability
header:
Provide-Capability:\
liferay.language.resources;\
resource.bundle.base.name="content.Language"
The example omits a service ranking—it uses OSGi’s default ranking 0
, which is higher than the default global resource bundle service ranking -1
.
Global language translation overrides are easiest to manage when they’re in the same module.
Although we don’t recommend using multiple modules to override global language translations, if you override the same translation in multiple modules, the language resource provider with the highest service ranking wins.
For example, if you want your module’s language translations to take priority over translations from a provider that has service ranking 1
, set your ranking to 2
or higher.
Provide-Capability:\
liferay.language.resources;\
resource.bundle.base.name="content.Language";\
service.ranking:Long="2"
Deploy the module to see your new language translation values.
Overriding in Earlier Versions
On Liferay DXP/Portal versions earlier than 7.4, overriding global language translations requires a language properties file and a java.util.ResourceBundle
for each translation being customized. Learn more by deploying the following example and examining its code.
Many of the language translations are in the global language translation files, but some may be located in specific application modules. The process of overriding module language translation in earlier versions is different from overriding the global translations.
Deploy the Example for Earlier Versions
This example changes the publish
language translation setting to this:
publish=X8F3 Publish
Here’s how to deploy the example:
-
Download and unzip the
liferay-x8f3.zip
example project.curl https://resources.learn.liferay.com/dxp/latest/en/liferay-internals/extending-liferay/liferay-x8f3.zip -O
unzip liferay-x8f3.zip
-
Build and deploy the project module.
cd liferay-x8f3
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
-
Confirm the deployment in the Liferay Docker container console.
STARTED com.acme.x8f3.impl_1.0.0 [3209]
-
Open your browser to
https://localhost:8080
and sign in. -
Navigate to a page and click the edit icon (). The publish button shows the custom language translation.
-
Use the language selector to select Brazilian Portuguese or Japanese to see the custom language translation. The module overrides language translations for each locale you include in the module.
Like the 7.4+ example, this module specifies custom values in language translation files. Instead of using metadata (a bnd.bnd
file header) to declare the override, however, the module uses ResourceBundle
classes.
Create Resource Bundle Classes
Each locale you’re overriding requires a class that extends java.util.ResourceBundle
. Here’s the example resource bundle class for the en_US
locale:
@Component(property = "language.id=en_US", service = ResourceBundle.class)
public class X8F3EnglishResourceBundle extends ResourceBundle {
@Override
public Enumeration<String> getKeys() {
return _resourceBundle.getKeys();
}
@Override
protected Object handleGetObject(String key) {
return _resourceBundle.getObject(key);
}
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/content
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. Its 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 translation in the module’s resource bundle (which is based on the module’s language properties file) and returns the key’s value as an Object
.
getKeys
: Returns an Enumeration
of the resource bundle’s keys.
Your resource bundle service component redirects the default language translation to your module’s language translation overrides.
Global language translation overrides for multiple locales require a separate resource bundle class for each locale. For example, the tutorial code has one for Brazilian Portuguese, English, and Japanese. Each resource bundle must specify its locale in the language.id
component property definition and in the language file qualified name parameter. For example, here is what they look like for the Japanese locale.
Component definition:
@Component(property = "language.id=ja", service = ResourceBundle.class)
Resource bundle assignment:
private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(
"content.Language_ja", UTF8Control.INSTANCE);
Deploy your module to see your new language translation values.
When you’re ready to upgrade to DXP 7.4+, you can continue to use your language translation override module. Optionally, you can simplify the module by removing the ResourceBundle
class and specifying the Provide-Capability
header in your bnd.bnd
file as demonstrated above.