Notes from Michele Leroux Bustamante's TechEd 2004 break-out session "Building Applications with Globalization in Mind." (The slides and code for this talk should be available from her blog; see the comments for a direct link.) Michele is a globalization expert and has written an article on said topic on MSDN online (see Globalization Architecture for ASP.NET). For more information on globalization check out the Ask Dr. International or Microsoft .NET Internationalization sections on MSDN. The following is an outline of Michele's talk.
- What is Globalization? (Separating culture dependencies from code; content translation).
- Locale / Culture is represented by a language code and country code (i.e., en-US, en-UK, es-EC, etc.). There are ISO codes for language and country. RFC 3066 specifies tags for identifying languages.
- What to Localize and How to Store Localized Content?
- Static content - menu captions, control captions, Web page content, etc.
- Dynamic content - content populated at runtime. Need to have location of content to be organized by culture, and things like queries or filenames may differ based on culture.
- Things to consider:
- Windows vs. Web app
- How often the content changes
- Where to place culture-specific information (resource files, XML files, database)
A Windows Forms assembly contains resource information. We can also have satelite assemblies that store resource information for a particular culture. These satelite assemblies can be dropped in independent of recompiling the application. In addition to satellite assemblies, some content will likely need to be placed in a database. The database table names should be named according to the ISO standard country/language codes - perhaps by suffixing the table name with code.
For Web apps, typically a site's pages are duplicated for globalized apps. That is, a set of Web pages for each locale supported. Usually implemented as subdirectories - www.yoursite.com/en/*, www.yoursite.com/es/*, etc. These directories would contain locale-specific translations, images, etc. A better approach is to use a single content base with satelite assemblies that contain the locale-specific information.
- What are .NET Resources?
- Resources are generated via an XML resource file (.resx).
- Automatically generated by VS.NET for each Windows Form and Web Form
- By default, compiled and embedded in project assembly
- Can add custom resources to the project
- Can build assemblies that contain shared resources
- Can manually edit the .resx files via VS.NET
- The resource information is stored in the assembly's manifest - can view this information via ILDASM.
- Localizing Windows Forms applications
- Can set a WinForm to Localizable via the Properties pane. This adds a
ResourceManager in the code section.
- Can also specify the language via the Language option in the Forms' properties pane.
- The invariant culture is stored in the assembly - culture-specific information is stored in satelite assemblies. The satelitte assemblies are in appropriately named folders in the same directory as the project assembly.
- Satelite assemblies contain only resources - no code.
- Runtime follows a "resource fallback process" to find closest match - i.e., en-US rolls back to en rolls back to the invariant culture.
- In addition to satelite assemblies with locale-specific information, could also have other assemblies with common error messages. To create these, build a Class Library project with no code, just resource information.
- VS.NET / runtime are very picky on resource file naming conventions.
- The satelite assembly used depends on the culture setting of the executing thread's culture information.
- Can use the NeutralResourcesLanguageAttribute attribute to specify a default resource rather than relying on the runtime's fallback technique.
- WinForms control properties automatically sotred in embedded resources. Allows translators toedit individual form layout without touching your code. Other content can be stored in shared resources.
- Accessing Resources via
System.Resources.ResourceManager
- Access specific resource type based on a Form, strings, errors, etc. Specify the typeof ResourceManager and then can request resource entries by key name.
- The
GetString()/GetObject() methods gets the specific resource by name using the fallback technique. Can also use GetResourceSet() to get all resources for a particular culture.
- The current thread's culture setting dictate resource selection via the
CurrentUICulture and CurrentCulture properties. CurrentUICulture touches the satelite assembly to load resources; CurrentCulture does not access resource information, but dictates how things like date/time information is formatted, how currency is formatted, etc.
- Localizing ASP.NET Web Applications
- Option #1: Duplicate Content
- Facilitate rapid 1.0 release, deal with translation later
- Translate content for each culture in Web Forms, User Controls, HTML pages, XML files, etc.
- Redirect user to localized set of pages via browser's accept language HTTP header
- Duplicate content is error prone, since translators must edit content source.
- Typically implemented via culture-specific directories - www.yoursite.com/en/*, www.yoursite.com/es/*, etc.
- Can set culture and UI culture settings via
<globalization> element in maching.config/Web.config; can also do it on a page-by-page basis via the @Page directive
- Option #2: Single Content Base
- One code base; low impact on future translations
- Dynamic page content sotring locale-specific information in resource files, databases, XML files, etc.
- XML resource files provided for
Global.asax and each Web Form - embedded in main assembly. Michele recommends placing static page content in database rather than in resource for each Web page.
- Browsers send an
Accept-Language HTTP header; can use this to set the current culture on the thread rendering the ASP.NET page. Might also want to let user select culture, to override browser setting. Need to reset the thread's culture on each and every trip to the server.
Another great talk from Michele. Being an ASP.NET guy, I was most interested in the globalization for ASP.NET applications. The track looked at both WinForms and Web Forms applications, but focused more on WinForms, unfortunately (for me). Check out the blog's comments for a direct link to the slides and code.