Monthly Archives: January 2010

Visit to Sweet Water Organics

This past Wednesday, I had the pleasure of exploring a hidden gem in Milwaukee.  Sweet Water Organics is a local company based in Bay View that is commercializing Will Allen‘s aquaponic system.  Aquaponics is the method of growing crops and fish together in a re-circulating system.  They had an “open house” and perch auction to not only generate some cash for the business but to also show off their digs.

Nicole and I hung out there for just under two hours.  Among others, we spoke with Jesse Hull, the man responsible for keeping Sweet Water operational and its lead horticulturist.  Not only did he blow me away with his knowledge of plants, our conversation ranged from the 5-second rule to using grow lights for heat transfer.  It was very stimulating to chat with him and I look forward to talking with him in the future.

Sweet Water Organics has great connections with many local chefs and restaurants.  They’re all about the miles to market mantra, where they try to provide local, sustainable ingredients.  They are looking to have retail operations in the future, that will allow you to buy fresh produce and fish directly from them.  Until that happens, you’ll be able to buy fish at upcoming auctions like the one they just had.

The vibe I felt while there was similar to how Lakefront Brewery felt in its early days.  There’s an excitement in the air and everyone knows that Sweet Water Organics is not only a benefit to the people but also the community.  Interesting to note, Lakefront provided a keg of delicious beer for all to enjoy while they mingled throughout the building.

Localize Asp.Net MVC Views using a LocalizedViewEngine

Localizing content is never an easy task.  Asp.Net tries to make localization and globalization easier with built in support for resources and cultures.  While I think that is a good start, I feel that the typical localization technique for asp.net applications is slightly misdirected and could be implemented easier.

In the past, I’ve put every sentence into a culture specific resource file.  Those sentences may be composite format strings or they could just be fragments.

This not only makes it difficult to rapidly develop, but can also create some rather difficult situations when special characters are introduced.  Think percent signs and currency symbols on Edit views.  Not to mention getting right-to-left languages like Arabic to display nicely.

A different approach

I propose a different solution to resource files that contain string fragments.  Rather than piecing together views with resource fragments, why not just have one view per language, per action.  Each language specific view can be identified by including culture names in their file name.

So if you have an Index action on the Home controller and want to support the default language (en-US) and Japanese (ja-JP), you would have the following files:

/Views/Home/Index.aspx
/Views/Home/Index.ja-JP.aspx

An added benefit to this method, is that it allows you to add new translations to your web application without requiring a recompile.  Along those lines, you can incrementally translate your site as budget and time allow.  If you haven’t added a translated view yet, the view engine will fall back on the default language view.

What are the downsides?

While this all sounds like a nice solution, there is one major downfall.  You duplicate the markup in many places.  So if or when you make a change in the future, you’ll have to go through each language specific view and make the change there as well.  That’s a lot to ask of a developer, but I feel that this method outweighs trying to piece together fragments and maintain text outside of the view.

How is this accomplished?

As everyone is aware, Asp.net MVC allows developers to extend the framework rather easily.  To allow for language specific views, we just need to tweak the WebFormViewEngine to first check for the view of the CurrentUICulture.  If that page is not found, let the view engine continue as it normally would.

public class LocalizedWebFormViewEngine : WebFormViewEngine
{
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
string localizedPartialViewName = partialViewName;
if (!string.IsNullOrEmpty(partialViewName))
localizedPartialViewName += “.” + Thread.CurrentThread.CurrentUICulture.Name;

var result = base.FindPartialView(controllerContext, localizedPartialViewName, useCache);

if (result.View == null)
result = base.FindPartialView(controllerContext, partialViewName, useCache);

return result;
}

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
string localizedViewName = viewName;
if (!string.IsNullOrEmpty(viewName))
localizedViewName += “.” + Thread.CurrentThread.CurrentUICulture.Name;

string localizedMasterName = masterName;
if (!string.IsNullOrEmpty(masterName))
localizedMasterName += “.” + Thread.CurrentThread.CurrentUICulture.Name;

var result = base.FindView(controllerContext, localizedViewName, localizedMasterName, useCache);

if (result.View == null)
result = base.FindView(controllerContext, viewName, masterName, useCache);

return result;
}
}

To specify that you would like to use the LocalizedViewEngine, modify the Application_Start method in your Global.asax.cs file to be similar to:

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new LocalizedWebFormViewEngine());
}

That’s it.  I’m interested in hearing your thoughts about this method.