C# – How to format part of a resource

asp.net-mvccresources

Suppose you're building a web application in ASP.NET MVC, and you have to display some formatted text. A very simple example might be:

Click any of the links below, or click here to cancel. Contact Customer Service with any questions.

What do you store in the resource file, and what do you code inline in your view?

For example, do you hardcode the target of the link in the resource? Or do you put {0} and populate it with string.Format in the View? Or store the link text as a separate resource and put the markup in the View, including the target?

What if the instructions are long, and need to be displayed in a tabular format? Do you put the <TABLE> <TR> and <TD> tags into the resource? Or do you have to put those tags in your View and create resources for each cell?

If you put HTML markup in some of your resources, you have to dodge the automatic HTML-escape mechanism employed by Razor (e.g. use Html.Raw). How do you remember which resources can be inserted directly and which need to be unescaped? Do you keep formatted resources in a separate resource file? Use a naming convention? Cross your fingers?

Bottom line: How do you deal with the common requirement of formatting part of a resource?

Best Answer

In ASP.NET MVC, HTML content belongs to the view, and localized strings belong to resource files.

The difficulty is what happens when you need to mix both, i.e. when you need to have localized HTML content. There are several alternatives:

  • Put HTML in resource files. This is the worst solution, which should be avoided unless you have very good reasons not to. The issue is not only that it makes it overly complex to handle HTML which should be output as is with Html.Raw and user content which should be properly escaped, but also the complete lack of support from the IDE: with resources, you won't even have syntax highlighting.

    It also means that you're making it impossible to insert any dynamic content in HTML stored in resources. In worst cases if you're in a team of programmers who don't know well what they are doing, someone will end up reinventing the wheel by creating a system of placeholders to insert dynamic content in HTML from resources.

  • Put localized HTML content in views, one view per culture.

    The benefit of this approach is that each individual view would be easy to read and maintain, with the source being quite close to the result you'll see in the browser.

    The drawback, however, is that the same markup change has to be made in every localized view. If you need to support, say, six languages, every change has to be replicated six times.

  • Put HTML without translated content in a view, and call the corresponding localized resource strings from the view.

    The benefit of this approach is that you specify the markup only once.

    However, any content change would be cumbersome; for instance, in order to add a paragraph with one word in italic, you'll have to create three additional resource strings, create their translations and use them in the new markup.

    A more subtle issue is the same as for any resources-based approach: localization is not just about filling the placeholders. Sometimes you have to change the entire sentence; sometimes, you have to change the order of content (say [Cancel] the previous action would require a placeholder before the cancel button in some languages, such as, if I'm not mistaken, German); sometimes, you have to use a different color, or a different set of icons. Something as basic as putting ¿...? in Spanish versus ...? in English can be overly complex when you mix markup, dynamic content and placeholders, and I'm not even mentioning all the grammar subtleties.¹

    Therefore, localized views seem to me to be a more flexible solution, which, in long term, would require less maintenance. The exception would be a situation where you need to support a huge number of languages (twenty or more) in a context where nobody really cares about subtle adaptations of content to different cultures.


¹ One example I enjoy a lot is the request I received once for a web app which had to support a dozen of languages. On a page, there was a counter of products which was written as “6 products.” Things went well with some numbers, but not with others: “1 products” was not particularly correct in terms of English grammar. Therefore, the product owner asked if it would be possible to display a proper variant when needed. As I gave an estimate of how long would it take, the PO looked at me as if I was crazy: “Why, you need that much time for just adding a ‘product’ version and displaying it if the number is equal to one?! It should be one line of code!” So I started to explain that the if n == 1 rule may be true in English, but certainly not in languages such as Russian, where there will be one form for any number which ends by one, unless it ends by eleven, another form for numbers ending by 2, 3 or 4 but not by 12, 13 and 14, and a third form for anything else. More cultures to support means more rules to introduce, which are far more complex than adding a resource string.


Original answer:

It is unfortunate that you can't use ASP.NET MVC instead (especially in a context of an MVC web app!) In ASP.NET MVC, there is a mechanism specifically for that, called partial views. Instead of having to handle resource files (which has numerous drawbacks, including but not limited to the lack of proper editor with syntax highlighting and the contrived diffs in version control), you are simply putting the HTML content where it belongs—in the view—and then include it in other pages.

In ASP.NET, a similar mechanism could be a user control that you later include using RenderPartial. User controls give you the ability to pass parameters to them, making it possible, in your case, to pass the URI. Then you simply inject the value in HTML.

Both partial views and user controls give you an additional advantage of being able to add both markup and logic later with a relative ease—something you won't get with resource strings.

So:

  • Keep HTML where it belongs, that is in the view.
  • Use resources for their primary purpose: storing localized strings.