Overriding A Module’s Language Keys

Simplifying: i18n with OSGi in Liferay 7

If you are here, you are probably looking for a way to translate some language keys for your application and probably read Liferay's official guide looking for a simple way to do it. Importunately, the guide does not look like what you would expect, with many steps and unnecessary explanations. It even tells you to go to a repository looking for jar files, only to read metadata that you could easily just get from GitHub.

In this post I will show you a simple component you can use as an example to translate portlets just like you do for the global keys. The procedure for portal keys is extremely simple (OVERRIDING GLOBAL LANGUAGE KEYS), and I will show you a similar approach.   

  1. Determine the language keys to override
  2. Override the keys in a new language properties file
  3. Create a service component

import com.liferay.portal.kernel.util.*;
import org.osgi.service.component.annotations.*;

import java.util.*;

@Component( immediate = true,
			property = {
				"bundle.symbolic.name=com.liferay.knowledge.base.web",
				"resource.bundle.base.name=content.Language",
				"servlet.context.name=knowledge-base-web",
				"service.ranking:Integer=100"
			}, service = ResourceBundleLoader.class )
public class CustomResourceBundleLoader implements ResourceBundleLoader {

	private AggregateResourceBundleLoader resourceBundleLoader;

	@Override
	public ResourceBundle loadResourceBundle( Locale locale ) {

		return resourceBundleLoader.loadResourceBundle( locale );
	}

	@Override
	public ResourceBundle loadResourceBundle( String languageId ) {

		return resourceBundleLoader.loadResourceBundle( languageId );
	}

	@Reference( target = "(bundle.symbolic.name=com.liferay.knowledge.base.web)" )
	public void setResourceBundleLoader( ResourceBundleLoader resourceBundleLoader ) {

		ClassLoader classLoader = this.getClass( )
									  .getClassLoader( );

		ClassResourceBundleLoader classResourceBundleLoader = new ClassResourceBundleLoader( "content.Language", classLoader );
		CacheResourceBundleLoader cacheResourceBundleLoader = new CacheResourceBundleLoader( classResourceBundleLoader );

		this.resourceBundleLoader = new AggregateResourceBundleLoader( cacheResourceBundleLoader, resourceBundleLoader );
	}

}

Now you can just create the translation files you want at: src/main/resources/content

For instance src/main/resources/content/Language_ru_RU.properties 


Liferay 6.2 hook plugins

Another advantage of this approach is that you can easily see similarities with the old hooks you used to have when using Liferay 6.2 hook plugins.


<hook>
    <language-properties>content/Language.properties</language-properties>
    <language-properties>content/Language_en.properties</language-properties>
    <language-properties>content/Language_ru.properties</language-properties>
</hook>
    

Example: blogs

Another example... and you can just keep creating those...


@Component( immediate = true,
			property = {
				"bundle.symbolic.name=com.liferay.blogs.web",
				"resource.bundle.base.name=content.Language",
				"servlet.context.name=blogs-web"
			},
			service = ResourceBundleLoader.class )
class CustomResourceBundleLoader implements ResourceBundleLoader {

	private ResourceBundleLoader resourceBundleLoader;

	@Override
	public ResourceBundle loadResourceBundle( Locale locale ) {

		return resourceBundleLoader.loadResourceBundle( locale );
	}

	@Reference( target = "(bundle.symbolic.name=com.liferay.blogs.web)")
	public void setResourceBundleLoader( ResourceBundleLoader resourceBundleLoader ) {

		ResourceBundleLoader customBundleLoader = new ClassResourceBundleLoader( "content.Language", CustomResourceBundleLoader.class.getClassLoader( ) );
		this.resourceBundleLoader = new AggregateResourceBundleLoader( customBundleLoader, resourceBundleLoader );
	}
}


Overriding Global Language Keys

Just for completeness let's compare with an example of component used for global keys:


@Component( immediate = true,
			property = { "language.id=ru_RU" },
			service = ResourceBundle.class )
public class RussianTranslations extends ResourceBundle {

	private final ResourceBundle resourceBundle = ResourceBundle.getBundle( "content.Language_ru_RU", UTF8Control.INSTANCE );

	@Override
	protected Object handleGetObject( String key ) {

		return resourceBundle.getObject( key );
	}

	@Override
	public Enumeration< String > getKeys( ) {

		return resourceBundle.getKeys( );
	}
}

More Blog Entries

0 Comments