Supporting Localization and Multiple Languages


Applications that support localization usually require some method for storing text strings and other content in multiple languages and formats. The usual approach is through resources stored within the project in the standard .resx file format. In ASP.NET, you can set up a page or an entire Web application for localization by specifying the resources it requires when you build it, and you can reference resources within an application in both declarative and programmatic ways.

ASP.NET has built-in support for identifying cultures, which define the language and other settings required for the localized output. You can declaratively define resource keys for controls, subobjects, and their properties without writing any code, and you can use page-level or application-level resources to localize an application without having to create and compile satellite assemblies. Finally, you can also use the new mechanism to enable inherent extensibility of resources by storing and retrieving resources from a database or in any other custom format.

In this section, you will see an overview of the code-free approach to localization and multiple culture-handling techniques before moving on to see how to use the new expression types, resource types, and attributes to localize a pageagain, without writing any code.

Code-Free Localization

ASP.NET allows you to localize a Web application without writing any code. Microsoft provides built-in localization support within the .NET Framework and Visual Studio 2005. You can localize an application using a combination of implicit and/or explicit expressions as well as page-level and/or application-level resources. The following subsections explain these expression types and resource types with examples.

Using Implicit Expressions and Local Resources

The simplest way to apply localization is through implicit expressions. Visual Studio 2005 greatly simplifies the localization of a page using implicit expressions, page-level or local-level resources, and declarative programming. This gives you an automatic way of applying resources to control properties. Listing 14.22 shows a simple example of this approach with a page that contains a Button, a TextBox, and a Label.

Listing 14.22. A Simple Demonstration of Implicit Expressions

<%@Page Language="C#" %> . . . <asp:Button  runat="server" Text="English Button" /> <asp:TextBox  runat="server" Text="English TextBox" /> <asp:Label  runat="server" Text="English Label" />

You can create this page in Visual Studio 2005, switch to Design view, and click Generate Local Resource on the Tools menu. This writes a resource key into each control and into the Page directive, and adds the Culture and UICulture attributes as shown in Listing 14.23.

Listing 14.23. The Resource Keys Added to the Example Page

<%@Page Language="C" meta:resourceKey="PageResource1"         Culture="auto" UICulture="auto" %> ... <asp:Button  runat="server" Text="English Button"      meta:resourcekey="Button1Resource1" /> <asp:TextBox  runat="server" Text="English TextBox"      meta:resourcekey="TextBox1Resource1" /> <asp:Label  Runat="server" Text="English Label"      meta:resourcekey="Label1Resource1" /> </asp:Label>

The Page directive and every server control now have a resource key indicated by the meta:resourcekey attribute. The combination of this attribute and the resource key is an implicit expression. The Generate Local Resource command performs several functions:

  • It creates an App_LocalResources folder (if one does not already exist) to store page-specific resource files.

  • It creates a culture-neutral resource file in this folder, using the page name with the extension .resx. This file contains the resource values for the keys declared in the page.

You can view the .resx file by double-clicking on it in the Solution Explorer window to open it in the RESX editor, as shown in Figure 14.19.

Figure 14.19. The contents of a culture-neutral resource file


The .resx file contains a resource key and the corresponding value for each control property designated internally in the control as localizable. The Visual Studio designer uses the design-time-only attribute as a pointer for properties inserted into the .resx file. Note that this is not a runtime feature.

Each control can have different properties designated as localizable, although most text-based properties are marked localizable by default. As you can see in Figure 14.19, the Button control properties such as Text and ToolTip are marked as localizable by default. The file also contains a key/value pair for the Page directive, which sets the page title. The RESX editor displays all String-type properties in the Strings category, and all other types (such as Boolean) in the categories available from the dropdown list at the top-left of the Resources Editor window.

You can now create a new resource file that contains resource values in the German culture. Change all occurrences of "English" to "German" in the Value column, and save the file with the .de.resx file extension (the string "de" is the standard abbreviation for German). Visual Studio adds the new file to the App_LocalResources folder and displays it in the Solution Explorer window. You now have two .resx files, one for German and the original one not marked with a language abbreviation. The unmarked file is the default, used for any browser requests that do not explicitly request German. In other words, it is the neutral culture, sometimes referred to as the fallback culture.

The UICulture="auto" attribute added to the page automatically by Visual Studio causes ASP.NET to read the culture information within the HTTP headers sent by the client browser. When accessed from a browser that indicates it is set up for the German culture, ASP.NET displays the German version of the page. You have localized a page without writing any code. At runtime, the ASP.NET compiles the .resx files and adds them to the assembly, and the Resource Manager performs the resource lookups to get the appropriate values. Figure 14.20 shows the result of running this page with the default culture.

Figure 14.20. The result when opening the localized page under the default culture


To see how the culture-specific resources appear, you can set the culture for your browser accordingly. To set the browser culture to German:

  1. In Microsoft Internet Explorer, choose Internet Options from the Tools menu.

  2. In the General tab of the Internet Options dialog, click the Languages button.

  3. Click Add in the Language Preference dialog, and select German (Germany) [de] from the list of languages.

  4. Click OK to close the Add Language dialog.

  5. Back in the Language Preference dialog, select German (Germany) [de] from the list of languages, and then click Move Up.

  6. Click OK to close the Language Preference dialog.

  7. Click OK to close the Internet Options dialog.

Once you set German as the browser culture, ASP.NET will automatically read resource information from the .de.resx file and display the German content (including the page title in the browser title bar), as shown in Figure 14.21. If you change the browser culture to any other language, the page will not find a corresponding .resx file and will revert to the culture-neutral .resx file (the English version).

Figure 14.21. The result when opening the localized page under the German culture


You can support more cultures by creating corresponding .resx files. You can then send these files to agencies or translators, along with a read-only version of the source Web page so that they can see the context for the text. After translation, you simply add the .resx files to the App_Local Resources folder and run the page under various browser settings to verify the localization.

Note

Design view of a localized page always uses the culture-neutral resource file.


Using Explicit Expressions

In the previous section, you saw localization using implicit expressions. Another technique is to take advantage of explicit expressions. Expressions allow you to assign values declaratively to almost any property of a control or an object in a Web page. You can localize a control or an object on a per-property basis using the new expression syntax:

<%$ Resources: [NameSpace,] [ClassName.]ResourceKey %>


Explicit expressions are useful for localizing those properties not marked as localizable. For example, you can use an explicit expression to localize the BackColor property of a button. You must first define a color resource, which must be available in all appropriate resource files, including the culture-neutral resource file.

You should always add any resource key/value pair manually defined in a culture-specific resource file to the culture-neutral resource file as well.


You can edit the resource files in the built-in resource editor, or by right clicking on them and selecting Open with... and then XML Editor. Listing 14.24 shows part of the XML view, with a color resource named Mycolor added to the default and the German .resx files using the data and value elements. The color in the culture-neutral resource file is set to Red, and in the German file it is set to Yellow.

Listing 14.24. Additions to the Resource Files to Support a Color Resource

Default .resx file . . .   <data name="MyColor" xml:space="preserve">     <value>Red</value>   </data> </root> German .resx file . . .   <data name="MyColor" xml:space="preserve">     <value>Yellow</value>   </data> </root>

Note that MyColor is of type System.String. ASP.NET automatically converts the string value to the destination type, as required. You can now use these resource files to change a color property of any control, depending on the current culture. In Visual Studio 2005, you can apply this resource using the Expressions dialog box shown in Figure 14.22. Open the Expressions dialog by clicking the Expand (...) button in the Expressions box in the Properties window for Button1. A pink-colored icon in the Properties window indicates localized properties.

Figure 14.22. Setting the BackColor property using the Expressions dialog


Clicking OK in the Expressions dialog creates an explicit expression that assigns the resource to the property you are editing:

<asp:Button  runat="server"      BackColor="<%$ Resources: MyColor %>"      Text="English Button"      meta:resourceKey="Button1Resource1" />


This expression indicates that the BackColor property will use the MyColor resource. ASP.NET selects the exact value of the resource at runtime, depending on the culture setting of the user's browser. It converts the resource value to a value of type System.Drawing.Color as required by the property of the control.

As with implicit expressions, you can use explicit expressions without writing any code. Figure 14.23 displays the result under German culture after setting the BackColor property for the TextBox and Label.

Figure 14.23. The results in the German culture when using an explicit expression


Of course, you can type the explicit expression directly into the control declaration in Source view instead of using the Expressions dialog box. Expressions are not case sensitive.

Using Global Application Resources

Local resources are great for storing unique resource keys for individual Web pages. However, shared resources are best stored as global application resources. All application-level resources are stored in an App_Global Resources folder at the Web application level. You can then use them by specifying the namespace and/or class name within the explicit expression syntax.

For example, you can use a shared resource called MySharedKey from the files named MyResources.aspx and MyResources.de.aspx (in a page that has culture resources defined) to set the Text property of a Label like this:

<asp:Label  runat="server"      BackColor="<%$ Resources: MyColor%>"      Text="<%$ Resources: MyResources, MySharedKey %>"      meta:resourceKey="Label1Resource1" />


In this example, the Text property is set using an explicit expression. However, the expression uses an expanded syntax that includes the name of the resource file (MyResources), and the resource (MySharedKey). By using this expanded syntax, you can point a property to resources in an application resource file, which in turn allows you to access the same resource file from multiple pages.

You can use both implicit and explicit expressions together, as shown in the example just presented. In such cases, implicit expressions have higher precedence over explicit expressions. In other words, the .NET Framework will use the value of Label1Resource1.Text instead of MySharedKey to set the Text property.

To illustrate this, in the example code just presented, the text in the title bar and the Tooltip property of the label will use the local resource file, because this is where the meta:resourceKey attributes point. The BackColor property will use the MyColor resource from the local resource file, and the Text property will use the MySharedKey value in the application-level resource file named MyResources. You can create as many culture-specific application resource files as you need, and (as you will see later) access both page-level and application-level resources programmatically.

Localizing Static Content

ASP.NET also supports localization of static text markup. This is simply a matter of enclosing the static content within an <asp:Localize> element:

<asp:Localize runat="server">This will be localized</asp:Localize> While this will not.


After enclosing the text that you wish to localize in the <asp:Localize> element, you use the Generate Local Resource command in Visual Studio. It creates a resource key for the <asp:Localize> element, encodes the text enclosed by the <asp:Localize> element, and stores the result as the value for the resource key in the culture-neutral resource file for the page.

You can work with the <asp:Localize> element only in Source view. This element can contain only static content, and not ASP.NET Web Controls. ASP.NET treats all content as static and pushes it into the resource file as it appears in the source of the page, so ASP.NET will not execute any server controls the <asp:Localize> element contains at runtime.


Figure 14.24 shows an example page that uses both local (page-level) and global (application-level) resources, and displays the culture name as well. You can get the culture name from the current thread using:

String culture = Thread.CurrentThread.CurrentUICulture.ToString();


Figure 14.24. Localizing static content using local and global resources


Note that you must import the System.Threading namespace into your code file to be able to access the Thread class. In C#, you add this statement to your file:

using System.Threading;


Exempting Controls from Localization

If you do not want to localize a control or Page directive, you can set the meta:localize attribute to false:

<asp:Button  Runat="server"             Text="Don't Localize Me!"             meta:localize="false" />


The button will display the default text "Don't Localize Me!" for all cultures. When you use the Generate Local Resource command, no resource key is generated for controls with the meta:localize attribute set to false.

Hiding Controls at Runtime

In some cases, instead of localizing the properties of a control, you might simply want to hide the control altogether for some cultures. For example, perhaps your Web page contains a graphic that you want to show for some cultures but not for others. To hide a control under a specific culture, you add a resource value for the control's Visible property and set it to false. In the first example, if you want to hide the text box for the German culture, you would add the key TextBox1Resource1.Visible with the value false to the .de.resx file. At runtime, ASP.NET will not include the TextBox control in the output for German culture requests, but will display it for all other cultures.

What Expression Type to Use, and When?

In general, you should use implicit expressions to localize a control or object. The shortened notation allows you to declare the resource key at the control level, instead of having to define an expression for each property of the control. However, you can only use implicit expressions with local resources, meaning that you must have a set of .resx files for each page.

If you are using shared (application-level) resources, you must use explicit expressions to localize a property of a control or object. You can use either expression type with the Page directive, and you can use both implicit and explicit expressions for the same control, as you saw earlier. Such a combination might be useful for properties not localized by default. Table 14.1 shows how the different expression types behave with different resource types.

Table 14.1. Using the Different Expression and Resource Types
 

Can Refer to Local Resources?

Can Refer to Global (Application) Resources?

Implicit expressions

Yes

No

Explicit expressions

Yes

Yes


User-Selectable Localization

There may be times when you prefer your users to be able to select the locale for which they will view the site. Typical implementations have a page showing flags for the languages supported, and selecting the appropriate flag sets the culture. In ASP.NET, you can accomplish this by storing the selected culture as a property of the profile for each user (Chapter 12 describes the profile feature in ASP.NET).

Setting the culture as each page loads, or in a Master Page, is not possible. However, there is a solution: using one of the application events in Global.asax. Consider Listing 14.25, where the CurrentCulture and CurrentUICulture for the CurrentThread are set to a culture stored in the UserCulture property of the user's profile. If no profile is stored, the code sets a default value.

Listing 14.25. Setting Localization Using Code in Global.asax

<%@Application Language="C#" %> <%@Import Namespace="System.Globalization" %> <%@Import Namespace="System.Threading" %> <script runat="server">   protected void Application_PostAcquireRequestState(                              object sender, EventArgs e)   {     CultureInfo ci = null;     if (Profile.UserCulture != String.Empty)     {       ci = new CultureInfo(Profile.UserCulture);     }     else     {       ci = new CultureInfo("en-gb");     }     Thread.CurrentThread.CurrentCulture = ci;     Thread.CurrentThread.CurrentUICulture = ci;   } </script>

However, there is a problem in that the culture is set before the page loads, and so any user interaction to change the culture setting will not take effect until the page reloads or the user loads a different page. One way that you can get around this is by adding the culture to the query string of a hyperlink, as shown in Listing 14.26.

Listing 14.26. The Flag Icons and Links to Select the Required Language

<asp:Hyperlink  runat="server"      ImageUrl="images/en-us.gif" ToolTip="US Culture"      NavigateUrl="localize-select.aspx?culture=en-us" /> <asp:Hyperlink  runat="server"      ImageUrl="images/de-de.gif" ToolTip="German Culture"      NavigateUrl="localize-select.aspx?culture=de-de" /> <asp:Hyperlink  runat="server"      NavigateUrl="localize-select.aspx"      Text="<%$ Resources: Hyperlink3.Text1 %>" />

Then, in the Page_Load event handler or in the event handler of a control that causes a postback with the new culture value, you can check if the user selected a language different from that in the user's current profile setting. If so, you can update the profilemaking sure you do not attempt to set the String value it contains to nulland then reload the page using the Response.Redirect method (see Listing 14.27). This code also displays the current culture setting.

Listing 14.27. Setting the Profile Property Value and Reloading the Page

protected void Page_Load() {   String query = Request.QueryString["culture"];   if (query == null)   {     query = String.Empty;   }   if (Profile.UserCulture != query)   {     // set profile value     Profile.UserCulture = query;     // reload page to pick up new culture     Response.Redirect(Request.Url.ToString(), true);   }   lblCulture.Text = Thread.CurrentThread.CurrentUICulture.ToString(); }

An alternative approach, if you enable personalization for your site, is to set the culture using an HTTP module that executes before the page Load event occurs. This approach was used in Chapter 12 to set the theme for a page by extracting the user's selection from his or her current profile. As demonstrated in that chapter, in the section Using an HTTP Module to Set the Theme, you create a class that implements the IHttpModule interface and then add it to your web.config file so that ASP.NET executes it as part of the request process. In the module, you extract the selected culture from the profile and apply it to the page.

Figure 14.25 and Figure 14.26 show the example page, first with the US-English culture selected and then with the German culture selected.

Figure 14.25. Selecting the US-English culture in the example page


Figure 14.26. Selecting the German culture in the example page


Programmatic Access to Resources

Resources are not strongly typed, but you can access them programmatically through the Resource Manager or the methods named GetPageResourceObject and GetGlobalResourceObject. Listing 14.28 shows a simple example. Notice how you must create instances of the correct types before assigning them to the control properties, including a System.Drawing.Color instance to set the BackColor of the Button control.

Extensibility

Sources for resource keys and their values are not limited to the file-based .resx format. You can use the rich extensibility mechanism of ASP.NET to store and retrieve the resource keys and their values from a database or any custom file format. Using a database makes it easier to centralize the resources for the application across many servers in a Web farm and to ensure central consistency.

Listing 14.28. Accessing Local and Application-Level Resources Programmatically

protected void Page_Load(object sender, EventArgs e) {   Page.Title = GetLocalResourceObject("PageTitle").ToString();   Button1.Text = GetLocalResourceObject("MyButtonText").ToString();   String clrName = GetGlobalResourceObject("MyResources",                                            "MyColor").ToString();   Color clr = Color.FromName(clrName);   Button1.BackColor = clr;   TextBox1.Text = GetGlobalResourceObject(                   "MyResources", "MyTextBoxText").ToString(); }

Both the .NET Framework and Visual Studio 2005 support extensibility. You can read and write resource values from a custom source using the ResourceProviderFactory and DesignTimeResourceProviderFactory classes. For more details, see http://msdn2.microsoft.com/en-us/library/9b1d2yze.aspx and http://msdn2.microsoft.com/en-us/library/system.web.ui.design.designtimeresourceproviderfactory.aspx.

Web Resources

Along with their assemblies, control developers often have to supply additional static files such as stylesheets and images. With the new resources model in ASP.NET, you can embed these static files as resources within assemblies. You simply use the WebResource attribute from the System.Web.UI namespace, as shown in Listing 14.29.

Listing 14.29. Storing an Image As a Resource Within an Assembly

[assembly: WebResource("MyImage.gif", "image/gif")] namespace MyDemoControls {   public class MyImageControl : WebControl   {     // over-ride creation of child controls     protected override void CreateChildControls()     {       // create new Image element and set ImageUrl       Image img = new Image();       img.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(                           typeof(MyWebControl), "MyImage.gif");       Controls.Add(img);     }   } }

At compile time, you embed the resource into the assembly using:

csc /t:library /out:MyImageControl.dll     /r:System.dll,System.web.dll     /res:MyImage.gif,MyImage.gif     MyImageControl.cs


The Web resources feature is not limited to just images. For example, to embed JavaScript for client-side support, you could add:

[assembly:WebResource("MyScript.js", "text/javascript", true)] public class MyControl {   // control code here }


The third parameter of this attribute indicates that ASP.NET should invoke the Web resource parser for this resource (which is not the default behavior). This ensures that the embedded resource will be valid when used by the client. ASP.NET pages, and controls such as the treeView, use this technique to provide the images and JavaScript they require. You can also access embedded Web resources directly from within ASP.NET pages in code, like this:

img1.Image = Page.ClientScript.GetWebResourceUrl(                       Type.GetType("MyControl"), "MyImage.gif")


We are grateful to Dietrich Birngruber for the assistance in the German translations used in this chapter.




ASP. NET 2.0 Illustrated
ASP.NET 2.0 Illustrated
ISBN: 0321418344
EAN: 2147483647
Year: 2006
Pages: 147

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net