Sun 25 Nov 2007
After a little while of tinkering and introducing myself to the Model-Glue 2 (MG) framework I’ve got a working model for creating localized views. I thought some people would find it useful to see how it’s implemented.
The steps involved can be summarized as:
- Create a folder for localized views
- Add a locale configuration bean to the ColdSpring.xml file
- Set every MG request to append the localized views folder (1) to the “viewMappings” configuration setting
To perform the above follow these steps:
1) Create the following folder structure in the “views” foider of your Model-Glue application:
locale/en-US
In this folder place a default view being used by your application. You can place all your views there - and create subfolders to organize views.
2) To create a locale configuration bean perform the following:
First, In the ColdSpring.xml file place the following snippet:
<bean class="MyApplication.beans.LocaleConfig" id="localeConfiguration">
<property name="config">
<map>
<entry key="en_US">
<map>
<entry key="viewMappings"><value>/MyApplication/views/locale/en-US</value></entry>
</map>
</entry>
</map>
</property>
</bean>
Make sure you replace “MyApplication” in the CLASS attribute with the actual name of your application (i.e. path the bean CFC). Do the same for the “viewmappings” definition.
Next, create a LocaleConfiguration CFC in your application. I find it most useful to create a folder at the root level of my application (same level as the “views” folder) named “beans”. The folder structure of your application will look something like something like this (PNG image):
In the “beans” folder create “LocaleConfiguration.cfc” and place the following code in it:
<cfcomponent hint="bean to handle locale configuration" output="false">
<cffunction name="Init" access="public" output="false" hint="new LocaleConfig bean constructor.">
<cfset variables.config = structNew() />
<cfreturn this />
</cffunction>
<cffunction name="SetConfig" access="public" return="void" output="false" hint="Set property: config">
<cfargument name="value" type="struct"/>
<cfset variables.config=arguments.value />
</cffunction>
<cffunction name="GetConfig" access="public" return="struct" output="false" hint="Get property: config">
<cfreturn duplicate(variables.config) />
</cffunction>
<cffunction name="GetConfigSetting" access="public" return="any" output="false" hint="I get a config setting from the config by name.">>
<cfargument name="name" required="true" type="string">
<cfreturn variables.config[arguments.name] />
</cffunction>
<cffunction name="GetState">
<cfreturn variables />
</cffunction>
</cfcomponent>
Finally, we’ll use the “autoWiring” capabilities of MG to automagically load our LocaleConfiguration bean into our controller. Place the following method in “Controller.cfc” of your MG application:
<cffunction name="setLocaleConfiguration" access="public" returntype="void" output="false">
<cfargument name="localeConfiguration" required="true">
<cfset variables.localeConfiguration = arguments.localeConfiguration.GetConfig()>
</cffunction>
Doing this means Controller.cfc (and it’s OnRequestStart() method - which we’ll see next) will have a private member with the configuration structure from our LocalConfiguration bean.
3) Setting every request to use the localized views folder is straightforward. The MG framework provides a setConfigSetting() method that takes “name” and “value” parameters. What we want to do is append the “viewMappings” configuration setting with our localized folder.
We could replace the “viewMappings” setting but this would result in poor degradation: if no locale configuration was present, the MG framework threw an exception, or other unpredictable circumstances occured we would get misleading errors about missing views.
Place the following code in the “OnRequestStart()” method of “Controller.cfc”:
<cfif isdefined("variables.localeConfiguration")>
<cfset getModelGlue().setConfigSetting("viewMappings", listappend(getModelGlue().getConfigSetting("viewMappings"), variables.localeConfiguration.en_US.viewMappings))>
</cfif>
Now you can set your event-handler view statements as usual. The only difference is they will be pulled from a localized folder. Obviously at least two major things are missing from this article:
- No logic is present to switch locales based on user preferences. Such information would likely be stored in the session. I’ll add example code for this later as the model matures.
- No examples of localized text in a view are provided. I’ll leave this for you to figure out how you want to implement. To start you can hardcode localized/translated text/messages into your localized views. A better solution is to use a resource bundle. A good overview of some of the issues and solution strategies can be found on Ray Camden’s blog.
Happy coding!
3 Responses to “Localization in Model-Glue 2”
Leave a Reply
You must be logged in to post a comment.
April 17th, 2008 at 3:42 pm
[…] A different approach than that of mine can be found here: Localization in Model-Glue 2 That solution involves creating pages for each locale. This is in contrast to my solution, where I have one page, but many language files. […]
April 25th, 2008 at 11:05 am
Well, I said, “No examples of localized text in a view are provided.” So, I’m glad there’s a solution out there.
The important thing is: the two solutions - mine presented herein - and the one presented by “Clogging up the Web” - shouldn’t be viewed as mutually exclusive. As Ray Camden pointed out (link above), localization isn’t just provided translated text tokens. In some cases the UI has differing layout/structure from locale to locale. Japanese, Chinese, and Hebrew locales are excellent examples.
A clever engineer out there should now have enough to architect a decent localization/internationalization system on MG2. But if anybody wants me to post a full example implementation let me know. Otherwise you’ll have to wait a while until I get time and necessity to go there…
April 26th, 2008 at 8:49 pm
Your point is well made. Both approaches have their place and can even be implemented at the same time. I can imagine scenarios where your approach would be useful with different page structures, not just different languages, depending on the country.