Microsoft Commerce Server 2000: Developing an International Site
This chapter describes best practices for offering multiple languages and currencies when you develop a site for an international audience. Your goal should be to make it easy for your customers to change language or currency at any time without losing context (that is, without being redirected to another page that contains different content). There are several ways to implement multiple languages and currencies. Which one you choose depends on your preferences and on project constraints.
The Microsoft Commerce Server 2000 sample site, a chocolate shop named Sweet Forgiveness, located on the Commerce Server 2000 Resource Kit CD. The Sweet Forgiveness site is multilingual and supports multiple currencies. It incorporates several of the methods described in this chapter.
Using Multiple Languages
Most companies would benefit from the ability to offer customers a choice of languages in which to interact with their site. However, many companies either ignore the issue or address it by deploying several versions of their site. For example, Amazon.com provides several versions of its site (Amazon.de and Amazon.nl).
If all versions of a site could be updated simultaneously, having multiple versions would not be a problem. However, in most cases, each version must be updated separately, which can cause the versions to differ significantly. For example, the English version of Amazon.com is much richer in functionality than the German and Dutch versions. Such significant differences can cause confusion for the project team and make the site difficult to manage. This section discusses ways to create a single, multilingual site.
There are two types of language-dependent strings used in e-commerce sites:
Site information (including HTML content in advertisements and discount descriptions)
Product information strings are the collection of language-dependent properties pertaining to products, such as name and description. Product information should be stored in the product catalog and should be available in all the languages your site supports because a multilingual product catalog is much easier to manage than separate catalogs for each language.
To manage language-dependent properties, simply adjust your code for each property to identify the language in which it is to be displayed. For example, your product might contain a property called short_description, which you want to display in English, French, and Dutch. To do this, you can rename short_description to short_description_en for the English version, short_description_fr for the French version, and* short_description_nl* for the Dutch version. When you display the product description, you can then adapt your code to select property **short_description plus the language code (en* *for English, fr for French, or nl for Dutch). The language code can be a parameter entered by the user or a property of the user profile.
Site information is the collection of strings that the site must display, such as "Product of the Week," "Search," and "OK." You can store the whole set of displayable strings in different languages in a database or in an Extensible Markup Language (XML) file. XML is the better choice because it's more portable. For example, you can send an XML file to a translator by e-mail, if necessary. For an example of how to use an XML file to store displayable strings in different languages, see the Rc.xml file in the Sweet Forgiveness site, which contains all its site information in strings.
The Global.asa file reads the XML file when the application starts. The strings are stored in the Commerce Server MessageManager object, which has application scope, thus ensuring that every server in your Web farm has its own copy of the string set for every language.
When a string must be displayed on the site, you can retrieve it from the MessageManager object with the following method call:
To speed up page execution, you can store strings that are displayed often, like menu bars (which are really concatenations of individual strings), in the CacheManager object for later retrieval. When you do this, the MessageManager object has to look them up only once.
You can use the same technique for other displayable strings, such as descriptions of discounts that you can't change in Commerce Server Business Desk.
The Commerce Server Solution Sites use the CacheManager object extensively. Essentially, the CacheManager object is an extended Dictionary object, which stores strings in name/value pairs.
If you examine the Solution Site code, you'll see that the name part of a name/value pair is called a cache key. If you decide to implement multilingual pages, you need to make cache key generation language-specific. You can do this with the following code:
sCacheKey = sCatalogName & sCategoryName & CStr(iPageNumber) & sLanguageCode
Using language-specific cache key generation makes the language code part of the cache key, so that the CacheManager object can detect which language to display.
Choosing the Language
A basic site scenario, often used in Europe, is to offer users a choice of language on the first visit. A user must click a link or a button to produce the site in the chosen language. The choice is then stored either as a property in the user profile or stored in a cookie on the user's computer so that the appropriate language appears immediately whenever the user revisits the site.
In another scenario, some sites try to guess a user's language preference by looking up the country extension from the IP address. For example, if the user is surfing from proxy.myprovider.co.uk (a U.K.-based provider), they assume that the user speaks English. This is often a convenient strategy, but it is not necessarily the most accurate. For example, many tourists browse the Web from cybercafs when they visit other countries. Other users browse from a .com, .net, or similar address, that doesn't have any obvious relationship to a particular language.
In a third scenario, your site can check the default language setting for users who use Microsoft Internet Explorer. The drawback to this scenario is that many users install the English version of Internet Explorer and then don't change the language settings, even though English might not be their native language. The issue of cybercafs arises in this scenario, too. If a cybercaf using Internet Explorer sets local language parameters, your site will assume that travelers logging in from that location want to view your pages in that language, rather than their own.
The best solution for most sites is probably to use the first scenario: to let the user choose a language, which is then saved in the user's profile. The next time the user logs in from any location, the site will automatically switch to the user's preferred language.
Multilingual sites should enable the user to change from one language to another on every page. The Sweet Forgiveness sample site does this with a drop-down list from which users can select a new language on any page on the site. Some sites display images of national flags that users can click to select the corresponding language.
Some multilingual sites allow changes in language only on the site home page, which means that users must return to the home page from other locations in the site to select a new language. This method is easy to implement, but less user-friendly than letting users change languages on any page to retain the context of the operation being performed.
There are four ways to encode language context:
Use a client-side cookie to store the active language code
Encode the language code in the URL
Store the language preference in the user profile
Use pre-generated pages
The method you use depends on project constraints and developer preferences.
Using a Client-Side Cookie with Language Codes
Using a client-side cookie is the easiest way to encode a language context, where permissible. To do this, you simply store a language code (en, fr, nl, and so on) in the cookie and read the cookie on every page that displays language-dependent strings. You can even make the cookie persistent by having it expire on some date far in the future, such as January 1, 2100, so that the site is always aware of a user's language (assuming that the user agrees to make the cookie persistent, of course).
It is best to use this technique only in situations where you can control cookie acceptance, such as proof-of-concept or company-internal projects. If there is a single user whose browser doesn't support cookies, such as a microbrowser in a cell phone, this technique will fail.
Encoding the Language Code in the URL
You can embed the language code in the URL, similar to the way in which the Solution Sites generate the session ID ticket. This means adapting the GenerateURL function to add the language code to every link you create, so that the site displays the correct language. For example, you have to call GenerateURL for every link so that:
Every page can then simply read the lang parameter.
Note You can't encode the language code with static HTML pages, because HTML pages can't pass any input parameters to other pages.
Storing the Language Preference in the User Profile
Another option for encoding language preferences is to keep a user's language in the user profile. Doing this requires that you add a language property to the user profile, which you must then update if a user changes languages. This is a cost-effective method of storing language preferences, because the only performance cost involved is retrieving and updating the profile.
Using Pre-Generated Pages
If your site contains mostly static HTML pages, then using pre-generated pages is another option for encoding language on your site. Pre-generated pages don't have to pass language identification to other pages, because the context of the pages (the directory that the pages are in) provides that capability. Pre-generated pages can link to other pages without providing language information. In addition, pre-generated pages don't have to read cookies, URL parameters, or user profiles to determine which language to display. You can even render pre-generated pages in static HTML.
To pre-generate your pages in all the languages you support, you can put all your pages in a /source directory and mark all strings that can be pre-generated with delimiters in your ASP code. For example, you might specify the Search button as:
<INPUT TYPE=SUBMIT VALUE="[[=Search]]">
In this fragment, [[=Search]] is a mnemonic for a word that will be translated. You must write a page generator that reads all the pages in the /source directory, looks up the delimited mnemonics using the MessageManager object, translates them, and saves the translated pages in a language-specific directory. Using our example of a site supporting English, French, and Dutch, you would read pages from /source and generate pages in the /en, /fr and /nl directories. This process can be automated to run once or twice a day, or whenever you update your site.
The page pre-generation approach saves time at run time and does not rely on the CacheManager object. In addition, it can significantly boost performance if your site has many static pages (pages that perform no logic other than to call the MessageManager object to look up strings) because now those pages can become truly static HTML pages rather than ASP pages. Putting those static pages on dedicated servers that serve only static content can enhance performance even further.
Using Multiple Currencies
The issues related to supporting multiple currencies are similar to, but simpler to solve than, the multilingual issues. You can support many currencies and let users switch back and forth between them, or you can display prices in all currencies at the same time. For some e-commerce sites, displaying prices in multiple currencies at the same time might be useful, but for the majority of sites, especially business-to-consumer (B2C) sites, the first method is easier.
You should store product pricing information in only one currency (the reference currency), if possible. For example, you can store your prices in U.S. dollars or European euros, and then recalculate prices in other currencies in real time, as needed. In order to recalculate prices based on the reference currency, you need an exchange rate table that specifies the rates for other currencies in comparison to the reference currency. The exchange rate table should contain the following fields:
International Standards Organization (ISO) currency code
The following example shows what an exchange rate table might look like.
ISO currency code
USD (U.S. dollar)
UKP (U.K. pound sterling)
BEF (Belgian franc)
EUR (European euro)
When your site displays a price, it recalculates the price based on the exchange rate and displays it with the associated currency symbol and display format.
Important If you store search results and product detail pages with the CacheManager object, you must make the currency part of the cache key or you will retrieve the wrong results when you try to display pricing in a different currency.
Different Prices for Different Locales
Some projects require different pricing for different locales. For example, a specific car might cost DM 100,000 in Germany, but only $40,000 in the U.S. However, that is locale-specific pricing, not currency-specific pricing. A German customer living in the U.S. should be charged the same price for the car, whether it is viewed in Deutsche Marks or U.S. dollars.
Different prices for different locales will, in most cases, require explicit pricing in the product properties, requiring you to keep several prices in your catalogs. You can do this by creating custom catalogs with the Catalog Editor module in Business Desk, or you can add locale-specific pricing properties to your catalog schema. The goal is to create inviting, market-oriented pricing that customers find appealing. For example, instead of simply multiplying a U.S. item price of $9.95 by a conversion factor, which can produce an odd price in Belgian francs (such as 457 francs), it is better to create a custom catalog for Belgium that contains a price tailored to the Belgian market (such as 450 francs).
Different Discounts for Different Locales
The notion of providing different discounts for different locales is similar to maintaining different pricing for different locales. However, locale-specific discounting does not require custom catalogs or multiple price properties. Instead, you can set up the Commerce Server Purchase pipeline and Content Selection pipeline to perform different discounts based on locale. This is not a currency-related issue, although at first glance it might look like one. For more information about Commerce Server pipelines, see Commerce Server 2000 Help.
The issues associated with changing currency are similar to the issues associated with changing language. The Sweet Forgiveness sample site contains a drop-down list from which users can choose currency in the same manner that they choose language. For the purposes of demonstration, the currency is always passed through the URL, as is the language.
You can provide an active currency in any of the following ways:
Encode the currency code in the URL. Use the same GenerateURL function that you use to change languages to include the active currency.
Store the currency code in the user profile. Storing the appropriate currency code in the user profile is an option, but every page that displays currency information then needs to invoke the user profile. If a user's profile data is already cached, this is a reliable and speedy method. The user's settings are then available from any location.
Configuring International Locale Settings
You can set up a site to use a different language from your development language. For example, you might develop your site in English, but want to use a copy of your English site to set up a French site. To set up a site using a different language:
Set the Windows 2000 system locale. In the Control Panel, set the options in Regional Options for the new locale. You must set locale separately for each computer and enable display and input of text in a given code page, as well as define default settings specific to the locale, such as currency, numeric format, and date and time formats.
Set up SQL Server collation settings. SQL Server collation settings are set when you set up SQL Server and you can't reconfigure them after installation. The collation settings determine which code page and sort orders will be accepted by the database for non-Unicode data. (The database schema determines whether or not the data is Unicode.)
Change the following Commerce Server site properties in Commerce Server Manager, using the App Default Config resource:
Site default locale
Page encoding charset
Unit of Measure for Weight
Currency: Base currency locale
Currency: Base currency code
Currency: Base currency symbol
If you plan to display more than one currency, you also need to configure the following properties for each additional currency:
Currency: Alternate currency options
Currency: Alternate currency conversion rate
Currency: Alternate currency locale
Currency: Alternate currency code
Currency: Alternate currency symbol
Currency: Currency display order options
For more information about configuring the App Default Config resource, see the "Configuring App Default Config Resource Properties" topic in Commerce Server 2000 Help.
After the Windows system locale is set up, SQL Server will default to the corresponding collation when you set it up. (Code page and sort orders match the locale.) When you set up Commerce Server, the Commerce Server databases support the code page you have configured. You can change any of the settings in the App Default Config resource in Commerce Server Manager.
After you unpack Business Desk or use one of the Solution Sites, the following site configuration properties are based on the system locale and should not need to be changed:
Site default locale (formats for numbers and dates).
Base currency locale.
Note The Base currency symbol and Base currency code properties are not set the same way.
Page encoding charset (set to the default charset that supports the language associated with the system locale). The encoding charset is used in Business Desk header files to set the charset for each page.
If you unpack a localized site with Commerce Server Site Packager on a system configured for the same locale, you shouldn't have to change any settings, unless you are displaying multiple currencies. All other settings are included in the Site Packager package. Be sure to review all settings before publishing your site.
For example, if you install an English site on a Korean system, you can enter Korean language characters into Business Desk without making any other changes.
If, however, you want to run a site in a different language on a system configured for your development language, such as a French site on an English system, you need to reconfigure the following settings:
Set Default site locale, Base currency locale, and Page encoding charset properties to French
In the BDHeader.asp and BDXMLHeader.asp files:
Remove "<%@ LANGUAGE=VBSCRIPT%>"
Uncomment "<%'@ LANGUAGE=VBSCRIPT CODEPAGE=1252 %>" and set the code page to the correct value for French
Note The Catalogs modules use the Base currency symbol and Base currency code properties when creating currency properties.