540 likes | 869 Vues
. Objectives: . Describe the Internationalization issues related to ASP.NET 2.0 applicationsDefine technical approaches Suggest strategies for Internationalizing ASP.NET 2.0 applications (and WinForms, too). Assumptions: Environment. ASP.NET 2.0 development environment Using Visual Studio 200
E N D
3. Assumptions: Environment
ASP.NET 2.0 development environment
Using Visual Studio 2005 C#
Microsoft SQL Server 2005
Typically, single or clustered server environment supporting multiple languages simultaneously:
Unicode as default code set
Likely: Using ASP.NET 2.0 Membership/Profile capabilities
4. Assumptions: Users
Using browsers:
Internet Explorer 6.0+ (Windows and Mac??)
Firefox 1.5+ (Windows and Mac)
Safari 1.3.2 (Mac)
Languages initially supported:
Unicode as default code set
English (default)
Western European languages
Asian: Japanese, Korean, Chinese (simplified (PRC), traditional (Taiwan, other areas)
Discussion will NOT include: bi-directional language
Only Gregorian calendar system will be considered
Most Users are not on local LAN - not dependant upon AD
7. SQL Server 2005 Default Internationalization Settings Default internationalization behavior is determined by:
SQL Installation
Install asks for default Character set and Collation - Affects System database Choosing Unicode would double system databases
- Hard to change after SQL Server is installed
Suggest using DEFAULTS: Windows Latin-1 char. Set Latin1_General collation
Defining a new database
Defaults to model database
- which defaults to SQL Installation Char set/Collation unless model database has been altered
Suggest using DEFAULTS:
8. SQL Server 2005 Data Columns Use Unicode datatypes in: Table columns, CONVERT() and CAST() operations
nchar
nvarchar
nvarchar(max)
ntext
Catalog view sys.types reports length in bytes, not characters
Substitute: ASCII() and CHAR() with: UNICODE() and NCHAR()
Define variables and parameters of Stored Procedure and triggers in Unicode
Prefix Unicode string constants with the letter N
Important even if the column name being references is Unicode: e.g. EXECUTE Product_Info @name = NChain SQL Server Book Online Server Side Programming with UnicodeSQL Server Book Online Server Side Programming with Unicode
9. SQL Server 2005 Unicode SQL Server 2005 uses UCS-2
Some characters not included: Additional Chinese characters
SQL Server stores these as: supplementary characters - stored as two unified Unicode character
Supplementary characters sorted in 90 series collations:
Japnese_90
Korean_90
Chinese_PRC_90 Chinese_PRC_Stroke_90
Chinese_Taiwan_Bopomofo_90 Chinese_Taiwan_Stroke_90
Chinese_Hong_Kong_Stroke_90_CI_AS SQL Server Book Online Supplementary Characters
And -- Collation Settings in Setup AND Storage and Performance Effects of UnicodeSQL Server Book Online Supplementary Characters
And -- Collation Settings in Setup AND Storage and Performance Effects of Unicode
10. SQL Server 2005 Collation SQL Server 2005 uses two collation Types
Windows Collation
Defined to support Windows locales
Uses the same code pages, sorting, comparisons as an application on a Windows system
Recommended if you mix Unicode and non-Unicode columns in the database applies Unicode based sorting rules to both Unicode and non-Unicode data (internally converts non-Unicode data to Unicode for comparison operations), unlike SQL Collations
Default setting Latin1_General supports 33 locales
SQL Collations Legacy for prior SQL versions
Sorts Unicode fields as Unicode, and non-Unicode as non-Unicode SQL Server Book Online Collation Types
And -- Collation Settings in SetupSQL Server Book Online Collation Types
And -- Collation Settings in Setup
11. SQL Server 2005 Sorting Order Sort order concepts
Three sort values
Primary value basic character ignoring case and accents
Secondary value A = a
Tertiary value - typically accents
Options:
Case Sensitive
Accent Sensitive
Kana sensitive distinguish between Japanese Kana and Hiragana
Width sensitive - distinguish between half-width and full-width chars.
Binary Binary Code For more detailed discussion, see the book: Inside Microsoft SQL Server 2005: The Storage Engine Pages 11-14 -- AND -- SQL Server Book Online Windows Collation Sorting Styles For more detailed discussion, see the book: Inside Microsoft SQL Server 2005: The Storage Engine Pages 11-14 -- AND -- SQL Server Book Online Windows Collation Sorting Styles
12. SQL Server 2005 SQL statements Specifying Collation in SQL
Collate clause:
Example:
SELECT name FROM customer ORDER BY name COLLATE Japanese_Unicode
Append options:
_CS _CI Case sensitive Case insensitive
_AS _AI Accent sensitive Accent inensitive
_KS Kana sensitive, if omitted, Kana insensitive
_WS Width sensitive, if omitted, width insensitive
Examples: Latin1_General_CI_AS SQL Server Book Online Windows Collation Name AND Windows Collation Sorting StylesSQL Server Book Online Windows Collation Name AND Windows Collation Sorting Styles
14. Culture Description of a language, and OPTIONALLY a region
System.Globalization.CultureInfo class
Culture string representation based on RFC 1766: languagecode2[-country/regioncode2[-script]]
Examples: en represents neutral English en-GB represents UK English
CultureInfo object
Invariant: absence of culture (may be English)
Neutral en Language NOT specific to a particular region
Specific en-GB Language in a specific region, and region info, e.g., formatting Further description: see .NET Internationalization book by Guy Smith Ferrier: pages 33-35Further description: see .NET Internationalization book by Guy Smith Ferrier: pages 33-35
15. Default International behavior Default internationalization behavior is determined by:
- CurrentCulture and CurrentUICulture
Determined from either:
CultureInfo class, or the current thread
Assigned only from the current thread
CurrentCulture must be a SPECIFIC culture:default culture for System.Globalization affects culture specific formatting (date/time, number,currency, AND display of Calendar control)
CurrentUICulture Can be neutral or specific culture:default culture used by ResourceManager
16. Setting the Culture Web.config
<globalization enableClientBasedCulture=true culture=en-GB uiculture=en />
Or, <%@ Page Culture=auto:en-GB UICulture=auto:en . %>
Page
Automatic (browsers first requested culture) with default: <%@ Page Culture=auto:en-GB UICulture=auto:en . %>
Programmatically:
Analyze complete list of browsers culture requests
Based upon setting in the Users Profile NOTE: enabledClientBaasedCulture optional attribute to the <globalization tag is not in use at this time according to Visual Studio 2005 help file,an.NOTE: enabledClientBaasedCulture optional attribute to the <globalization tag is not in use at this time according to Visual Studio 2005 help file,an.
17. Setting the Culture Collation SQL Server 2005 Collations
Two types:
Windows Collations recommended
Based upon Windows locales attempt to match SQL Server 2005 and Windows localesDefault Latin1_General
SQL Collations -- Legacy with prior version of SQL Server
Called very early in the page life cycle: - before ALL page events - during the FrameworkInitialize method before controls are created
Can set culture based upon LCIDinstead of Culture Name - useful for alternative Sort Orders
For discussion of LCID -Alternative Sort Orders, see: .. Chapter 6For discussion of LCID -Alternative Sort Orders, see: .. Chapter 6
18. Set Culture reviewing all culture requests from the browser Matching browsers culture requests:
Automatic method: <%@ Page Culture=auto .only uses browsers FIRST request
Iterate through the browsers requested cultures
Browsers cultures are listed in Priority order (there are actually weight information)
Strategies:
Find the first valid culture
Find the first culture that is supported by resource code
Differentiate between Culture and UICulture
19. Set Culture reviewing all browser requests CODE Sample Iterate through the browsers requested cultures Part 1 of 2 (Sample taken from .NET Internationalization book, pp 148-9)
protected override void InitializeCulture(){ if (Request.UserLanguages != null && Request.UserLanguages.GetLength(0) > 0) { foreach (string userLanguage in Request.UserLanguages) { CultureInfo cultureInfo = GetCultureInfo(userLanguage, true); if (cultureInfo != null) { Thread.CurrentThread.CurrentUICulture = cultureInfo; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name); break; } } }}
20. Set Culture reviewing all browser requests CODE Sample Iterate through the browsers requested cultures -- Part 2 of 2 (Sample taken from .NET Internationalization book, pp 148-9)
protected virtual CultureInfo GetCultureInfo( string userLanguage, bool useUserOverride){ int semiColonIndex = userLanguage.IndexOf(";"); if (semiColonIndex != -1) userLanguage = userLanguage.Substring(0, semiColonIndex); try { return new CultureInfo(userLanguage, useUserOverride); } catch (ArgumentException) { return null; }}
21. Set Culture Using Culture Information from User Profile User Profile :
Store users preferred culture information in the ASP.NET 2.0 Membership/Profile system
For each page, or using a new base class for all pages (Except the Logon-on pages)
See: Core Internet Application Development with ASP.NET 2.0 page 971
24. Setting the Culture - Page InitializeCulture method for a page
Method is new to ASP.NET 2.0
Called very early in the page life cycle: - before ALL page events - during the FrameworkInitialize method before controls are created
Can set culture based upon LCIDinstead of Culture Name - useful for alternative Sort Orders
For discussion of LCID -Alternative Sort Orders, see book: .NET Internationalization - Chapter 6For discussion of LCID -Alternative Sort Orders, see book: .NET Internationalization - Chapter 6
25. Resource code Managers ASP.NET Built-in: System.Resources.ResourceManager
Uses standard .resx format
Easily handled by localization firms
Directly supported in VS 2005
Built-in tool to generate .resx filesfrom non-localized ASP.NET project
Cached good performance
Custom resource managers
Directly use SQL Server
Slower performance The book: .NET Internationalization devotes Chapter 12 to Custom Resource Managers including a manager that directly uses SQL Server. However, the author cautions that all of the custom managers described in the chapter have poorer performance than the System.Resources.ResourceManager.
The book: .NET Internationalization devotes Chapter 12 to Custom Resource Managers including a manager that directly uses SQL Server. However, the author cautions that all of the custom managers described in the chapter have poorer performance than the System.Resources.ResourceManager.
26. Creating Resource Files VS 2005 Tool Visual Studio 2005 tool: Generate Local Resources
Generates resource file for a particular page -- from Design view Tools > Generate Local Resoruces
Automatically creates .resx file that includes all properties marked: Localizable(true)
By default, most Webcontrols: Text, Title, ToolTip
NOT HTLM controls, except: HtmlAnchor, HtmlImage HtmlInputImage, HtmlTitle
Automatically modifies the page source
Does NOT work with raw HTLM, e.g.: <p>text</p> can substitute Localize control
27. Resource File Hierarchy The Generate Local Resource tool only creates the default page resource files.You must copy the default resource files and rename then to create the language resource hierarchy. Diagram from: Core Internet Application Development with ASP.NET 2.0 page 960Diagram from: Core Internet Application Development with ASP.NET 2.0 page 960
28. Generate Local Resources Generate Local Resources Example code BEFORE using tool: <%@ Page Language="C#" AutoEventWireup="true CodeFile="Default.aspx.cs" Inherits="_Default" %>
<table>
<tr>
<td style="width: 100px">
<asp:Label ID="Label1" runat="server"
Text="User name"></asp:Label></td>
<td style="width: 100px">
<asp:TextBox ID="TextBox1" runat="server">
</asp:TextBox></td>
</tr>
</table> Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 137)
Full Before example is as follows:<%@ 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 ID="Label1" runat="server"
Text="User name"></asp:Label></td>
<td style="width: 100px">
<asp:TextBox ID="TextBox1" runat="server">
</asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px">
<asp:Label ID="Label2" runat="server"
Text="Password"></asp:Label></td>
<td style="width: 100px">
<asp:TextBox ID="TextBox2" runat="server">
</asp:TextBox></td>
</tr>
<tr>
<td colspan="2" style="width: 100px">
<asp:Button ID="Button1" runat="server"
Text="Login" Width="264px" /></td>
</tr>
Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 137)
Full Before example is as follows:
29. Generate Local Resources Generate Local Resources Page SourceExample code, before using tool:
<%@ Page Language="C#" AutoEventWireup="true CodeFile="Default.aspx.cs" Inherits="_Default" %>
after using tool:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default"
Culture="auto" meta:resourcekey="PageResource1" UICulture="auto" %> Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 139)Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 139)
30. Generate Local Resources Generate Local Resources Example code, after using tool:
<table> <tr>
<td style="width: 100px">
<asp:Label ID="Label1" runat="server"
Text="User Name"
meta:resourcekey="Label1Resource1">
</asp:Label></td>
<td style="width: 100px">
<asp:TextBox ID="TextBox1" runat="server"
meta:resourcekey="TextBox1Resource1">
</asp:TextBox></td>
</tr> </table> Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 140)
Full version of the example is as follows:<table>
<tr>
<td style="width: 100px">
<asp:Label ID="Label1" runat="server"
Text="User Name"
meta:resourcekey="Label1Resource1">
</asp:Label></td>
<td style="width: 100px">
<asp:TextBox ID="TextBox1" runat="server"
meta:resourcekey="TextBox1Resource1">
</asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px">
<asp:Label ID="Label2" runat="server"
Text="Password"
meta:resourcekey="Label2Resource1">
</asp:Label></td>
<td style="width: 100px">
<asp:TextBox ID="TextBox2" runat="server"
meta:resourcekey="TextBox2Resource1">
</asp:TextBox></td>
</tr>
<tr>
<td colspan="2" style="width: 100px">
<asp:Button ID="Button1" runat="server"
Text="Login" Width="264px"
meta:resourcekey="Button1Resource1" /></td>
</tr>
</table>
Notice that the original Text
Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 140)
Full version of the example is as follows:
32. Generate Local Resources Generate Local Resources Example Resource file: Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 138)
Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 138)
33. Generate Local Resources Generate Local Resources
Original TEXT attribute is retained
Not used at Runtime
Shown at design time
Property Windows - shown with pink icon:
Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 141)
Example taken from .NET Internationalization Chapter 5 ASP.NET Specifics (page 141)
34. Preventing localization When using the Generate Local Resources tool
Can prevent a control from being included in Generate Local Resources:<asp:Label ID="Label1" runat="server"
Meta:localize=false Text="User name">
</asp:Label> Example taken from: .NET Internationalization page: 142Example taken from: .NET Internationalization page: 142
35. Localize control Generate Local Resource tool Does NOT work with static text, e.g.: <p>This is an example.</p>
Can substitute Localize control (derived from Literal), but must contain ONLY static text (no ASP.NET controls) <p> <asp:Localize ID=locEx runat=Server> This is an example. </asp:Localize> </p>Generate Local Resources will transform this to: <p> <asp:Localize ID=locEx runat=Server> meta:resourcekey=locEx Text=This is an example.> </asp:Localize> </p> Example taken from: Core Internet Application Development with ASP.NET 2.0 Pages 958-9 (with corrections)
NOTE: <asp:Localize> element can contain ONLY static content and NOT any ASP.NET Web ControlsExample taken from: Core Internet Application Development with ASP.NET 2.0 Pages 958-9 (with corrections)
NOTE: <asp:Localize> element can contain ONLY static content and NOT any ASP.NET Web Controls
36. Explicit Expressions Generate Local Resource tool generates IMPLICIT expressions for controls with properties marked internally as Localizable(true)
Explicit Expressions useful for binding resources to ANY property such as color, or ImageURL of ImageControl
- use in HTML Attributes
Steps:Create string resource entry: e.g.: WarningColor
Using Controls Expressions select . Select the control, Expression Type choose: Resources Select the resource entry, property, resource Example taken from: .NET Internationalization pages: 151-4
The example for these EXPLICIT steps modifies a button definition as follows:
<asp:Button ID="SellStockButton" runat="server"
meta:resourcekey="SellStockButtonResource1"
Text="Sell Stock" BackColor="<%$ Resources:WarningColor %>" />
Example taken from: .NET Internationalization pages: 151-4
The example for these EXPLICIT steps modifies a button definition as follows:
<asp:Button ID="SellStockButton" runat="server"
meta:resourcekey="SellStockButtonResource1"
Text="Sell Stock" BackColor="<%$ Resources:WarningColor %>" />
37. Explicit Expressions contd Explicit Expressions
Syntax: <%$ Resources: resource-file, resource-key %>"
If resource-file is not specified, then looks for resource-key in local resource
Cannot combine: Explicit resource expression for a local resource and Implicit resource expression within same control
Can combine: Explicit resource expression for a GLOBAL resource and Implicit resource expression within same control As discussed in: Core Internet Application Development with ASP.NET 2.0 Pages 962As discussed in: Core Internet Application Development with ASP.NET 2.0 Pages 962
38. Global Resources Global Resources
Reduces duplication All pages may share access to the same set of resources
Necessary for Explicit resources where in control that also uses Implicit resources
Compiled into a strongly typed class
MUST be in folder: App_GlobalResources
MUST use explicit resource references
39. Programmatic Resource Access Global Resources
Can use compiled classname labMessage.Text = Resources.GlobalColors.WarningColor;
Local Resources
User the GetLocalResourceObject labMessage.Text = (string)GetLocalResourceObject( PageResources1.title);
41. Formatting - Overview Formatting
Default setting dictated by: CurrentCulture
Or, you may specify a particular culutre
Culture senstitive Requires an SPECIFIC Culture
E.g., en-GBNOT en
Always use the Globalization class
Consider Invariant for data exchange
42. Formatting Overview contd Formatting
Implications for:
Text: Comparison, case conversion, string length Sorting
Numbers/Currency
Date/Time
Issues: is the method sensitive to: CultureInfo.CurrentCulture
43. Text comparison String comparison
Culture Insensitive/Case Insensitive: == (equality operator) String.Equals(String,String)
Culture Sensitive String.Equals(String,String,StringComparison) String.CompareTo(String) String.Compare(String,String) String.Compare(String,String,Boolean) case-T/F String.Compare(String,String,StringComparison)
44. StringComparison StringComparison - Enumeration
CurrentCulure
CurrentCultureIgnoreCase
InvariantCulture
InvariantCultureIgnoreCase
Ordinal
OrdinalIgnoreCase
Ordinal comparison based upon numerical values of the Char objects in each string StringComparison enumeration is new in .NET 2.0StringComparison enumeration is new in .NET 2.0
45. Case conversion Case Conversion
Many language scripts do not have have a concept of case e.g., Japanese, Chinese
Culture Sensitive String.ToUpper() String.ToUpper(CultureInfo) String.Lower() String.ToLower(CultureInfo) Char.ToUpper() Char.ToUpper(CultureInfo) Char.ToLower() Char.ToLower(CultureInfo)
Culture Insensitive
-- Use CultureInfo overload and specify:
CultureInfo.InvariantCulture Case conversion defaults to CurrentCultureCase conversion defaults to CurrentCulture
46. Domain Name Processing International Domain names
Originally only 7-bit ASCII characters
2003 IETF specifies interim solution until full use of Unicode
Encoding system Unicode to ASCII domain names
.NET 2.0 idnMapping class idnMapping.GetAscii idnMapping.GetUnicode
Strategy:
Display (and accept) URLs and e-mail addresses in Unicode
Store and utilize URLs and e-mail addresses in Ascii Encoded form See discussion in the book: .NET Internationalization pages 209-212See discussion in the book: .NET Internationalization pages 209-212
47. Sorting Collation in .NET Sorting Issues
Distinction: (CompareOptions enumeration)
Word sort weights on characters e.g., coop sorts close to co-op
String sort all non-alphanumeric sort before alphanumeric
Ordinal sort based on the numeric value each Char object
Some Unicode characters can have multiple binary representations: composite characters dual-width
Unicode has four different normalization algorithms to normalize a string
Precise way of sorting/comparison in .NET:
Normalize strings: System.String.Normalize - used Unicode normalization to map to standard
Use Ordinal option on Compare to compare strings
Normalization technique detailed in Visual Studio 2005 - .NET Framework Developers Guide under Normalization and SortingNormalization technique detailed in Visual Studio 2005 - .NET Framework Developers Guide under Normalization and Sorting
48. Sorting/Collation - LCID Sorting Issues contd
Most cultures have multiple sort orders e.g.: Spanish Modern/International - Traditional the culture: es-ES uses the default Modern/Intl sort
.NET 2.0 allows creation for alternative sorting:
CultureInfo cultureInfo = new CultureInfo(es-ES_tradnl);
.NET 1.1 and 2.0 allow using Local ID (LCID)
CultureInfo cultureInfo = new CultureInfo(0x0000040A); Details available in the book: .NET Internationalization Globalization chapter Pages: 182-7
The discussion on pages 187-9 describe the problems of depending upon the browser preferences distinguishing between different sort orders that are available for the same culutre.Details available in the book: .NET Internationalization Globalization chapter Pages: 182-7
The discussion on pages 187-9 describe the problems of depending upon the browser preferences distinguishing between different sort orders that are available for the same culutre.
49. Numbers/Currency Numberic .ToString
Culture formatted using NumberFormatInfo class
Can be created for Specific or Invariant culture, but NOT created for a neutral culture
Default set by CurrentCultures NumberFormat Property
Standard number format Specifiers
Uses NumberFormatInfo class:
c, C Currency f, F Fixed Pointn, N Number p, P Percent
Does NOT use NumberFormatInfo class:
d, D Decimal e, E Exponential x, X Hexadecimal g, G General r, R Round-trip
Can specify a particular culture
Val.ToString(N, new CultureInfo(fr-FR)) Table from the book: .NET Internationalization page 208Table from the book: .NET Internationalization page 208
50. Numbers/Currency Parsing Input Numeric .Parse method
Uses the CurrentCulture by default
Can specify a particular culture
NOTE: Formatting characters throw an exception UNLESS specify NumberStyles enumeration
Any all styles except for Hex
Currency - all styles except for Exponent and Hex
None - all styles except for Exponent and Hex
Number, Integer
Example
CultureInfo MyCultureInfo new CultureInfo(en-US);
String MyString = 123,456;
Int MyInt = int.Parse(MyString, All, MyCultureInfo); Source: Visual Studio 2005 - .NET Framework Developers Guide
see: Parsing Numeric Strings and NumberStyles EnumerationSource: Visual Studio 2005 - .NET Framework Developers Guide
see: Parsing Numeric Strings and NumberStyles Enumeration
51. DateTime - Output DateTime .ToString method
Culture formatted using DateTimeFormatInfo class
Can be created for Specific or Invariant culture, but NOT created for a neutral culture
Default set by CurrentCultures DateTimeFormat Property
Uses CurrentCulture by default:
ToString() ToShortDateString() ToLongDateString() ToShortTimeString() ToLongTimeString()
Specify particular culture:
ToString(string)
ToString(string, IFormatProvider)
52. ASP.NET Calendar Control ASP.NET Calendar control
Automatically localized
Defaults to the CurrentCulture
NOTE: Not CurrentUICulture
Issue: If CurrentCulture and CurrentUICulture are different,then the Calendar control will appear in the LANGUAGE of the CurrentCulture A brief discussion can be found in the book .NET Internationalizaiton pages 129-30A brief discussion can be found in the book .NET Internationalizaiton pages 129-30
53. DateTime Parsing Input DateTime.Parse related methods
.Net Framework 1.1, 2.0: Parse ParseExact
.Net Framework 2.0: TryParse TryParseExact
Example: CultureInfo MyCultureInfo new CultureInfo(de-DE);
String MyString = 12 Juni 2002;
DateTime MyDateTime = DateTime.Parse(MyString, MyCultureInfo); Briefly discussed in the book: .NET Internationalization Pages: 204-5
Briefly discussed in the book: .NET Internationalization Pages: 204-5
54. Suggested References Books
Inside Microsoft SQL Server 2005: The Storage Engine pp 11-14 by: Kalen Delaney ISBN: 0735621055
.NET Internationalization -- by Guy Smith Ferrier ISBN: 0321341384
Core Internet Application Development with ASP.NET 2.0 by: Randy Connolly ISBN: 0321419502 Briefly discussed in the book: .NET Internationalization Pages: 204-5
Briefly discussed in the book: .NET Internationalization Pages: 204-5