Building a global Internet application that supports different locales requires good development practices. A locale refers to a national language and the region in which the language is spoken. The application itself must be aware of user locale preferences and present content following the cultural convention expected by the user. It is important to present data with appropriate locale characteristics, such as using the correct date and number formats. Oracle Database is fully internationalized to provide a global platform for developing and deploying global applications.
This chapter discusses global application development in a Java and Oracle Database environment. It addresses the basic tasks associated with developing and deploying global Internet applications, including developing locale awareness, constructing HTML content in the user-preferred language, and presenting data following the cultural conventions of the user locale.
This chapter has the following topics:
Global Internet applications must be aware of the user locale. Locale-sensitive functions, such as date, time, and monetary formatting, are built into programming environments such as Java and SQL. Applications can use locale-sensitive functions to format the HTML pages according to the cultural conventions of the user locale.
Different programming environments represent locales in different ways. For example, the French (Canadian) locale is represented as follows:
Environment | Representation | Locale | Explanation |
---|---|---|---|
Java | Java locale object | fr_CA |
Java uses the ISO language and country code.
|
SQL and PL/SQL | NLS_LANGUAGE and NLS_TERRITORY parameters |
NLS_LANGUAGE ="CANADIAN FRENCH"
|
See also: Chapter 8 "Working in a Global Environment" in the Oracle Database Express Edition 2 Day Developer Guide. |
Table 9-1 shows how some of the commonly used locales are defined in Java and Oracle environments.
Table 9-1 Locale Representation in Java, SQL, and PL/SQL Programming Environments
Locale | Java | NLS_LANGUAGE, NLS_TERRITORY |
---|---|---|
Chinese (P.R.C) |
|
|
Chinese (Taiwan) |
|
|
English (U.S.A) |
|
|
English (United Kingdom) |
|
|
French (Canada) |
|
|
French (France) |
|
|
German (Germany) |
|
|
Italian (Italy) |
|
|
Japanese (Japan) |
|
|
Korean (Korea) |
|
|
Portuguese (Brazil) |
|
|
Portuguese (Portugal) |
|
|
Spanish (Spain) |
|
|
When writing global applications across different programming environments, the user locale settings must be synchronized between environments. For example, Java applications that call PL/SQL procedures should map the Java locales to the corresponding NLS_LANGUAGE
and NLS_TERRITORY
values and change the parameter values to match the user locale before calling the PL/SQL procedures.
The Oracle Globalization Development Kit (GDK) provides the LocaleMapper
class. It maps equivalent locales and character sets between Java, IANA, ISO, and Oracle. A Java application may receive locale information from the client that is specified in the Oracle locale name. The Java application must be able to map to an equivalent Java locale before it can process the information correctly.
Example 9-1 shows how to use the LocaleMapper
class.
Example 9-1 Mapping from a Java Locale to an Oracle Language and Territory
Locale locale = new Locale("fr", "CA"); String oraLang = LocaleMapper.getOraLanguage(locale); String oraTerr = LocaleMapper.getOraTerritory(locale);
The GDK is a set of Java application programming interfaces (APIs) that provide Oracle application developers with the framework to develop globalized Internet applications. The GDK complements the existing globalization features in Java. It provides the synchronization of locale behaviors between a middle-tier Java application and the Oracle database server.
In a global environment, your application may have to accept users with different locale preferences. Determine the preferred locale of the user. Once that is known, the application should construct HTML content in the language of the locale, and follow the cultural conventions implied by the locale.
One of the most common methods in determining the user locale, is based on the default ISO locale setting of the browser of the user. Usually a browser sends locale preference settings to the HTTP server with the Accept-Language
HTTP header. If this header is set to NULL
, then there is no locale preference information available and the application should ideally fall back to a predefined application default locale.
Both JSP pages and Java Servlets can use calls to the Servlet API to retrieve the Accept-Language
HTTP header as shown in Example 9-2.
Example 9-2 Determining User Locale in Java Using the Accept-Language Header
String lang = request.getHeader("Accept-Language") StringTokenizer st = new StringTokenizer(lang, ",") if (st.hasMoreTokens()) userLocale = st.nextToken();
This code gets the Accept-Language
header from the HTTP request, extracts the first ISO locale, and uses it as the user-desired locale.
A Java locale object represents the locale of the corresponding user in Java. The Java encoding used for the locale is required to properly convert Java strings to and from byte data. You must consider the Java encoding for the locale if you make the Java code aware of a user locale. There are two ways to make a Java method sensitive to the Java locale and encoding:
Using the default Java locale and default Java encoding for the method
Explicitly specifying the Java locale and Java encoding for the method
When developing a global application, it is recommended to take the second approach and explicitly specify the Java locale and Java encoding that correspond to the current user locale. You can specify the Java locale object that corresponds to the user locale, identified by user_locale
, in the getDateTimeInstance
method as in Example 9-3.
The encoding of an HTML page is important information for a browser and an Internet application. You can think of the page encoding as the character set used for the locale that an Internet application is serving. The browser needs to know about the page encoding so that it can use the correct fonts and character set mapping tables to display the HTML pages. Internet applications need to know about the HTML page encoding so they can process input data from an HTML form.
Instead of using different native encodings for the different locales, it is recommended that UTF-8 (Unicode encoding) is used for all page encodings. Using the UTF-8 encoding not only simplifies the coding for global applications, but it allows for multilingual content on a single page.
This section includes the following topics:
There are two ways to specify the encoding of an HTML page, one is in the HTTP header, and the other is in the HTML page header.
Specifying the Encoding in the HTTP Header
Include the Content-Type
HTTP header in the HTTP specification. It specifies the content type and character set as shown in Example 9-4.
Example 9-4 Specifying Page Encoding in the HTTP Specification
Content-Type: text/html; charset=utf-8
The charset
parameter specifies the encoding for the HTML page. The possible values for the charset
parameter are the IANA names for the character encodings that the browser supports.
Specifying the Encoding in the HTML Page Header
Use this method primarily for static HTML pages. Specify the character encoding in the HTML header as shown in Example 9-5.
Example 9-5 Specifying Page Encoding on an HTML Page
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
The charset
parameter specifies the encoding for the HTML page. As with the Content-Type
HTTP Header, the possible values for the charset parameter are the IANA names for the character encodings that the browser supports.
You can specify the encoding of an HTML page in the Content-Type
HTTP header in a JavaServer Pages (JSP) file using the contentType
page directive. For example:
<%@ page contentType="text/html; charset=utf-8" %>
This is the MIME
type and character encoding that the JSP file uses for the response it sends to the client. You can use any MIME
type or IANA character set name that is valid for the JSP container. The default MIME
type is text/html
, and the default character set is ISO-8859-1. In the above example, the character set is set to UTF-8. The character set of the contentType
page directive directs the JSP engine to encode the dynamic HTML page and set the HTTP Content-Type
header with the specified character set.
For Java Servlets, you can call the setContentType
method of the Servlet API to specify a page encoding in the HTTP header. The doGet
function in Example 9-6 shows how you can call this method.
Example 9-6 Specifying Page Encoding in Servlets Using setContentType
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // generate the MIME type and character set header response.setContentType("text/html; charset=utf-8"); ... // generate the HTML page Printwriter out = response.getWriter(); out.println("<HTML>"); ... out.println("</HTML>"); }
You should call the setContentType
method before the getWriter
method because the getWriter
method initializes an output stream writer that uses the character set specified by the setContentType
method call. Any HTML content written to the writer and eventually to a browser is encoded in the encoding specified by the setContentType
call.
Making the user interface available in the local language of the user is one of the fundamental tasks related to globalizing an application. Translatable sources for the content of an HTML page belong to the following categories:
Text strings hard-coded in the application code
Static HTML files, images files, and template files such as CSS
Dynamic data stored in the database
This section discusses externalizing translatable content in the following:
You should externalize translatable strings within Java Servlets and JSP pages into Java resource bundles so that these resource bundles can be translated independent of the Java code. After translation, the resource bundles carry the same base class names as the English bundles, but with the Java locale name as the suffix. You should place the bundles in the same directory as the English resource bundles for the Java resource bundle look-up mechanism to function properly.
See Also:
Sun Microsystems documentation about Java resource bundles athttp://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html
Because the user locale is not fixed in multilingual applications, they should call the getBundle
method by explicitly specifying a Java locale object that corresponds to the user locale. The Java locale object is called user_locale
in the following example:
ResourceBundle rb = ResourceBundle.getBundle("resource", user_locale); String helloStr = rb.getString("hello");
The above code will retrieve the localized version of the text string, hello
, from the resource bundle corresponding to the desired locale of the user.
See Also:
For more information on creating resource bundles in Java, refer to Localizing Text on JSP Pages in JDeveloper.Static files such as HTMLs and GIFs are readily translatable. When these files are translated, they should be translated into the corresponding language with UTF-8 as the file encoding. To differentiate between the languages of the translated files, the static files of different languages can be staged in different directories or with different file names.
Dynamic information such as product names and product descriptions are most likely stored in the database regardless of whether you use JSP pages or Java Servlets. In order to differentiate between various translations, the database schema holding this information should include a column to indicate the language of the information. To select the translated information, you must include the WHERE
clause in your query to select the information in the desired language of the query.
Data in the application needs to be presented in a way that conforms to user expectation, if not, the meaning of the data can sometimes be misinterpreted. For example, '12/11/05' implies '11th December 2005' in the United States, whereas in the United Kingdom it means '12th November 2005'. Similar confusion exists for number and monetary formats, for example, the period (.) is a decimal separator in the United States, whereas in Germany, it is used as a thousand separator.
Different languages have their own sorting rules, some languages are collated according to the letter sequence in the alphabet, some according to stroke count in the letter, and there are some languages which are ordered by the pronunciation of the words. Presenting data that is not sorted according to the linguistic sequence that your users are accustomed to can make searching for information difficult and time-consuming.
Depending on the application logic and the volume of data retrieved from the database, it may be more appropriate to format the data at the database level rather than at the application level. Oracle Database offers many features that help you to refine the presentation of data when the user locale preference is known. The following sections include examples of locale-sensitive operations in SQL:
There are three different date presentation formats in Oracle Database. These are standard, short, and long dates. Example 9-7 illustrates the difference between the short data and long date formats for both United States and Germany.
Example 9-7 Difference Between Date Formats by Locale (United States and Germany)
SQL> ALTER SESSION SET NLS_TERRITORY=america NLS_LANGUAGE=american; Session altered. SQL> SELECT employee_id EmpID, 2 SUBSTR(first_name,1,1)||'.'||last_name "EmpName", 3 TO_CHAR(hire_date,'DS') "Hiredate", 4 TO_CHAR(hire_date,'DL') "Long HireDate" 5 FROM employees 6* WHERE employee_id <105; EMPID EmpName Hiredate Long HireDate ---------- --------------------------- ---------- ----------------------------- 100 S.King 06/17/1987 Wednesday, June 17, 1987 101 N.Kochhar 09/21/1989 Thursday, September 21, 1989 102 L.De Haan 01/13/1993 Wednesday, January 13, 1993 103 A.Hunold 01/03/1990 Wednesday, January 3, 1990 104 B.Ernst 05/21/1991 Tuesday, May 21, 1991 SQL> ALTER SESSION SET SET NLS_TERRITORY=germany NLS_LANGUAGE=german; Session altered. SQL> SELECT employee_id EmpID, 2 SUBSTR(first_name,1,1)||'.'||last_name "EmpName", 3 TO_CHAR(hire_date,'DS') "Hiredate", 4 TO_CHAR(hire_date,'DL') "Long HireDate" 5 FROM employees 6* WHERE employee_id <105; EMPID EmpName Hiredate Long HireDate ---------- --------------------------- -------- ------------------------------ 100 S.King 17.06.87 Mittwoch, 17. Juni 1987 101 N.Kochhar 21.09.89 Donnerstag, 21. September 1989 102 L.De Haan 13.01.93 Mittwoch, 13. Januar 1993 103 A.Hunold 03.01.90 Mittwoch, 3. Januar 1990 104 B.Ernst 21.05.91 Dienstag, 21. Mai 1991
Example 9-8 illustrates the differences in the decimal character and group separator between the United States and Germany.
Example 9-8 Difference Between Number Formats by Locale (United States and Germany)
SQL> ALTER SESSION SET SET NLS_TERRITORY=america; Session altered. SQL> SELECT employee_id EmpID, 2 SUBSTR(first_name,1,1)||'.'||last_name "EmpName", 3 TO_CHAR(salary, '99G999D99') "Salary" 4 FROM employees 5* WHERE employee_id <105 EMPID EmpName Salary ---------- --------------------------- ---------- 100 S.King 24,000.00 101 N.Kochhar 17,000.00 102 L.De Haan 17,000.00 103 A.Hunold 9,000.00 104 B.Ernst 6,000.00 SQL> ALTER SESSION SET SET NLS_TERRITORY=germany; Session altered. SQL> SELECT employee_id EmpID, 2 SUBSTR(first_name,1,1)||'.'||last_name "EmpName", 3 TO_CHAR(salary, '99G999D99') "Salary" 4 FROM employees 5* WHERE employee_id <105 EMPID EmpName Salary ---------- --------------------------- ---------- 100 S.King 24.000,00 101 N.Kochhar 17.000,00 102 L.De Haan 17.000,00 103 A.Hunold 9.000,00 104 B.Ernst 6.000,00
Spain traditionally treats 'ch', 'll' as well as 'ñ' as letters of their own, ordered after c, l and n respectively. Example 9-9 illustrates the effect of using a Spanish sort against the employee names Chen and Chung.
Example 9-9 Variations in Linguistic Sorting (Binary and Spanish)
SQL> ALTER SESSION SET NLS_SORT=binary; Session altered. SQL> SELECT employee_id EmpID, 2 last_name "Last Name" 3 FROM employees 4 WHERE last_name LIKE 'C%' 5* ORDER BY last_name EMPID Last Name ---------- ------------------------- 187 Cabrio 148 Cambrault 154 Cambrault 110 Chen 188 Chung 119 Colmenares 6 rows selected. SQL> ALTER SESSION SET NLS_SORT=spanish_m; Session altered. SQL> SELECT employee_id EmpID, 2 last_name "Last Name" 3 FROM employees 4 WHERE last_name LIKE 'C%' 5* ORDER BY last_name EMPID Last Name ---------- ------------------------- 187 Cabrio 148 Cambrault 154 Cambrault 119 Colmenares 110 Chen 188 Chung 6 rows selected.
The NLS_LANGUAGE
parameter also controls the language of the database error messages that are returned from the database. Setting this parameter prior to submitting your SQL statement will ensure that local language-specific database error messages will be returned to the application.
Consider the following server message:
ORA-00942: table or view does not exist
When the NLS_LANGUAGE
parameter is set to French, the server message appears as follows:
ORA-00942: table ou vue inexistante
See Also:
"Working in a Global Environment" chapter in the Oracle Database Express Edition 2 Day DBA for a discussion of globalization support features within Oracle Database.Your Java application can make use of resource bundles, to provide different localized versions of the text used on your JSP pages.
Resource bundles contain locale-specific objects. When your program needs a locale-specific resource, such as some text to display on a page, your program can load it from the resource bundle that is appropriate for the current user locale. In this way, you can write program code that is largely independent of the user locale isolating the actual text in resource bundles.
In outline, the resource bundle technology has the following features:
Resource bundles belong to families whose members share a common base name, but whose names also have additional components that identify their locales. For example, the base name of a family of resource bundles might be MyResources
. A locale-specific version for German, for example, would be called MyResources_de
.
Each resource bundle in a family contains the same items, but the items have been translated for the locale represented by that resource bundle. For example, a String
used on a button might in MyResources
be defined as Cancel
, but in MyResources_de
as Abbrechen
.
You can make specializations for different resources for different countries, for example, for the German language (de
) in Switzerland (CH
).
To use resource bundles in your application, you must do the following:
Create the resource bundles.
In pages that have visual components, identify the resource bundles you will be using on the page.
For each item of text you want to display on your pages, retrieve the text from the resource bundle instead of using hard-coded text.
See Also:
Sun Microsystems documentation on resource bundles athttp://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html
In the sample application, resource bundles can be used in the following places:
Headings and labels on JSP pages. In this case, rather than entering text directly on the pages, you can use a scriptlet to find the text.
Values for buttons and other controls. In this case, set the value
property of the button to an expression that retrieves the text from the resource bundle
This section covers the following tasks:
To create a default resource bundle:
Create a new Java class called MyResources.java
, that extends class java.util.ListResourceBundle
.
Define the resource bundle class and methods to return contents as follows:
public class MyResources extends ListResourceBundle { public Object[][] getContents() { return contents; } static final Object[][] contents = { }; }
Add an entry for each item of text you need on your pages, giving a key and the text for that key. For example, in the following example, the comments indicate the strings that must be translated into other languages:
static final Object[][] contents = { // LOCALIZE THIS {"CompanyName", "AnyCo Corporation"}, {"SiteName", "HR Application"}, {"FilterButton", "Filter"}, {"UpdateButton", "Update"}, // END OF MATERIAL TO LOCALIZE };
The complete resource bundle class should look similar to that shown in Example 9-10.
Example 9-10 Creating a Resource Bundle Class
public class MyResources extends ListResourceBundle { public Object[][] getContents() { return contents; } static final Object[][] contents = { // LOCALIZE THIS {"CompanyName", "AnyCo Corporation"}, {"SiteName", "HR Application"}, {"FilterButton", "Filter"}, {"UpdateButton", "Update"}, // END OF MATERIAL TO LOCALIZE }; }
To globalize your application, you must create the locale-specific versions of the resource bundle for the different locales you are supporting, containing text for the items in each language.
To use the text defined in a resource bundle on your JSP pages:
Open the JSP page you want to work on in the Visual Editor, such as edit.jsp
.
Create a new line at the top of the page before the first heading and set the Style of the line to None
. Add a jsp:usebean tag to the new line. Enter myResources
as the ID, and hr.MyResources
as the Class. Set the Scope to session
, and click OK.
Drag a jsp:scriptlet to the page, where you want the resource bundle text to be displayed, for example in the heading for the page.
In the Insert Scriptlet dialog, enter the script for retrieving text from the resource bundle:
out.println(myResources.getString("CompanyName") + ": " + myResources.getString("SiteName"));
If there was text already displayed in the heading, you can remove it now.
If you select the Source tab below the Visual Editor, you should see code for the page similar to the following:
<h2 align="center"> <% = myResources.getString("CompanyName") + ": " + myResources.getString("SiteName")); %> </h2>
To use resource bundle text as the label for a button, double-click the button in the Visual Editor. In the button properties dialog, for the Value parameter of the button, enter a script similar to the following:
<% out.println(myResources.getString("UpdateButton"));%>
If you view the Source code for the page, you will see code similar to the following:
<input type="submit" value=<% out.println(myResources.getString("UpdateButton"));%> />
If you now run your application, you will see the text you defined in your resource bundle displayed on the page.