Practical ASP.NET
Supporting Multiple Languages and Cultures (Part 2)
Peter Vogel dives deeper into the challenge of presenting ASP.NET Web pages in multiple languages and cultures.
To fully support multiple languages and cultures in an ASP.NET site, you'll need use global resources and write some code to access the special features that ASP.NET provides for internationalization.
In last week's column (Supporting Multiple Languages and Cultures), I discussed ASP.NET's base support for internationalization and localization. This week I'm going to discuss some more interesting problems.
One issue that I raised last week was handling those scenarios where the user wanted pages displayed using a different language or culture than is specified in the browser. To support this you need to set up a table to hold the user's preferences (or just use the ASP.NET Profile object) to hold the language or culture that the user wants.
Once you've set up a place to store the user's preference you just need to set the Page's UICulture property to the user's preferred language/culture setting. Assuming that you have a resource file created for that language and/or culture, the page will automatically display the right values. The appropriate way to do this is to override the Page’s InitializeCulture method. This example sets the page to use Spanish language for the Mexican culture:
Protected Overrides Sub InitializeCulture()
Me.UICulture = "es-MX"
MyBase.InitializeCulture()
End Sub
Setting the UICulture property in the InitializeCulture method doesn't require that you set the Page's UICulture property to Auto.
Shared Resources
However, this change still only supports translating the content of a single page. Many applications will have message or other text that needs to be shared across multiple pages. You can add these resources to a global resource file that can be accessed from multiple pages.
To add a global resource file, do the following:
- Select the Web site in Solution Explorer
- Right-mouse click and select Add ASP.NET Folder | App_GlobalResources
- Right-mouse click on the new folder and Select Add New Item | Resource File
When the file is first created it will be named filename.resx. As described in last week's column, you'll need to rename the file to indicate the language/culture it contains (e.g. rename the file to filename.es-MX.resx if the file holds "Spanish for Mexico" resources).
Once you've created the file you can add name/value pairs to it where the value is the text that you want to use. For instance, I might create a name/value pair in my en-US ("English for the USA") resource file with a name (or "ResourceId) of "Warning" and a value of "Don't touch"; In my es-MX resource file, I would have the same name but the value would "No toque".
To get your controls to use a value in a global resource file, you can bind the value to a property in the page by specifying the file to use and the ResourceId to select from the file. This example binds the Text property of a Label to a file called WarningMessages and pulls out the value associated with the ResourceId "TouchWarning":
‹asp:Label ID="lblWarning" runat="server"
Text="‹%$ Resources:WarningMessages,TouchWarning %›"›‹/asp:Label›
Once again, ASP.NET will use the correct resource file based on the browser's settings (provided you've set the Document's UICulture property to Auto) or any overrides you've put in the InitializeCulture method.
While binding a property in the aspx file will handle text common to many pages that never change, it won't handle a label that displays error messages that change dynamically. To handle that you'll need to stop returning text error messages to your user interface. Instead, you should return names for items in either your local or global resource files. For global resource files, you can then use the .NET GetGlobalResourceObject to retrieve a value by passing the name of the ResourceFile and the value's ResourceId.
This example sets the Text property of a label from a resource file called ErrorMessages, passing the value in the variable ErrorId as the ResourceId to retrieve:
Me.lblError.Text = GetGlobalResourceObject("ErrorMessages", ErrorId).ToString
Again, ASP.NET will load the right resource file based on the browser's settings (with UICulture set to Auto) or values set in the InitializeCulture method.
Obviously, I haven't covered everything here (I've ignored displaying dates, numbers and currencies, for instance). For those you can use the standard .NET classes (e.g. passing the CurrentUICulture property on the CurrentThread Object to the ToString method of a Date object).
Notice that at no point are you obliged to compile your resource files into DLLs, though you certainly can. Here is a good discussion of ASP.NET support for internationalization and localization, which includes instructions on how to create resource DLLs. As the author points out, that feature is really only there for developers distributing custom controls and WebParts.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.