This article will start with the basic concepts of resource globalization and localization in Asp.net, and explain the steps and methods to achieve globalization and localization in Asp.net1.1 and Asp.net2.0.
one. Basic concepts
1. Why localize resources?
Our site may be viewed by people from various countries and regions around the world, and people in each country and region have their own language and cultural characteristics. Take our great motherland as an example. Mainland China uses Simplified Chinese, while Hong Kong, Macao and Taiwan use Traditional Chinese. In addition, each country has different expression formats for currency, numbers, calendar and other information. Our country mostly uses the year, month, and day format, while the United States uses the month, day, and year format. There are many differences like this, so I won’t give many examples. In order to give our website visitors a better user experience, we should provide a global solution. As long as the user selects his language and region, the site will display the page information according to his language and cultural habits. This process can be called localization.
2. Culture, fixed culture, non-specific culture, culture-specific
culture names follow the RFC 1766 standard and are in the format "<languagecode2>-<country/regioncode2>", where <languagecode2> is derived from ISO 639-1. A two-letter lowercase code, <country/regioncode2> is a two-uppercase code derived from ISO 3166. For example, US English is "en-US". Where two-letter language codes are not available, three-letter codes derived from ISO 639-2 are used; for example, the three-letter code "div" is used for regions where the Dhivehi language is spoken. Some culture names have suffixes that specify a writing symbol; for example, "-Cyrl" specifies a Cyrillic writing symbol, and "-Latn" specifies a Latin writing symbol. Example:
Culture Name | Culture Identifier | Language - Country |
zh-CN | 0x0804 | Chinese - China |
zh-TW | 0x0404 | Chinese - Taiwan |
zh-CHS | 0x0004 | Simplified Chinese |
zh-CHT | 0x |
7C |
04 | Traditional Chinese | |
en | 0x0009 | English |
en - US | 0x0409 | English - United States | en
- | GB | 0x0809 |
uz | - | UZ - Cyrl |
0x0843 | Uzbek (Cyrillic) - Uzbekistan uz-UZ-Latn 0x0443 | Uzbek (Latin) - Uzbekistan |
Fixed cultures are not culture-sensitive. You can use the empty string ("") to specify a fixed culture by name or by the culture identifier 0x007F. Invariant culture instances are represented by the InvariantCulture property of the CultureInfo class. Fixed cultures are only associated with the English language, not any country. It can be used in almost any method in the "globalized" namespace that requires culture. If your program performs string comparisons or case-changing operations, it should use an InvariantCulture to ensure that regardless of the culture set by the system, behavior will be done according to the fixed culture of the English language represented by the InvariantCulture. However, a fixed culture must be used only by processes that require culture-independent results (such as system services); otherwise, the results it obtains may be linguistically incorrect or culturally inappropriate. Example: CultureInfo Invc = New CultureInfo("");
CultureInfo Invc = CultureInfo.InvariantCulture; These two lines of code have the same effect, the purpose is to obtain an invariant culture instance.
For example, you now want to execute the dateTime.ToString() method on a DateTime instance dateTime. This method actually uses the CurrentCulture of your current thread as the default culture, and converts the date instance into the corresponding string form based on this culture. So if we don't need it to perform the ToString operation according to the thread or system culture at this time, then we should use this method dateTime.ToString("G", CultureInfo.InvariantCulture) or dateTime.ToString("G", DateTimeFormatInfo.InvariantInfo) .
A neutral culture is a culture that is associated with a language but not a country. A specific culture is one associated with a certain language and a certain country. For example, "en" is a neutral culture, while "en-US" is a specific culture. Note that "zh-CHS" (Simplified Chinese) and "zh-CHT" (Traditional Chinese) are culture-neutral.
Cultures have a hierarchical structure, that is, the parent of a specific culture is a non-specific culture, and the parent of a non-specific culture is an InvariantCulture. The Parent property of the CultureInfo class will return the non-specific culture associated with the specific culture. If the culture-specific resource does not exist on the system or is otherwise unavailable, the non-culture-specific resource is used; if the non-culture-specific resource is also unavailable, the resource embedded in the main assembly is used.
3. Implement common types, properties, and methods for localization.
The CultureInfo class represents information about a specific culture, including the name of the culture, writing system, and calendar used, as well as information about common operations (such as formatting dates and sorting strings). Provides access to culture-specific objects of information. There are generally two ways to instantiate the CultureInfo class, as follows:
CultureInfo culture = CultureInfo. CreateSpecificCulture (name);
CultureInfo culture = new CultureInfo(name);
The difference between the two is that using the first method, you can only create a CultureInfo instance of a fixed culture or a specific culture. If name is an empty string, a fixed culture instance is created. If name is a non-specific culture, a default culture-specific CultureInfo instance associated with name is created. The second method is to create a CultureInfo instance of the culture specified by name, which can be fixed, non-specific or culture-specific.
The CurrentCulture property of the Thread class is used to get or set the culture of the current thread. It must be set to a specific culture. Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); If Thread.CurrentThread.CurrentCulture = new CultureInfo("en "); an error will be reported!
The CurrentUICulture property of the Thread class is used to get or set the current culture used by the resource manager to find culture-specific resources at run time. The resource manager here can be associated with the ResourceManger class.
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
The ResourceManger class can find culture-specific resources, provide substitute resources when localized resources do not exist, and support resource serialization. The commonly used ResourceManager constructor is public ResourceManager(string, Assembly). Its meaning is to initialize a new instance of the ResourceManager class, which looks for resource files from the given Assembly using the specified root name. The so-called root name is, for example, the root name of a resource file named "MyResource.en-US.resources" is "MyResource". A namespace can be added to the expression of the root name, such as "MyWebSite.Resource.UserFolder.MyResource". The Assembly can be the Assembly where the page that needs to call the resource file is located, such as typeof(MyPage).Assembly. The GetString method of the ResourceManager class is used to obtain the value of the specified key in the resource file. Example: When the CurrentUICulture property of the thread has been set, follow the following method.
ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly());
String str = rm.GetString("welcome");
If you want to obtain resources according to the specified culture, write as follows:
ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly());
CultureInfo ci = Thread.CurrentThread.CurrentCulture;
String str = rm.GetString("welcome",ci);
two. To implement resource localization in Asp.net1.1,
you should first create a Resource folder in the website project WebTest, and store resource files common to the entire project in this folder. For example, we have created the following three resource files: MyResource.en.resx, MyResource.en-US.resx, MyResource.zh-CN.res. There are two key-value pairs in each resource file, the key values are State and Address. Call the resource file in the page MyPage.aspx that needs to use the resource file, as shown below:
Thread.CurrentThread.CurrentCulture= CultureInfo.CreateSpecificCulture("zh-CN");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
ResourceManager rm = new ResourceManager("WebTest.Resource.MyResource", typeof (MyPage).Assembly);
Label1.Text = rm.GetString("State");
Label2.Text = rm.GetString("Address");
Well, at this time Label1 and Label2 will display "state" and "address" according to the regulations in the MyResource.zh-CN.resx file. The above is the most basic and simple localization method. There are some problems hidden here. Let us solve and optimize this method one by one.
1. How to obtain the user's default culture
is through the settings in the user's browser's "Properties" -> "Language" option. Take the top one as the user's default language.
CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(Request.UserLanguages[0]);
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
Generally, the CurrentCulture and CurrentUICulture are set to have the same culture. Of course, they can also be different. For example, you specify that CurrentCulture is en-US and CurrentUICulture is zh-CN. The effect of this is that the currency, date and other information on the page are displayed in the American English format, and the resource manager will obtain the content that needs to be obtained from the resource file from the MyResource.zh-CN.resx file.
If your site page does not provide the function for users to select a language, then it will be displayed according to the culture set by the user's browser by default, so you can put the above code in the Application_BeginRequest method of the Global.asax.cs file. . This way every time a user makes a request for a page, our program will first set the culture.
2. Remember the user's locale settings
The browser's locale settings or selections can be remembered through the session. But this operation cannot be performed in the Application_BeginRequest method in the Global.asax.cs file, because the session is still unavailable at that time. If your site does not provide the function for users to select a language, then there is no need for you to remember the user's regional settings. Just set it in the Application_BeginRequest method in the Global.asax.cs file as described above. No affect performance. This mainly avoids conflicts in which the user suddenly changes the language settings in the browser midway, but the website still displays the page content to the user according to the culture stored in the session.
If you have mentioned the function of letting the user select a language, then obviously you need to use a session in the page program to record the user's culture selection. Because every request from the client to the server segment, the server segment will open a new thread for processing and response. If your program does not remember the customer's selection, it will only respond with the default culture.
3. How does the resource manager find the corresponding resource files for a specified culture?
When performing a value operation, that is, when executing the GetString method of the ResourceManager class, the resource manager will search for the corresponding resource file according to the CurrentUICulture property of the current thread. There are several situations:
(1). For example, if the culture corresponding to the current CurrentUICulture is en-US, then first check whether MyResource.en-US.resx exists. If it exists, take the value from it; if it does not exist, check whether MyResource.en.resx exists.
(2). For example, the culture corresponding to the current CurrentUICulture is en, because en is a non-specific culture, then first find whether the resource file MyResource.en-US.resx of the specific culture en-US associated with it by default exists. If so, Then get the value from it; if it does not exist, check whether MyResource.en.resx exists.
(3). For example, if the culture corresponding to the current CurrentUICulture is en-GB, then first find the resource file MyResource.en-GB.resx. If it does not exist, check whether MyResource.en.resx exists. If it exists, get the value from it; If it does not exist, check whether the resource file MyResource.en-US.resx of the default specific culture en-US associated with en exists. If MyResource.en-US.resx does not exist at this time, but MyResource.en-CA. resx exists, the program will still throw an exception that the appropriate resource file cannot be found.
Therefore, we can summarize that when the current thread CurrentUICulture corresponds to a specific culture, the resource manager first searches for the resource file corresponding to this specific culture. If it is not found, it will look for its non-culture resource file. If it has not yet been Find it, and then look for the resource file of the default culture associated with its non-culture-specific association. When the current thread's CurrentUICulture corresponds to a non-specific culture, the resource manager first checks whether the default culture-specific resource file corresponding to the non-specific culture exists. If it does not exist, check whether the resource file corresponding to the non-specific culture exists. exists, and throws an exception if it does not exist either.
4. How to deal with cultures that do not provide localization support?
If the site does not provide corresponding resource files to support the user's default culture, then the CurrentUICulture of its current thread must be converted to your site's default culture, such as en-US or zh-CN. There are two opportunities for conversion:
One is that when you obtain Request.UserLanguages[0], compare it with the supported culture preset in the configuration file. If it is confirmed that it is not supported, then immediately set CurrentUICulture as the default culture.
The second is to use the try catch structure to capture the MissingManifestResourceException exception when using the GetString method of ResourceManager to obtain the value. In the exception handling, first set the CurrentUICulture to the default culture, and then use GetString to obtain the value again.
5. Set the site's default culture and uiCulture through Web.config
<globalization requestEncoding="utf-8" responseEncoding="utf-8" uiCulture="zh-CN" culture="en-US"/>
As shown above: It is specified that the default culture of the site is en-US (it must be a specific culture here), and the uiCulture is zh-CN.
Of course, you can also set it page by page in the Page tag of each page: <@Page Culture="zh-CN" UICulture="en">. Regardless of how web.config is set here, the page will be displayed according to the settings of the Page tag.
three. Implementing resource localization in Asp.net2.0
Asp.net2.0 provides more diverse implementation methods for resource localization. I will focus here on the differences from Asp.net1.1.
1. Setting the site's default culture and uiCulture through Web.config
has already been discussed in Asp.net1.1 using the web.config file to set the site's culture, but in Asp.net2.0 it is more flexible. Typically, you'll want all pages in your site to conform to the same culture. Just assign a site-wide "auto" value to the UICulture and Culture (culture) attributes of the globalization element in web.config as shown below. Note that this "auto" value is not used in Asp.net1.1 accepted. <globalization uiCulture="auto" culture="auto" /> The meaning of auto is that ASP.NET obtains the user's preferred culture setting by checking the HTTP header sent by the browser, and uses this culture to set the default culture of the site. That is, the CurrentUICulture and CurrentCulture properties of the current thread.
In addition to automatic settings, you can also specify a site's default culture for Asp.net: <globalization uiCulture="auto:zh-CN" culture="auto:zh-CN" /> Note: This is only possible if ASP.NET cannot Find the HTTP header to determine the user's preferred culture. For example, when there is no culture setting in the browser's "Properties" -> "Language" and it is completely empty, the default culture set after auto will take effect.
After globalization is configured in web.config, your application does not need to write any code. The CurrentUICulture and CurrentCulture of the thread will obtain the culture settings according to the uiCulture and culture attribute values set in the globalization element. If globalization is not configured, the thread's CurrentUICulture and CurrentCulture will default to en-US.
2. Use the Web.config file to track the user's regional selection.
In Asp.net1.1, those sites that provide regional selection generally use sessions to record the user's selection so that every time the user makes a request to the site, All display content is localized according to the culture chosen by the user. Another method provided in Asp.net2.0 is to use the web.config file to track the user's culture selection.
You can support anonymous identification of a user's culture by adding a string-based profile property called LanguagePreference to your web.config file. Please note that the enabled attribute of the anonymousIdentification element must be "true", otherwise the anonymous identification function will not be available.
<anonymousIdentification enabled="true"/>
<profile>
<properties>
<add name="LanguagePreference" type="string" defaultValue="auto" allowAnonymous="true" />
</properties>
</profile>
Below I will explain how to program the LanguagePreference attribute in Asp.net2.0. First, you can write a PageBase class, which inherits from System.Web.UI.Page and serves as the base class for all page classes in the site. The purpose of this is actually very simple, which is to extract some common processing processes in each page and put them into the base class to reduce code duplication and improve maintainability. Then write the following code in the PageBase class: protected override void InitializeCulture()
{
base.InitializeCulture();
string LanguagePreference = ((ProfileCommon)this.Context.Profile).LanguagePreference;
//When the user visits this site for the first time and Profile.LanguagePreference is empty, identify the language setting of the user's browser
if(string.IsNullOrEmpty(LanguagePreference))
{
if (this.Context.Request.UserLanguages != null)
{
LanguagePreference = this.Context.Request.UserLanguages[0];
((ProfileCommon)Context.Profile).LanguagePreference = LanguagePreference;
}
}
else
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(LanguagePreference);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(LanguagePreference);
}
}
The InitializeCulture method of the System.Web.UI.Page class is newly added in Asp.net2.0. It sets Culture and UICulture for the current thread. The page life cycle has been designed so that the InitializeCulture method runs before the page's Init and Load. In the above code, first use ((ProfileCommon)this.Context.Profile).LanguagePreference; to obtain the value of the current LanguagePreference profile attribute and determine whether it is empty, that is, whether the cultural settings have been saved for the user. If empty, the user's preferred culture is obtained from the Http header and saved via ((ProfileCommon)Context.Profile).LanguagePreference = LanguagePreference;. If it is not empty, it means that the user's culture settings have been saved, then use this culture to set the CurrentUICulture and CurrentCulture properties of the current thread.
If <globalization uiCulture="auto" culture="auto" /> is defined in Web.config, then the above code can be simplified to: protected override void InitializeCulture()
{
base.InitializeCulture();
string LanguagePreference = ((ProfileCommon)this.Context.Profile).LanguagePreference;
if(!string.IsNullOrEmpty(LanguagePreference))
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(LanguagePreference);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(LanguagePreference);
}
else
{
((ProfileCommon)Context.Profile).LanguagePreference = Thread.CurrentThread.CurrentCulture.Name;
}
}
If the site provides a function that allows users to select a culture, such as placing a list of language selections in the master page of the site, then the user's choice of culture can be remembered through the following statement:
protected void lstLanguage_SelectedIndexChanged(object sender,EventArgs e)
{
if (lstLanguage.SelectedValue != "Auto") //The default option is Auto
{
Profile.LanguagePreference = lstLanguage.SelectedValue;
}
else
{
Profile.LanguagePreference = null;
}
Response.Redirect(Request.Url.AbsolutePath);
}
Pay attention to the line of code Response.Redirect(Request.Url.AbsolutePath); because the event handling code is executed after Page_Load, if you want the page to change quickly, you must perform a redirection operation.
When using resource files to create global resource files in the site
in Asp.net2.0
, VS.Net2005 will automatically create an App_GlobalResources folder specifically to store global resource files.The so-called global resource file is a resource file used by multiple page files or master pages in the site. Suppose we create files named MyResource.resx and MyResource.zh-cn.resx. In the program, we can use the following code to obtain the value in the resource file: this.lblCountry.Text = Resources.MyResource.Country;
Where Country is the key in the resource file. Obviously, this is much easier than getting values from resource files in Asp.net 1.1.
There are two issues to note here: First, when creating a group of resource files with the same root name, files without culture identification must be created, such as MyResource.resx, others such as MyResource.en-gb. resx and MyResource.zh-cn.resx are created as needed. If MyResource.resx is not created and only MyResource.zh-cn.resx is created, MyResource will not appear under the Resources namespace in the above code, so the compilation of the above code cannot pass. MyResource.resx should store the content of the site's default language in case a localized resource file matching the current thread's CurrentUICulture cannot be found or the corresponding key value cannot be found in the localized resource file. Asp.net is based on the key in the MyResource.resx file. If the Country key does not exist in MyResource.resx, but the Country key exists in MyResource.zh-cn.resx, then the above code will also report an error when compiling. Second, Asp.net will not report any exception when it cannot find the localized resource in the corresponding area. It will automatically obtain the value from the MyResource.resx file, but it will not change the CurrentUICulture of the current thread.
When creating local resource files in the site, VS.Net2005 will automatically create an App_LocalResources folder specifically to store local resource files. The so-called local resource files are resource files used for a single page file in the site. Its naming method is generally Default.aspx.resx and Default.aspx.zh-cn.resx. Now I add three keys Language, lblNavigation.Text and lblNavigation.ForeColor in the Default resource file. Among them, I set blue for lblNavigation.ForeColor of Default.aspx.resx and red for lblNavigation.ForeColor of Default.aspx.zh-cn.resx. There are two ways to obtain content from local resource files in Default.aspx in the page file:
(1). <asp:Label ID="lblLanguage" runat="server" Text="<%$ Resources:Language %>"></asp:Label>
(2). <asp:Label ID="lblNavigaion" runat="server" meta:resourcekey="lblNavigation"></asp:Label>
Be careful to use the $ symbol when using the first method. Using the second method is more flexible and allows you to set values for many properties of the control at once.
There are still issues to note here: the default local resource file of the page must be created, such as Default.aspx.resx is required, and Default.aspx.zh-cn.resx is required. If you do not create a default local resource file, but use local resource files in the page, when using the first method for binding, a compilation error will occur; when using the second method for binding, no compilation error will occur. A compilation error occurs, but the settings of these properties have no effect, as if they were not written.
4. Displaying localized images
Displaying localized images is also a new feature of Asp.net2.0. In Asp.net2.0, resource files are not limited to string type key-value pair combinations. It can save multiple types of files. Use this feature to localize images. In fact, the so-called localized images are nothing more than placing images prepared for different regions into different localized resource files. For example, put LitwareSlogan.jpg in MyResource.resx, and put LitwareSlogan.cn.jpg in MyResource.zh-cn.resx.
When global resource files of different localized versions contain localized versions of image files, you can customize a handler file named MyLocalImage.ashx to conditionally load it based on the user's language preference. The code is as follows Show.
Calling method in the page:
<asp:Image ID="Image1" runat="server" ImageUrl="~/ MyLocalImage.ashx" />
How to write the handler of MyLocalImage.ashx:
public class MyLocalImage: IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
context.Response.ContentType = "image/png";
string LanaguageReference = ((ProfileCommon)context.Profile).LanguagePreference;
if (!string.IsNullOrEmpty(LanaguageReference))
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(LanaguageReference);
}
Bitmap bm = Resources.Litware.LitwareSlogan;
MemoryStream image = new MemoryStream();
bm.Save(image,ImageFormat.Png);
context.Response.BinaryWrite(image.GetBuffer());
}
}
The custom handler class defined in MyLocalImage.ashx uses similar logic that you saw previously in the custom InitializeCulture method to initialize the CurrentUICulture settings for the current thread before retrieving the image file from the global resource file. You may wonder why the CurrentUICulture of the current thread has been set in the base class of the page and needs to be reset here. That is because the thread here is not the same thread as the thread processed in the base class. After the custom handler correctly initializes the CurrentUICulture settings, it can access the image file through the strongly typed resource class of MyResource.resx. Then it's just a matter of writing the image file's bits to the HTTP response stream.