Localizability in Visual Studio 2005


The localization story in Visual Studio 2005 is significantly more advanced than in Visual Studio 2003. To see this in action, create a new ASP.NET Web site and add a table, two labels (User Name and Password), two TextBoxes, and a Button (Login) so that the resulting page looks like Figure 5.4.

Figure 5.4. Example ASP.NET 2.0 Web Form before Localization


Make a note of the page directive:

 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> and also the script for the table:- <table>     <tr>         <td style="width: 100px">             <asp:Label  runat="server"             Text="User name"></asp:Label></td>         <td style="width: 100px">             <asp:TextBox  runat="server">             </asp:TextBox></td>     </tr>     <tr>         <td style="width: 100px">             <asp:Label  runat="server"             Text="Password"></asp:Label></td>         <td style="width: 100px">             <asp:TextBox  runat="server">             </asp:TextBox></td>     </tr>     <tr>         <td colspan="2" style="width: 100px">             <asp:Button  runat="server"             Text="Login" Width="264px" /></td>     </tr> </table> 


Notice that the text is hard-coded and, therefore, not localizable. To make this Web form localizable, select the Design view and then select Tools, Generate Local Resource. The output window displays a couple progress messages:

 Start creating resource content and adding 'meta:' attributes to server controls and directives. Finished creating resource content and adding 'meta:' attributes. 


The Generate Local Resources option performs the following steps:

1.

It adds a local resource file.

2.

It modifies the page source.

We start by looking at the resource file. If the App_LocalResources folder does not already exist, it is created. Into this folder, a resx resource file is added in which the name is the same as the page name, but with an additional "resx" extension. So if the page is Default.aspx, the resource file is called Default.aspx.resx. For each property of each control where the property is marked with the Localizable(true) attribute, a new entry is added to the resource. The entry key is the name of the control plus "Resource1." plus the name of the property (e.g., "Button1Resource1.Text"). The entry value is the value of the property at the time the Generate Local Resources menu item was invoked. Figure 5.5 shows the contents of the resx file in Visual Studio 2005's Resource Editor. We can see from this part of the process that all the localizable values have been copied from the source into a resource.

Figure 5.5. Resource Editor Showing Resources Generated by Generate Local Resources


The Generate Local Resources process is dependent upon properties being marked with the Localizable(true) attribute. The Localizable attribute is used throughout WebControls, but it is used considerably less freely in HtmlControls. Of all of the Html-Controls, only HtmlAnchor, HtmlImage, HtmlInputImage, and Html Title have any properties marked with Localizable(true). For this reason, the majority of HtmlControls will not be included in the localization process by Generate Local Resources. You should change these controls to their WebControls equivalents.


The WebControls Label.Text and Literal.Text properties are marked as localizable in Visual Studio 2005, so static text placed in these controls is easily localizable.


The next change that Generate Local Resources makes is to modify the page source to reference the newly created resources. The first line that is modified is the page directive:

 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Culture="auto" meta:resourcekey="PageResource1" UICulture="auto" %> 


You can see that three attributes (Culture, meta:resourceKey, and UICulture) have been added. We return to the Culture and UICulture attributes later. The meta:resourceKey attribute is the code part of an implicit expression. An implicit expression is the combination of the resources we have already seen and this key. The meta:resourceKey attribute specifies the name that is used to identify the resources from which the control's properties are loaded. So the Page's Title is loaded using the PageResource1.Title key. Generate Local Resources also adds a meta:resourceKey attribute to each of the controls for which resources were extracted:

 <table>     <tr>         <td style="width: 100px">             <asp:Label  runat="server"             Text="User Name"             meta:resourcekey="Label1Resource1">             </asp:Label></td>         <td style="width: 100px">             <asp:TextBox  runat="server"             meta:resourcekey="TextBox1Resource1">             </asp:TextBox></td>     </tr>     <tr>         <td style="width: 100px">             <asp:Label  runat="server"             Text="Password"             meta:resourcekey="Label2Resource1">             </asp:Label></td>         <td style="width: 100px">             <asp:TextBox  runat="server"             meta:resourcekey="TextBox2Resource1">             </asp:TextBox></td>     </tr>     <tr>         <td colspan="2" style="width: 100px">             <asp:Button  runat="server"             Text="Login" Width="264px"             meta:resourcekey="Button1Resource1" /></td>     </tr> </table> 


Notice that the original Text attributes (and any other attributes for which a resource was extracted) remain in the source with their original value. At runtime, these values are no longer used. Their only benefit lies in providing a value at design time. This is further reflected in the Properties Window (see Figure 5.6), where properties that are bound by implicit expressions are identified with a pink icon (with an appropriate ToolTip). This serves as a warning that modifying these values here in the Properties Window (or in the source) affects only the appearance at design time, not the appearance at runtime.

Figure 5.6. The Properties Window Showing Properties with Implicit Expressions


Note that it would be confusing to have a different design-time experience than the runtime experience, so whenever you change the resource value, you should also change the property value to keep them in synch.

At this point, the Web form is localizable but has not yet been localized. To localize the Web form, copy the resx resource file in the App_LocalResources folder to a new file in the same folder, and change its name to include a culture name. For example to create a French version of the Web form, copy Default.aspx.resx to Default.aspx.fr.resx. Now open the French resources in Visual Studio 2005 and translate all of the text into French. If you change your browser's language preferences to French and run the application, you will see the French version of the Web form.

The Visual Studio 2005 Web Form Designer always displays forms using the fallback resources. Unlike the Windows Forms Designer, it does not allow you to view the form using a different set of resources.


Visual Studio 2005's Web Form Designer does not remember that Generate Local Resource has been run on a Web form. When you add a new control to a form, the new control is not automatically localizable. The control does not include the meta:resourcekey attribute, and a corresponding entry is not added to the resource file. To ensure that the control is localizable, you must remember to either rerun Generate Local Resources or add the meta:resourcekey attribute to the control and create a corresponding entry in the resource file.


You can prevent Generate Local Resources from localizing individual controls by including a meta:localize tag in the control and setting its value to false:

 <asp:Label  runat="server" Text="Label" meta:localize="false"></asp:Label> 


In this example, the Label1 control will not be included in the Generate Local Resources process.

How It Works

It is not necessary to know how implicit expressions work in order to use them, so if you are just looking for results, you can skip this section. But for the curious, read on. One of the ways in which you can find out what ASP.NET is actually doing is to look at the source code that it generates. Include the Debug="true" attribute in the page directive. Add a Label called LocationLabel and add the following code to the page's Load event:

 LocationLabel.Text =     System.Reflection.Assembly.GetExecutingAssembly().Location; 


When the application is run, the Debug attribute ensures that the generated code is saved to disk. The label shows the location of the generated code. Figure 5.7 shows the result when the application is run.

Figure 5.7. Showing the Location of Generated Source Code


Make a note of the name of the DLL (i.e., "App_Web_ofc8q4sg.dll" in this example). In the same folder as the DLL, you will find the generated source. The source filenames begin with "App_Web_" and use the suffix of the DLL (i.e., "ofc8q4sg") with a numbered .cs extension (i.e., "App_Web_ofc8q4sg.0.cs", "App_Web_ofc8q4sg. 1.cs"). The ".0.cs" is the generated source and the ".1.cs" file is your own partial class (i.e., "Default.aspx.cs").

In the generated source code, you will find a method called @__BuildControl-form1. (@__BuildControlform1 is called by @__BuildControlTree, which is called by FrameworkInitialize, which is called by the worker process when the page is requested). The following is a heavily edited extract from @__BuildControlform1:

 @__ctrl1 = this.@__BuildControlLabel1(); @__parser.AddParsedSubObject(@__ctrl1); @__ctrl2 = this.@__BuildControlTextBox1(); @__parser.AddParsedSubObject(@__ctrl2); @__ctrl3 = this.@__BuildControlLabel2(); @__parser.AddParsedSubObject(@__ctrl3); @__ctrl4 = this.@__BuildControlTextBox2(); @__parser.AddParsedSubObject(@__ctrl4); 


Each control is built up using a method in the generated class, and the resulting object is added to the page's parser. The @__BuildControlLabel1() method is representative of the behavior of all the "BuildControl" methods. Here is the code with the #line directives removed, for clarity:

 private global::System.Web.UI.WebControls.Label     @__BuildControlLabel1() {     global::System.Web.UI.WebControls.Label @__ctrl;     @__ctrl = new global::System.Web.UI.WebControls.Label();     this.Label1 = @__ctrl;     @__ctrl.ApplyStyleSheetSkin(this);     @__ctrl.ID = "Label1";     @__ctrl.Text = "User Name";     @__ctrl.Text = System.Convert.ToString(         this.GetLocalResourceObject("Label1Resource1.Text"),         System.Globalization.CultureInfo.CurrentCulture);     @__ctrl.ToolTip = System.Convert.ToString(         this.GetLocalResourceObject("Label1Resource1.ToolTip"),         System.Globalization.CultureInfo.CurrentCulture);     return @__ctrl; } 


Toward the bottom of the method are two assignments to the Label's Text property and one assignment to the Label's Tooltip property. The first assignment to the Label's Text property assigns the value that is set in the IDE. This assignment is redundant because the next line makes an assignment to the same property overwriting the previous value. The second assignment to the control's Text property uses the page's GetLocalResourceObject method to retrieve a resource value using the "Label1Resource1.Text" key. The GetLocalResourceObject in this example ultimately makes a call to ResourceManager.GetObject to retrieve the resource. However, ASP.NET 2.0 is built on a provider model, and, as we see in Chapter 12, "Custom Resource Managers," it is possible to replace the existing model, which uses the ResourceManager class, with a different model that potentially uses a different class. In addition, GetLocalResourceObject goes to some lengths to identify the location of the resource assemblies. This is particularly necessary if you do not precompile your Web sites and the assemblies have pseudorandom names and are placed in folders with pseudorandom names.

If you previously read Chapter 4, "Windows Forms Specifics," you can see that ASP.NET 2's approach is similar to Windows Forms 1.1's Property Assignment Model, as opposed to Windows Forms 2.0's Property Reflection Model. The Property Assignment Model reads a property value for every property in which its Localizable attribute is TRue. The downside to this approach is that every localizable property is pushed to a resource file "just in case" it might be localized. The Property Reflection Model reverses the problem and examines what resources exist and then applies those resources to corresponding properties. Consequently, the Property Reflection Model is more scalable than the Property Assignment Model. ASP.NET does not support an equivalent to the Property Reflection Model in ASP.NET 2.0, but it could be argued that the need for such a model in ASP.NET is not as high as it is in Windows Forms. The main reason for this is that considerably fewer properties are marked with Localizable(true). Instead of implying any lesser potential for localization, the problem of needing to localize properties that are less frequently localized is solved a different way. It is solved using Explicit Expressions, which we come to later in this chapter.

Resx Files, Application Domains, and Session State

One of the new features in ASP.NET 2 is that ASP.NET applications watch for changes to resx files. A change to an application's resx file has the same effect as a change to web.config: The application domain is unloaded and the application is restarted. There are several consequences to this. First, this makes it easy to change resx files and have their changes incorporated into the application immediately. Second, all state in the application is lost as the application domain is unloaded. Certainly, this is an excellent feature during development and can help your translator/localizer considerably, but for obvious reasons, you should avoid taking advantage of this feature in a production environment if your application state is maintained in the application domain (i.e., the default). You can store your application's state in a separate process using the Web.config sessionState element (set the mode attribute to either StateServer or SQLServer).




.NET Internationalization(c) The Developer's Guide to Building Global Windows and Web Applications
.NET Internationalization: The Developers Guide to Building Global Windows and Web Applications
ISBN: 0321341384
EAN: 2147483647
Year: 2006
Pages: 213

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