Implementing a multilingual web application is something I see as crucial, in order to address a larger crowd of people. In ASP.NET Web Forms, this was very easy to accomplish using the ‘$’ or meta:resourceKey, and the code behind relevant methods. In ASP.NET MVC I’m uncertain if this is inherently supported so I was searching for a way how to accomplish this. Global resources behave the same: ASP.NET infrastructure auto-generates a Resource class which can be used in exactly the same manner as in Web Forms. For example, if I have a GlobalResources.resx file, a GlobalResources class will be auto-generated containing static properties, which can be used as follows:
Local resources, however, are not auto-generated classes. Looking around the web I came across an interesting post on how to use Local Resources using an extension method. This was great, but I was looking for some implementation that will: 1) Use a single “resource key” as an argument, and 2) Will be “context aware”, so that if the context is a layout (“Master page”), it’ll use local layout resources, and if the context is a page, it’ll use local page resources. After performing some experiments and debugging, I learned two interesting things using the excellent .NET Reflector (see pic below):
- Layouts and Pages are both considered as “pages” as they inherit from “WebViewPage”, making them both “pages” (Web Form’s MasterPage does not inherit from Page class, but from UserControl).
- Despite that, layouts seem to be compiled to a different assembly than pages.
Line 3 performs the two relevant things:
- Using the WebViewPage base class we have access to the ViewContext->HttpContext->GetLocalResourceObject, which is what retrieves the resource.
- the page.VirtualPath is what “differentiates” the Layout from the Page “resource context wise” . So when we’re in layout context, this will return the layout’s path. When in page context, this will return the page’s path. This is what ASP.NET needs in order to return the correct resource file.
Lines 4-7 are not really essential. They simply help in pointing out resource keys which do not exist in the resource file yet. This can also be logged to a log file.
The resulting code:
Line 1 demonstrates a GlobalResource usage.
Line 2 shows the Local Resources implementation.