What a challenge - retrofitting globalisation into our behemoth enterprise application.
Wunderbar, merveilleux, замечательный!!!
Ahem - yes, I was excited.
Most likely due to my database intensive upbringing, I was biased towards the translations being in a database table instead of .Net resource files, so that's the way it rolled.
My implementation is basic for now, catering for just one language per country at the moment. To date, we have 5 languages set up, one of them being Ukrainian - I still get a buzz when I log onto our site and see it in
I'm happy with what I've got and the best indicator of its success is that the other developers were using it from day 1 with no need for any guidance. They know nothing of the internals - it just works.
And the results are visible immediately on the webpage.
A nice side-effect of this approach is that new translations can be added through the website by the customers instead of passing them to us for updating a resx file and the subsequent recompilation of the web app this would entail. This is very beneficial to us as we are effectively outsourcing our localisation. And in an application that uses very domain-specific terminology/jargon, a simple Google translate would not work.
The solution described below makes use of Expression Builders to dynamically set the text for HTML or ASP.Net Controls (they need to be runat="server"). For example:
Any attempted translations that do not have an entry in the database are returned to the webpage as the id code pre-fixed with an x.
Any attempted translations that have an English but no corresponding foreign translation are prefixed with an _ underscore - this is carried out in the SQL statement.
Our aim is that the foreign language administrators will never see an x, otherwise they should inform us. When they come across an underscored term, they know they must add a translation in the maintenance screen.
To prevent database connection overload and prevent performance issues, the translations are stored in cache. They are an ideal candidate for caching - relatively static content that rarely changes and used quite extensively.
Upon each update to the Translations table from within the class, the translations cache is refreshed. May seem a bit heavy handed, but additions/changes to the translations are very infrequent. Each request for a translation calls a function (PopulateTranslationCache) to ensure that the cache is populated.
The elements required are:
- Inclusion of the expression signature in the Web.config file.
- TranslationExpressionBuilder.vb - A class that declares the expression to be used and returns the value of the function (the translated text) referenced by the expression.
- Translation.vb - A class that represents the translation object and maps the object fields to the corresponding columns in the database. This will also include the functions required to return the translation to the expression class. A delegate was used as lambdas were not hanging out on the VB scene at the time. (I need to come back to this class and apply the Single Responsibility Principle.)
- The database table to store text and their translations.
- And, of course, an ASP .Net web form that uses the translation expression to evaluate text for controls on the page.
Expression Builder
Web.config:
TranslationExpressionBuilder.vb:
Translation.vb: Web Form:
References:
http://stackoverflow.com/questions/699911/application-variable-in-sqldatasource-control-parameter
http://weblogs.asp.net/infinitiesloop/archive/2006/08/09/The-CodeExpressionBuilder.aspx
http://weblogs.asp.net/ricardoperes/archive/2009/03/04/useful-expression-builders.aspx
http://www.4guysfromrolla.com/articles/030409-1.aspx
No comments:
Post a Comment