post icon

Enums with localization the Lazy Way

So, I worked for a while in a codebase that has a ton of enums, they’re used to categorize a lot of data and to help define and apply a lot of  business rules. This might come as a surprise but, you’re not the only one that has wondered which is the best way to deal with enums, to localize them and display them easily on your presentation layers. In the project I mention we came up with a solution that involved storing enum values, names and descriptions for the UI in a table and we just queried that table when we needed to deal with the enums on the frontend.

That approach served us well, it’s probably a common thing to do, but a couple of weeks ago starting a new project and faced with the dilema again I found that now most things seemed rather wrong with the solution:

  1. For every use of a form with an enum we needed to query the database, and mind you there were a lot of enums and a lot of round trips to the database. So we had to implement a caching mechanism on our services for this (throwing more code to a problem anyone?).
  2. If the source had to be compiled again for enum changes, why would we keep their presentation data in a changeable and expensive to consult environment like the database, this seems overkill.
  3. Special care (A.K.A more code, A.K.A post it notes everywhere) had to be given to keeping the database and code representations of enums synched (yes, we gave a towel to each team member).
  4. We didn’t do almost any reporting on this application, it was pure operations, just a handful of reports here an there none with enums involved, then why the table at all?.

So I decided to use some T4 templates, reflection and xml to solve this problem in the new project. The solution in a nutshell is an xml file defining the enums, all the cultures that the application will support and just generate both the code and the resources of off the Xml, here it is.

The Xml File

The file defines among other things, the namespace for the code generation, the relative path to the project root where resources are to be saved, all the cultures a resource will be generated for and all enums.

<enums namespace="DevDo.LazyEnums">
  <resources relativePath="Resources" filename="Enums">
    <culture code=""/> <!-- NEUTRAL CULTURE-->
    <culture code="es"/>
    <culture code="de"/>
  </resources>
  <enum name="DaysOfWeek" summary="Exposes all days of the week.">
    <item name="Sunday" value="0" summary="Sunday" />
    <item name="Monday" value="1" summary="Monday" />
    <item name="Tuesday" value="2" summary="Tuesday" />
    <item name="Wednesday" value="3" summary="Wednesday" />
    <item name="Thursday" value="4" summary="Thursday" />
    <item name="Friday" value="5" summary="Friday" />
    <item name="Saturday" value="6" summary="Saturday" />
  </enum>
</enums>

The T4 Template

T4 template classes.

Classes on T4 template.

The three classes above are defined in the T4 template and used to load the xml definition file. The template loads the Xml file and outputs all enum types defined in it. It then creates a resource file for each culture specified using the following format: Enum.{culture}.resx. It verifies on creation that the entries to be added don’t exist, if they do, they’re left with their current values, if on the other hand there are entries in the resx file that aren’t defined in their corresponding enum, these are removed. Also all descriptions in the resource files are set by default to: “Resource value for enum item ({enum_value_name}) in Culture ({culture_name}) NOT SET.”

Usage and Syntactic sugar

  • To enable access to the description of an enum, an extension method Text() was created, which gets the description from the resource files depending on the UI Culture of the running app.
  • Also there’s a class for binding to combos/lists and that sort of Text-Value binding control. It’s called TextValueItem it has a method called GetAllForEnum<TEnum>() which returns a List<TextValueItem> with all possible values of the enum.

Here’s a few usage samples:


            //1 - Get text for enum with neutral culture
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            Console.WriteLine("I wish today was {0}.", DaysOfWeek.Wednesday.Text());

            //2 - Get text for enum in other culture (spanish).
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            Console.Write("{0} in spanish is ", DaysOfWeek.Wednesday.Text());

            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
            Console.WriteLine(DaysOfWeek.Wednesday.Text()+"\n");

            //3 - Get all possible enum descriptions as a TextValueItem list in spanish.
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
            Console.WriteLine(TextValueItem.GetAllForEnum<DaysOfWeek>().JoinDescriptions(", "));

            //4 - Get the text for enum that doesn't have a resource value set (de - German).
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            Console.Write("{0} in german is ", DaysOfWeek.Wednesday.Text());
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de");
            Console.WriteLine(DaysOfWeek.Wednesday.Text());

The Output is:

1) I wish today was Wednesday.
2) Wednesday in spanish is Miércoles
3) Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado
4) Wednesday in german is Resource value for enum item (Wednesday) in Culture(de) NOT SET.

Here’s the Code, give it a try and let me know if it helps you out.


Download VS2008 Project

No related posts.

Read full story »

No comments yet.

Leave a comment