Plugins:i18n
<< Back to Dashboard | << Plugins Viewer
|
Internationalization (i18n) & Resource Bundles Usage in ColdBox
ColdBox comes with two plugins and some configuration setup in the coldbox.xml that will facilitate any project to be internationalized. This guide will not explain what internationalization is or a full in depth guide on resource bundles. For that, see the Resources section below. A project can be internationalized and use resource bundles for displaying per locale strings or just use internationalization without resource bundles. Another features are that you can use the plugins separate from the coldbox.xml declarations. So basically you can programmatically use i18n and resource bundles. The ColdBox bundle download also includes a i18N sample application that you can learn from. Also, the samples gallery is an internationalized application that you can learn from.
Credits
These plugins are based on Mr. Paul Hastings work and all credit goes to him. I only converted them to a ColdBox plugin and wired them for usage in the framework. http://www.sustainablegis.com/blog/cfg11n/
Coldbox.xml Declarations
In the coldbox.xml you can declare in the <i18n> section the default resource bundle to use, the default locale of the application, and the storage space of the locale by the framework. For more information please visit the Configuration Guide
<i18N> <--D<efault Resource Bundle without locale and properties extension--> <DefaultResourceBundle>includes/main</DefaultResourceBundle> <--J<ava Standard Locale--> <DefaultLocale>en_US</DefaultLocale> <--s<ession or client--> <LocaleStorage>session</LocaleStorage> <-- <Unknown Translation ---> <UnknownTranslation>NO_TRANSLATION</UnknownTranslation> </i18N>
The code above will tell the framework to load the resource bundle main for locale en_US and save the user locale information in the session scope. The only available user scopes are client, session and cookie. You can also use the config declaration for a i18n project with no resource bundles by using the following declaration:
<i18N> <--J<ava Standard Locale--> <DefaultLocale>en_US</DefaultLocale> <--s<ession or client--> <LocaleStorage>session</LocaleStorage> </i18N>
You eliminate the resource bundle element or leave it blank. The framework will not load the bundle.
From this point, the framework loads any default resource bundle into the ColdBox cache and sets the locale you will be using. It is then up to you (DEVELOPER) to code the necessary hooks for internationalization. The last element is the UnknownTranslation element that is used in the resource bundles plugin. If a resource is asked for that does not exist in the bundle, this element contents will be used or if not declared, the default of UNKOWN_TRANSLATION will be used.
Important: All language resource bundles are stored in the configuration structure of your application and are lazy loaded in. So if a language is not used, then it does not get loaded. This is separate to where the user's locale information is stored.
Coding for i18n
Now that you have completed the initialization of the i18n tags in the configuration file, you are ready to code for them.
Note: Please note that the i18N plugin gets cached by default on the ColdBox Cache indefinitely. You do not need to do any persistence on this object.
<cffunction name="onAppInit" access="public" returntype="void" output="false"> <cfargument name="event" type="any"> <--- Set a default Locale, just in case ---> <cfset getPlugin("i18n").setfwLocale(getSetting("DefaultLocale"))> </cffunction> <cffunction name="onRequestStart" access="public" returntype="void" output="false"> <cfargument name="event" type="any"> <--- place plugin object on request collection for easy reference ---> <cfset event.setValue("localeUtils",getPlugin("i18n"))> </cffunction>
I call setfwLocale(getSetting("DefaultLocale")) on the application start method. This code tells the plugin what locale to instantiate the java classes in. You now have a locale specific i18n Plugin loaded for usage. You can look at the plugins API to see all the methods the i18n plugin contains. On my on request start method I then place the plugin on the event scope in order to be accessed from an alias on my views. I can actually skip this step and just use consecutive getPlugin("i18n") calls. So there are alternatives.
You can then use this utility for i18n specific methods, below is a simple example:
<cfoutput > <strong>Locale:</strong> <br />#rc.localeUtils.getfwLocale()#<br /> <strong>Language:</strong> <br />#rc.localeUtils.showLanguage()#<br /> <strong>Country:</strong> <br />#rc.localeUtils.showCountry()#<br /> <strong>TimeZone:</strong> <br />#rc.localeUtils.getServerTZ()#<br /> <strong>i18nDateFormat:</strong> <br />#rc.localeUtils.i18nDateFormat(rc.localeUtils.toEpoch(now()),1)#<br /> <strong>i18nTimeFormat:</strong> <br />#rc.localeUtils.i18nTimeFormat(rc.localeUtils.toEpoch(now()),2)#<br /> <hr> <strong>I18NUtilVersion:</strong> <br />#rc.localeUtils.getVersion().I18NUtilVersion#<br> <strong>I18NUtilDate:</strong> <br />#rc.localeUtils.dateLocaleFormat(rc.localeUtils.getVersion().I18NUtilDate)#<br> <strong>Java version:</strong> <br />#rc.localeUtils.getVersion().javaVersion#<br> </cfoutput>
Resource Bundle Usage
You have declared the i18n section in your config and now you want to display locale specific text on your layouts, views, event handlers, etc. Well, all you need to do is use the getResource("Key") method. This method can be called from anywhere within the framework to retrieve a key from the current set locale's resource bundle. If you have not used resource bundles before or have no clue of what they are, please see the Resources at the end of this guide. It is a basic concept of getting key values from a structure.
String Substitutions
I recommend that you read the API for the resource bundle and the i18 plugin as they contain tons of methods that you can use for your internationalization and localization needs. One such method that is very handy is the formatRBString() method. This method is used in conjunction with the getResource() method. This will allow you to do dynamic text substitutions within resource strings. Wow! That was a mouthful. What does it mean? Well, it means that if you have a resource that looks like this:
confirmMessage=Thank you {1} for your recent order. Please call {2} for any suggestions.
Then you can actually substitute the {1} and {2} with dynamic data very easily using this formatRBString() method.
- formatRBString(string rbString, any substituteValues)
This method takes in a resource string and substitution values as a simple value or an array of values. So to substitute values, I would do something like:
<cfset oRB = getPlugin("resourceBundle")> <cfset orderDetails = ArrayNew(1)> <cfset orderDetails[1] = "Luis Majano"> <cfset orderDetails[2] = "1-800-555-5555"> <cfoutput>#oRB.formatRBString(getResource('confirmMessage'),orderDetails)#</cfoutput>
Resource Bundle Tools
- A great utility that I have found is Attesoro, which can help you build your resource bundles. It is also included with ColdBox
- Eclipse Resource Bundle Editor Plugin: http://sourceforge.net/projects/eclipse-rbe/ is another FANTASTIC editor for eclipse.
- IBM's Resource Bundle Manager which is awesome too.
Below you can see some screenshots of the eclipse resource bundle editor plugin. I really recommend this tool also
<div align="center"> <img src="http://sourceforge.net/dbimage.php?id=29500"> <img src="http://sourceforge.net/dbimage.php?id=29496"> <img src="http://sourceforge.net/dbimage.php?id=29494"> </div>
Note: Make sure your files are all utf-8 encoding. It's also good i18n practice to liberally use cfprocessingdirective
Here is a simple example of how to use the getResource() method:
<p> </p> <h2>#getresource("about")# ColdBox </h2> <p>#getResource("aboutcoldbox")# </p> </div>
It makes a call to the getResource method with a key to retrieve. ColdBox then retrieves the appropriate key from the loaded resource bundle. If no key is found it will return an _UNKNOWNTRANSLATION value.
How do I change Locales?
Well, it would not make any sense to use i18n for just one locale, would it? That is why you need to be able to change the framework's locale programmatically. You can do this in two ways:
- Using the i18n plugin and calling the setfwLocale() method.
- Using the i18n plugin instance that you loaded into the application scope (or any scope you loaded it in) and calling the setfwLocale method on it.
Below you can see an example taken from the samples gallery:
<cffunction name="doChangeLocale" access="public" returntype="void" output="false"> <cfargument name="event" type="any"> <--- Change Locale ---> <cfset getPlugin("i18n").setfwLocale(event.getValue("locale"))> <cfset event.setNextEvent('main.home')> </cffunction>
It calls the plugin instance and tells it to load the locale submitted. If an incorrect or unsupported locale (by the JVM) then the framework will throw an invalid locale exception.
Notes
The i18n plugin contains several methods that you can use for i18n purposes, from language codes, timezone support, offsets, etc. You also have the resourceBundle plugin that you can use to load on the fly resource bundle files, parse them, etc. Please the cfc documentation for all the possibilities with these plugins.
Best Practices
- eclipse (not CFEclipse) doesn't add a BOM to UTF-8 encoded files.
- Always use cfprocessingdirective
<cfprocessingdirective pageencoding="utf-8">
- ColdBox uses the core java resource bundle flavor so you have to use a proper resource bundle tool to manage these.
Resources
- http://www.melody-soft.com/html/unifier.html (vista-compatibleUnifier converts a batch of plain text or HTML files in various characters set encoding to Unicode in UTF-16 or UTF-8 encoding)
- http://www.i18ngurus.com/
- http://www.xencraft.com/resources/webi18ntutorial.pdf
- http://www.adobe.com/support/coldfusion/internationalization/internationalization_cfmx/
- http://coldfusion.sys-con.com/read/43795.htm
- http://sourceforge.net/projects/eclipse-rbe/
- Attesoro : A great Resource Bundles utility.
- rbManager from icu4j
- RBman

SideBar
User Login 




Comments (