Umbraco is very neat and easy to integrate with ASP.NET, probably because it was built on it. One typical scenario is to create a multi-lingual web site with Umbraco, which automatically requires the use of localization. Umbraco supports localization very well and there are two main techniques, I can think of – using a dictionary or using a special page with custom fields. I personally prefer the latter, because one can use nicer names and descriptions for the custom fields, so it is easier and more intuitive to edit the texts.
It is a good idea to create a separate branch in Umbraco for each language in your website. You should keep the language-independent settings in the root node and all language-dependent ones in the branches.
The next step is to use this localization in your custom controls in ASP.NET. Umbraco has a nice control, called item, which can display the contents of a property. By default, this control tried to look up the property in the current node, however you can also specify a node by its id. So, one solution is to use this control and specify the node ID of your Texts node every time (or create some wrapper over this control). However, I find this way very clumsy in spite of the nice properties the item control provides.
If we were to use the traditional resource files, ASP.NET provides very nice syntax to access them.
1 |
<asp:Label Runat="server" Text="<%$ Resources: MyResourceFile, MyKey %>"> |
The special syntax <%$ … %> allows you to use localization pretty easy and clean. Can’t we just use the same syntax, but instead of using resource files to use Umbraco? The answer is simple – yes. ASP.NET provides the so called expressions, which provide a declarative way of setting control properties. We can create our own expression using the ExpressionBuilder class. From the MSDN example we can create the following implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
[ExpressionPrefix("Umbraco")] public class UmbracoExpressionBuilder : ExpressionBuilder { public static object Localize(string expression, Type target, string entry) { return IoC.Resolve().Localize(expression); } public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) { Type type1 = entry.DeclaringType; PropertyDescriptor descriptor1 = TypeDescriptor.GetProperties(type1)[entry.PropertyInfo.Name]; CodeExpression[] exs = new CodeExpression[3]; exs[0] = new CodePrimitiveExpression(entry.Expression.Trim()); exs[1] = new CodeTypeOfExpression(type1); exs[2] = new CodePrimitiveExpression(entry.Name); return new CodeCastExpression(descriptor1.PropertyType, new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(base.GetType()), "Localize", exs)); } } |
Note, that we make use of some inversion of control technique, so that you can reuse this logic in other parts of the code, if necessary. I simple implementation of ILocalization would look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class UmbracoLocalization : ILocalization { private INode LocalizationNode { get { ... } } public string Localize(string key) { IProperty property = LocalizationNode.GetProperty(key); return property == null ? null : property.Value; } } |
You have to write some logic to get the proper Texts node depending on the current culture in the system. The last step is to register your expression builder in web.config. In <system.web> there is a section, called <expressionBuilders>. You should register you builder namely in this section.
1 |
<add expressionPrefix="Umbraco" type="UmbracoLExpressionBuilder" /> |
Now, we can use our custom expression in the following way:
1 |
<asp:Label Runat="server" Text="<%$ Umbraco: MyKey %>"> |