Localizing the Content
Every piece of content on a Charlie webpage is based on the Entity System. Therefore, to localize the content of a webpage requires localizing the entities.
My first instinct here was to introduce a new class named LocalizedEntity, which would inherit from Entity. I created the class in Visual Studio, provided it with a Culture property, and then proceeded to change some of Charlie’s business objects to inherit from this new LocalizedEntity class. What I discovered is that having two very closely related classes made things unnecessarily complex. Originally, the existence of a single base class (Entity) made the underlying Entity System very simple and very flexible. However, the introduction of a closely-related class (LocalizedEntity) removed the simplicity and limited the flexibility. So, I removed this new LocalizedEntity class, and moved its Culture property to the underlying Entity class.
Initially this concerned me a little. Not all entities will have text properties, so having a Culture property seemed a little inconsistent (it affected the cohesion of the class). But, I then considered what would happen if I later added a text property to an existing business object (say, to the Role business object). If the Culture property is down in the Entity base class, I can “switch on” the Culture property, switching it away from its InvariantCulture default value. Conversely, if the Culture property existed in a deriving base class of LocalizedEntity, adding a text property to the Role business object would require that the Role class change its base class. Changing the base class in order to add a property is a most undesirable situation. So, I kept the Culture property in the base Entity, and removed the LocalizedEntity class.
Looking away from the class design and turning towards the database design, how do we support localization at the database? Fortunately, I did not have to think this one through, as Karl Seguin had already provided me with the answer in the second part of his two-part article series, Creating Multilingual Websites. Karl explains the problem and the solution very well, so I will not repeat it. In summary, each Entity in Charlie is supported by at least two database tables. One table holds culture-agnostic information (such as dates and numbers), and the other table holds culture-sensitive information (text). Here is a part of the Charlie’s table design shown in SQL Enterprise Manager:
The two separate tables are brought together using a JOIN statement so simple that even I have been able to work with this database structure. What is particularly nice about this two-tables-per-entity database schema is that represents a simple convention. An ongoing approach to the development of Charlie has been to find conventions that can be applied again and again. I’d like to say something impressive, maybe “conventions promote internal consistency and increase component cohesion.” But the truth is, I’m just not smart enough to have too many tricks in my programming bag. If I find a trick that works, well, dammit, I’ll use that trick everywhere.
As evidence of my repeated use of conventions, Charlie localizes content by using the same cascading logic as was used to localize chrome and to obtain role permissions. If the user requests the Canadian French version of an article, Charlie will first look for the article in that specific culture (fr-CA). If it is not available, Charlie will then look for the article in the neutral culture (fr). If it is not available, Charlie will then look for the article in the default culture. (There’s actually a bit more to it, but that's the basis of the cascade.)
The end result of my efforts is that Charlie is now globalized. This has not been achieved by the conventional wisdom of resource files and satellite assemblies, but rather by the application of a database schema and supporting code. I believe that this approach is more simple and more configurable, which makes the approach consistent with the specifications for Charlie.
by Alister Jones | Next up: Getting Entities onto the Page →
----
Post a Comment