|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionGlobalization and localization are two important processes which every developer should be aware of while creating global products or applications. Though there are many articles which explain the subject well, I did not find a single resource which explains all important concepts regarding globalization/localization, practically and comprehensively. This article aims to provide practical step-by-step approach to globalizing a web application in ASP.NET 2.0. Background TheoryGlobalization is defined as the process of developing a program or an application so that it is usable across multiple cultures and regions, irrespective of the language and regional differences. For example, you have made a small inventory management program and you live in a region where English is the main language, assume England. Now, if you want to sell your program in a different country, let’s say Germany, then you need to make sure that your program displays and takes input in German language. Localization is the process of creating content, input, and output data, in a region specific culture and language. Culture will decide date display settings (like, mm/dd/yyyy or dd/mm/yyyy), currency display formats etc. Now, the process by which we can make sure that our program will be localized is known as Internationalization or Globalization. In simpler terms, Globalization can be defined as the set of activities which will ensure that our program will run in regions with different languages and cultures. So, globalization is related to intrinsic code changes to support such changes like using Resource files etc. Whereas, localization is the process of using a particular culture and regional info so that the program uses the local languages and culture. This means translating strings into a particular local language. This covers putting language specific strings in the resource files. Globalization starts in the main construction phase along with the code development. Localization generally comes later. Globalizing an ASP.NET 2.0 WebsiteLet’s start with a simple example. For the purposes of explaining localization and keeping things simple, I have created a new website in ASP.NET and C#, called TestSite (source code of the example is included in this article). I have added a Master Page and a default page. This default page has a I have published the test web application, and you can see the functional version here. Cultures and LocaleNow, before we move ahead, let me throw some light on cultures and locale. Languages also depend upon the geographical location. For example, French is spoken in France as well as Canada (besides many other countries). But linguistically speaking, Canadian French is quite different from French spoken in France. Similarly, there are linguistic differences between US English and British English. Therefore, the language needs to be associated with the particular region where it is spoken, and this is done by using locale (language + location). For example: How do we define or change the current culture? There are two properties of the
Thread.CurrentThread.CurrentUICulture = new CultureInfo(“fr”);
Or, Thread.CurrentThread.CurrentUICulture = new CultureInfo(“fr-CA”);
Culture: gets/sets the region specific culture and formats of currency, dates etc. This needs language as well as location (locale).Thread.CurrentThread.CurrentCulture = new CultureInfo(“fr-A”); //correct as
///we have given locale
Thread.CurrentThread.CurrentCulture = new CultureInfo(“fr”); //wrong, will
// not work
Sometimes we need a culture which does not belong to any language or locale, which is invariant of any region/language. For this, we have the Both Switching LocaleComing back to our application, we need a way to switch the locale. There are two approaches regarding this:
<GLOBALIZATION culture="auto" uiculture="auto" enableClientBasedCulture="”true”" />
Going by the second recommended approach, I have created a section on the top (inside a For my application to be globalized, I want that whenever the user selects a locale from the language, the following should happen:
To achieve the above goals, the first thing you need to make sure is to take out content from the code and put it in separate resource files, which are simple XML files in .NET with a .resx extension. Since this content will vary from language to language, we will have resource files for every culture. Each such file has Name and Value fields (like a Dictionary). Below are the sample entries in two resources, assuming we have to enter a string “Welcome”:
If you want to add Canadian French resources, then you need to create another resource file by the name of TestSiteResources.fr-CA.resx. The middle part of this name defines the locale, and this should be the same as specified by the Tip/Trick: If you want that only certain pages show localized strings, you can restrict the localization behavior throughout the application by putting resource files in the App_LocalDirectory folder. This will make localization page specific and not application wide. The naming should be like (assuming you want to localize only a page named MyPage.aspx):
All the above .resx files would be compiled into assemblies at runtime. These assemblies are known by the name of “satellite assemblies”, and have strongly typed wrappers for the .resx files. So, we don’t need to worry about creating resource assemblies ourselves in ASP.NET 2.0. These assemblies are placed in separate folders (by the name of the locale) under the /bin folder, after you have published your website: For non ASP.NET applications, we need to use two tools:
There is lot of detailed information on how to use these tools, on MSDN, and the user can refer to these links: Now that we have created the resource files for different cultures and languages, we need a way to load them at runtime when the user changes culture dynamically. Fortunately, implementing this in ASP.NET 2.0 is quite easy. See the code below: String welcome = Resources.TestSiteResources.Welcome;
In this line of code, we are using the
<asp:Label id=lblWelcome meta:resourcekey="lblWelcome"
Text="Welcome" runat="server">
</asp:Label>
For this to work, we need to have page specific resource files in the /App_LocalDirectory folder. Implicit localization helps trim down the size of the global resource files, and helps in better overall resource management. Use it when you have largely page specific content. You do not need to do anything manually to set these implicit localization properties. Just open your web page in the Design mode, go to Tools->Generate Local Resources. This will automatically create a resource file for your page. You only need to set the values ( <asp:Label id=lblWelcome Text="<%$Resources:TestSiteResources, Welcome %>"
runat="server"></asp:Label>
We can set this using the VS IDE. Select the
lblWelcome.Text = Resources.TestSiteResources.Welcome;
This will work, but then it needs to be coded for every control in the page. So, use #2 for all the controls, and use this method to access resource strings for other content, if needed. Also, note that controls like the Incorporating GlobalizationIn my website, after creating resource files and putting some localized data, I first start using the explicit localization to set the text of the controls such as Notice that the resource files have the locale as their middle names, so I need to set the But the problem is: how should I change the culture dynamically on the postback event? Fortunately, ASP.NET provides a method in the Since this method is in the Going back to the UI design: I had a ///<SUMMARY>
/// The name of the culture selection dropdown list in the common header.
/// We need to use this name as we don't have any other
/// control property as the control (dropdown) itself is not initialized yet.
/// So we use the "nested" dropdown name through which we will get the
/// dropdown's value from the Request.Form[] collection.
/// </SUMMARY>
public const string LanguageDropDownID = "ctl00$cphHeader$Header1$ddlLanguage";
/// <SUMMARY>
/// The name of the PostBack event target field in a posted form. You can use
/// this to see which control triggered a PostBack:
/// Request.Form[PostBackEventTarget] .
/// </SUMMARY>
public const string PostBackEventTarget = "__EVENTTARGET";
See how I am using the " /// <SUMMARY>
/// Overriding the InitializeCulture method to set the user selected
/// option in the current thread. Note that this method is called much
/// earlier in the Page lifecycle and we don't have access to any controls
/// in this stage, so have to use Form collection.
/// </SUMMARY>
protected override void InitializeCulture()
{
///<remarks><REMARKS>
///Check if PostBack occured. Cannot use IsPostBack in this method
///as this property is not set yet.
///</remarks>
if (Request[PostBackEventTarget] != null)
{
string controlID = Request[PostBackEventTarget];
if (controlID.Equals(LanguageDropDownID))
{
string selectedValue =
Request.Form[Request[PostBackEventTarget]].ToString();
switch (selectedValue)
{
case "0": SetCulture("hi-IN", "hi-IN");
break;
case "1": SetCulture("en-US", "en-US");
break;
case "2": SetCulture("en-GB", "en-GB");
break;
case "3": SetCulture("fr-FR", "fr-FR");
break;
default: break;
}
}
}
///<remarks>
///Get the culture from the session if the control is tranferred to a
///new page in the same application.
///</remarks>
if (Session["MyUICulture"] != null && Session["MyCulture"] != null)
{
Thread.CurrentThread.CurrentUICulture = (CultureInfo)Session["MyUICulture"];
Thread.CurrentThread.CurrentCulture = (CultureInfo)Session["MyCulture"];
}
base.InitializeCulture();
}
/// <Summary>
/// Sets the current UICulture and CurrentCulture based on
/// the arguments
/// </Summary>
/// <PARAM name="name"></PARAM>
/// <PARAM name="locale"></PARAM>
protected void SetCulture(string name, string locale)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(name);
Thread.CurrentThread.CurrentCulture = new CultureInfo(locale);
///<remarks>
///Saving the current thread's culture set by the User in the Session
///so that it can be used across the pages in the current application.
///</remarks>
Session["MyUICulture"] = Thread.CurrentThread.CurrentUICulture;
Session["MyCulture"] = Thread.CurrentThread.CurrentCulture;
}
So the user will see the content in his/her selected language. We need to save the culture selected in a Session or a Cookie variable because if the user moves to some other page in the same application, the thread's culture information would be lost as the new <globalization responseEncoding"=utf-8” requestEncoding="utf-8”
fileEncoding="utf-8" />
Note the encoding attributes: Also, an important point to note is that though we can have the resource files in raw XML form on the deployment server (so that the user can edit them without re-compiling the entire site), the application will re-start if we make any modification in the resource files. This can hamper the performance of the deployed application. dir Attribute for Language DirectionMany times, we also need to set the direction of the localized text (which is set using the First, create a Direction (you can use any name) field in all your resource files, setting its property to RTL or LTR based on individual resource files. For Arabic, the value of this field would be RTL, and for Hindi it would be LTR. Then, set the same in the <body runat="server" dir=">
<%$ Resources: TestSiteResources, Direction %>"
This will set the right direction as the value will come from the resource file based on the current thread's culture. Using a Database for LocalizationWe have seen how to localize the text of the controls and the presentation in the UI. But what about the content stored in a database? This content also needs to be localized, but since it is stored in a DB, we cannot use resource files for the same. We need to create new tables for the same. Suppose I have a table which stores user comments. The table structure is: Now, we want the Here, we have added a new field as Now, we can use SQL queries with SummaryI have tried to cover some important aspects of implementing Globalization in ASP.NET 2.0, and we saw that it is easy and simple, but there are a few important points to note:
Though I tried my best to cover important topics, in case I missed something, I would appreciate if readers can send in their suggestions on the same. Happy globalizing! | ||||||||||||||||||||