Skip to content
perpetualKid edited this page May 3, 2021 · 1 revision

Localizable Enum Descriptions

Often there are scenarios where enums should provide additional textual information, ideally even localized for different languages.

[Description("Time of the year")]
public enum Season
{
    [Description("Spring Season")]
    Spring,
    [Description("Summer Season")]
    Summer,
    [Description("Autumn Season")]
    Autumn,
    [Description("Winter Season")]
    Winter
}

There is no magic in the ICatalog interface specifically for enums and description, but with some support through GetText.NET Extractor it is easily possible to support translation for such scenarios.

The Extractor is designed to extract enum description attributes. These attributes need to be of type DescriptionAttribute from System.ComponentModel namespace, and will be exported to catalog template (*.pot) just as other localizable string constant.

msgid "Spring Season"
msgstr ""

msgid "Summer Season"
msgstr ""

...

When using an Description attribute for the enum type itself, this text will be used for message context in the GetText template

[Description("Time of the year")]
public enum Season
{

...
msgctxt "Time of the year"
msgid "Spring Season"
msgstr ""

msgctxt "Time of the year"
msgid "Summer Season"
msgstr ""

...

Localizing enums

With catalogs localized now, translated enum descriptions will be used at runtime using common Catalog.GetString* funtionality:

public class EnumDemo
{
    // mapping enum values to their original (un-translated) descriptions
    private readonly Dictionary<Languages, string> valueToDescriptionMap = new Dictionary<Languages, string>();
    // the enum type description 
    private readonly string enumDescription;

    private ICatalog catalog;

    public EnumDemo()
    {
        catalog = new Catalog("messages");

        // Getting the enum type description attribute to be used for message context 
        enumDescription = typeof(Season).GetCustomAttributes(typeof(DescriptionAttribute), false).
            Cast<DescriptionAttribute>().
            Select(x => x.Description).
            FirstOrDefault();
        
        // Mapping all original enum descriptions to their enum value 
        foreach (Season value in ((Season[])Enum.GetValues(typeof(Season))))
        {
            FieldInfo field = typeof(Season).GetField(value.ToString());
            valueToDescriptionMap[value] = field.GetCustomAttributes(typeof(DescriptionAttribute), false)
                        .Cast<DescriptionAttribute>()
                        .Select(x => x.Description)
                        .FirstOrDefault();
        }
    }

    public string TranslatedEnumDemo(Season season)
    {
        // lookup translation from original description for the particular enum value (season),
        // using the particular context (enumDescription)
        return catalog.GetParticularString(enumDescription, valueToDescriptionMap[season]);
    }
}

Using CatalogManager<T>

When enums types are defined in different assemblys and multiple catalogs are used, CatalogManager adds dedicated support for this use case by using CatalogManager<T> where T: Enum to refer to the corresponding catalog.

    public string TranslatedEnumDemo(Season season)
    {
        // lookup translation from original description for the particular enum value (season),
        // using the particular context (enumDescription)
        return CatalogManager<Season>.Catalog.GetParticularString(enumDescription, valueToDescriptionMap[season]);
    }

If frequently used across a solution, it is recommended to encapsulate some of the enum handling such as attribute resolving (valueToDescriptionMap in the sample above) into separate helper functionality.