An Agreeable Procrastination – and the blog of Niels Kühnel

Code, the universe and everything

Archive for March 2012

An 101 on the Localization framework in Umbraco 5

with 7 comments

Yes! Umbraco 5 is out, and I remember talking with sir Alex Norcliffe about having one assembly even non-Umbraco projects could use to leverage some of its awesomeness.

That’s “Umbraco.Framework.dll”.

So, you can use Umbraco 5 localization in Umbraco 5 projects, and also in any other project. Just reference “Umbraco.Framework”.

In this blog post I’ll run through:

  • How to use localized texts in views and code
  • How to define your texts
  • MVC conventions (how to set texts for view model labels, validation errors etc. without attributes)
  • How ITextSource can be used to keep your texts in a Google Spreadsheet.
  • How to define custom languages and fallbacks

How to print texts

In views you import the namespace Umbraco.Framework and then you can write


If you need parameters for your text you’ll write

<div>@HtmlGetText("Hello", new {UserName="Bob", NewMessages = 4, Weight=158})</div>

If you write the above and have defined a text “Hello” with the pattern

Hello {UserName}. You have #NewMessage{0: no new messages | 1: one new message | {#} new messages}. You weigh {Weight:N2} kg.

your view would print “Hello Bob. You have 4 new messages. You weigh 158.00 kg.”

In your controllers and other code the easiest way to localize is to import the namespace “Umbraco.Framework.Localization” and use the extension method on string called Localize. This method assumes that the string is a text key, so in code you would write:

var message = "Hello".Localize(this, new {UserName="Bob", NewMessages = 4, Weight=158})

You have to write “this” as the first parameter because texts are “namespaced”, but I’ll cover that in an even later blog post. (Basically, you can embed texts in assemblies and these texts won’t interfere with your other texts even if they have the same key. And you can also override assemblies texts with your own, it’s awesome! But not covered here).

Defining texts
If you’re in an Umbraco 5 project it’s pretty simple. You just define your texts in ~/App_Data/Umbraco/LocalizationEntries.xml and start coding. NOTE: You’ll have to add Namespace=”” to the root tag, so your file should like this:

 <?xml version="1.0" encoding="utf-8" ?>
 <Translations Namespace="">
 <Text Key="Welcome">
 <Translation Language="*">Hello {UserName}.</Translation>
 <Translation Language="da-DK">Hej {UserName}.</Translation>

Note that if a text is missing, the framework will look for a text in the language “*”. This is the “default” language all other languages will fall back to if a text is missing. If your site’s default language is English you should define your English texts with “*”.


If you’re not in an Umbraco 5 project you only have to add this to Application_Start in global.asax.cs:


And then you’re ready to go.

Standalone, the path for LocalizationEntries.xml is ~/App_Config/LocalizationEntries.xml

MVC conventions

The localization framework provides a ModelMetaDataProvider and ModelBinder that automatically binds texts to view model labels and validation messages following the conventions described here.
Assume you have a view model like

public class FooModel
 public string Name {get;set;}
 public int Age{get;set}

If you would like your views to print something other than “Name” and “Age” when you write Html.LabelFor(m=>m.Name) you simply define texts with the keys “FooModel.Name” and “FooModel.Age”.

You can also just define keys called “Name” and “Age”. In that case those would be used for all view models with those properties. Also, if you want to be really specific you can prefix the view model’s class name with its namespace.

The framework consider these keys in this order:

  1. Namespace.ClassName.PropertyName
  2. ClassName.PropertyName
  3. PropertyName

Validation messages
Validation messages are also localized, and opposite .NETs localization with resource strings the messages can use parameters.
You add keys named ClassName.PropertyName.[Name of validation attribute]. (Same patterns as above, so Name.Required will do and including the namespace is more specific)
For instance, if you add a key with the name FooModel.Name.Required and text “This is so required” this will be used if the Name field is left blank.

You can also add general validation texts for all properties by adding keys named “Validation.Required”, “Validation.Range” etc. If you define a text for “Validation.Required” all required fields will show this validation message if you have not defined specific texts for them.

The texts for validation messages can use the special parameter “Value” and all public properties of the validation attribute. For example, for [Range] you can define your text as “{Value} is not between {Minimum} and {Maximum}” and then you have a nice validation message that can easily be translated and state the limits (standard .NET resource texts are not great for that).

Text sources
If you don’t like the XML format or have texts from an external source you can create your own provider that implements ITextSource.
You’ll only have to implement the Get method that returns an IEnumerable of LocalizedText. When creating those you shouldn’t normally bother with more than Key, Language and Pattern. (The rest are “advanced topic material”)
In the demo project (see link at bottom) I have implemented a CSV file source and another one that reads texts from a Google Spreadsheet. If you have your own spreadsheet just click File->Publish and copy the link from the “Get a link to the published data” after you have picked CSV, and insert that link instead of mine. I (think I) have shared my spreadsheet so that you can read it.

Custom languages
The localization framework is not bound to CultureInfos. It is the standard though, so if you don’t specify anything else it will look up the language code from the current CultureInfo (e.g. “en-US”, “ar-SY”, “da-DK” etc.).
If you choose to define custom languages you can define “fallback chains” for languages so, for example, if a Danish text isn’t found a Norwegian one is better than English. You can see a simple example of how to do this in the demo project.

The CultureInfo used for formatting dates and numbers is inferred from the key. This means DO follow .NETs names (“en-US” etc.). You are allowed to add more dashes, so if you need a few texts different for Mac and PC users you can define “en-US-mac” and “en-US-pc”. Both will use “en-US” locale and fall back to “en-US” if no specific text is found. It’s a design choice because it’s easier if you stick with standardized language keys. If you really, really need something else you can subclass LanguageInfo and define your own logic (also “advanced topic”)


I’ve created a small demo solution for the purpose, and it can be found here:
It demonstrates the concepts described in this post.

Happy localizing!


Written by niels.kuhnel

March 11, 2012 at 4:43 am

Posted in Uncategorized