Many websites have text on them which is not classified as content. These are pieces of text that might be used throughout the site, not just in one place. For example, the place holders on form fields or the text of a button. In a normal ASP.NET project you might use App_GlobalResources to store these values.
At Building Blocks this is often the way we approach string resources in our multi-lingual ASP.NET web applications. When the applications need SDL Tridion to publish these resources we generally store the Labels in a Component which is then assigned as Publication Metadata and Published as a Labels.resx file using a custom TBB.
To allow editors a nice interface to create the labels, we use a "System" schema called Labels. This is a schema with a single Embeddable Schema field with an XML name of "label" which allows a similar editing experience to the String Resources editor in Visual Studio.
As you may know, DD4T is an ASP.NET MVC application. There's a few ways to approach Labels in MVC and using App_GlobalResources which can be published to the file system is one way.
One thing I don't like about using App_GlobalResources is that the application dies completely if a label is missing. This can cause problems on implementations where there are lots of sites and the Labels Component has been localised.
This can make deployments painful if you forget to publish the labels or add a label to one of the localised copies. This can really hold up UAT while the translation happens and can make the application appear broken since this is a runtime error. Because of the above this also often adds communication overheads to the development by having to provide the content editors with lists of all the labels ahead of time which then need to be reimported.
I thought I would try something a little different on this project and use the IResourceProvider interface instead to allow me to output the text "Missing label with key: LabelName" when a label was missing. I used the same Schema as in the example Component above, but instead of a Page Template I created a normal DD4T Component Template and set it to Publish as a Dynamic Component Presentation. At the moment the editor publishes the Labels Component rather than a Page within App_GlobalResources.
Here is the IResourceProvider implementation along with the DD4TResourceProviderFactory and CustomResourceReader implemetations (these are very simple). The code for these was adapted from MSDN.
[gist id=4651524 file=DD4TResourceProvider.cs]
(Can't see the code? https://gist.github.com/rsleggett/4651524#file-dd4tresourceprovider-cs)
There isn't much DD4T code here because it's wrapped in a static class it's pretty generic. As you can see from the GetObject method. The code will output a message if the resource is not found. Notice the use of caching, so you'll also need to have the implementation of the ICacheWrapper interface shown later in the post.
Here's the DD4T bit:
[gist id=4651524 file=DD4TResourceHelper.cs]
(Can't see the code? https://gist.github.com/rsleggett/4651524#file-dd4tresourcehelper-cs)
What's happening is we're looking up the Labels Component by Schema (the code assumes there is just one per Publication, which is something we'll come back to at the end of the post) and then loading a Dictionary with the keys and values.
Then all we need is some HtmlHelper extension methods to use these in our views:
[gist id=4651524 file=ResourceHelperExtensionMethods.cs]
(Can't see the code? https://gist.github.com/rsleggett/4651524#file-resourcehelperextensionmethods-cs)
Now we could use this in our views like:
In this code we're using some additional caching over and above DD4T's internal caching. Here's the code for the ICacheWrapper implementation which we use in application code.
[gist id=4651524 file=ICacheWrapper.cs]
[gist id=4651524 file=WebCacheWrapper.cs]
There are a lot of improvements to be made to this approach and the code. Some things to think about (not necessarily DD4T specific).
- Is one Labels Component a good idea? Could you use one for each area of functionality or section of the site or group by type (e.g. buttons) perhaps? How would the above code need to change to accommodate that?
- Do you think an editor would understand a Page or a Dynamic Component Presentation better for Labels?
- Could the Labels Component be automatically published whenever a Page was published using the Event System?
If you have any feedback, please add a comment at the bottom of the post.