Anda di halaman 1dari 12

D

Appendix: Internationalization
In the time of globalization, when we talk about a new software product or application for users from different countries and region, the importance of making this product Global has increased manifold. The term Global can be used for those products which can support different languages, text formats, number formats, and currency formats that are being used in different regions in the world. In other words, our application should speak in many languages for the satisfaction of all users from different locales. In the current scenario, every new product designed and developed is first planned for its Internationalization. This helps in the adopting of locale-specific message and data formats by the application with less or no efforts. Java, Standard Edition, Platform (Java SE) provides a rich set of APIs to support the creation of global application. This appendix gives the reader a brief introduction to the terms like Internationalization and Localization and how to use APIs provided with Core Java platform for the Internationalization of a software product. The Internationalization APIs provided with Java SE can easily adapt different messages, number, date, and currency formats according to different country and region conventions.

Internationalization
In simple words, Internationalization can be defined as a process of enabling a software or application to adapt different country and region specific formats without any change in the code or any recompilation for the purpose. The term Internationalization is generally abbreviated as i18n as there are 18 characters between i and n. An internationalized application, with the help of locale-specific resources (localized data), can run worldwide with the same executable code and without any engineering changes in the application. The text messages and GUI component labels are not hardcoded in the program. They are bundled separately and can be dynamically obtained. The application does not require any recompilation for supporting new languages. All date, number, and currency formats conform to the region and language of the end user. Thus, the internationalized application can be easily localized. Lets now see what localization is.

Appendix D

Localization
The customization process of software for specific region and language by introducing locale-specific components is known as localization. It enables our application to adapt message, number, and date formats according to a given locale. Localization can be abbreviated as l10n, because the number of letters between l and n are 10. Localization is translating user interface elements, like label messages, icons, sound, etc. according to a locale. In addition to this, some other relevant changes to the application include change in number, date, and currency formats. The cultural sensitive sounds and pictures are also changed in localization. An application internationalized in a better way is always easy to localize for a new language and character encoding scheme.

Locale Class
A locale can be defined as a specific geographical, political, or cultural region. A locale can be represented by an instance of class java.util.Locale. All operations and services that take care of the locale are known as locale-sensitive operations, like getDataInstance(), getTimeInstance(), and getDateTimeInstance() of DateFormat class. An instance of Locale class describes a geographical or cultural region. This is one of the classes that provide you with all the help to internationalize an application for different locales. The Locale class defines number of constants that are useful for dealing with most of the common locales in the world. Table D.1 lists all of these constants. Some of these constants have been introduced in Java SE 6 to support new languages like Japanese. Table D.1: Locales Supported in Java SE 6
CANADA CHINESE FRENCH ITALIAN JAPANESE PRC TAIWAN US CANADA_FRENCH ENGLISH GERMAN ITALY KOREA ROOT TRADITIONAL_CHINESE CHINA FRANCE GERMANY JAPAN KOREAN SIMPLIFIED_CHINESE UK

Every constant is for a specific country or region and there is a unique Locale identifier for each of them. You can see the list of all supported locales for java.util and java.text functionality at http://java.sun.com/javase/6/docs/technotes/guides/intl/locale.doc.html. An object of Locale class can be created by using one of the following three constructors:
Locale(String language) Locale(String language, String country) Locale(String language, String country, String variant)

A Locale object created by using the first constructor represents a specific language, and in case of the last two variants of constructors, it represents specific country also. The arguments should consist of ISO-standard language and country code. The variant argument is used for providing auxiliary browser and vendor specific information.

Internationalization

The setDefault() method of Locale class sets a Locale object as the default Locale for this instance of JVM:
static void setDefault(Locale obj)

Some important methods of Locale class are shown in Table D.2. Table D.2: Methods of Locale class

Method
String getCountry() Static Locale getDefault() String getDisplayCountry() String getDisplayCountry (Locale inLocale) String getDisplayLanguage() String getDisplayLanguage (Locale inLocale) String getDisplayName() String getDisplayName (Locale inLocale) String getDisplayVariant() String getDisplayVariant (Locale inLocale) String getISO3Country()

Description
It returns the country code for this locale It returns the default locale for this instance of JVM It returns name for the locales country It returns a name for the locales country It returns a name for the locales language It returns a name for the locales language

It returns a name for the locale It returns a name for the locale It returns a name for the locales variant code. It returns a name for the locales variant It returns a three-letter abbreviation for this locales country It returns a three-letter abbreviation for this locales language It returns a list of all 2-letter country codes defined in ISO 3166 It returns a list of all 2-letter language codes defined in ISO 639 It returns the language code for this locale, which will either be the empty string or a lowercase ISO 639 code

String getISO3Language()

Static String[] getISOCountries() Static String[] getISOLanguages() String getLanguage()

Appendix D

Table D.2: Methods of Locale class

Method
String getVariant() Static void setDefault (Locale newLocale)

Description
It returns the variant code for this locale It sets the default locale for this instance of the Java Virtual Machine

The classes like Calender, GregorianCalender, DateFormat, and SimpleDateFormat operate in locale-sensitive manner, i.e. the output of their methods depends upon the Locale instance created and used. These types of classes are known as locale-sensitive. For example, the object of java.util.Calender class can be created by using getInstance() method and passing a Locale object passing into it as shown in the following lines:
Locale japLocale=new Locale("jp", "JP","JP"); Calendar cal=Calendar.getInstance(japLocale);

Locale-Sensitive Services
The classes of the java.text and java.util packages provide locale-sensitive services. These services can be extended implementing SPIs (Service Provider Interfaces) for locales. The localized symbols or names for Currency, Locale, and TimeZone classes can be added in java.util package and similarly the implementation of some classes, like BreakIterator, Collator, DateFormat, DateFormatSymbols, DecimalFormatSymbols, NumberFormat in the java.text package can be plugged in with the SPIs. So, this feature enables programmers to plug-in of locale-specific data and services and hence some third parties can implement most of the locale-sensitive classes in the java.text and java.util packages. The SPI implementation is based on a set of abstract classes and interfaces which can be implemented by service providers. The same class loading scheme is used to dynamically locate and load classes implementing SPIs. Table D.3 and Table D.4 shows the list of Service Provider Interfaces in java.util.spi and java.text.spi packages respectively. Table D.3: Service Provider Interfaces in java.util.spi package CurrencyNameProvider LocaleNameProvider LocaleServiceProvider TimeZoneNameProvider Table D.4: Service Provider Interfaces in java.text.spi package BreakIteratorProvider DateFormatProvider DecimalFormatSymbolsProvider CollatorProvider DateFormatSymbolsProvider NumberFormatProvider

Internationalization

For example, to provide a new type of NumberFormat object for a new locale to be supported, we can implement java.text.spi.NumberFormatProvider class by extending it and implementing its methods.

Localized Resources
The locale-sensitive classes must be capable of accessing resources which are customized for the locales they support. These customized resources contain locale-specific content which should be separated from the locale-independent part of the program. For example, we may have a number of customized files containing messages written in specific languages which can be accessed by programs dynamically according to the locale-specified.

ResourceBundle Class
ResourceBundle is an abstract class which represents a container of resources. For a specific locale, we can create subclasses of ResourceBundle containing some locale-specific resources. New instances of the ResourceBundle can be added to the system and new resources can also be added in an existing instance of ResourceBundle. Resources are being packaged as classes here and it helps in taking advantage of class loading mechanism of Java. ResourceBundle class helps in easy localization and translation of contents. We can handle multiple instances of ResourceBundle and so can handle multiple locales at once. These resources can be modified later easily.

Any local-specific resource can be loaded and used from the resource bundle according to the users locale. This approach helps programmer in writing code that is largely independent of users locale and separating locale-specific information into resource bundles.
Basically, a ResourceBundle is a set of related subclasses that share the same base name, say MyLabels. The characters following the base name are language code, country code, and variant of Locale. For example:
MyLables MyLabels_de MyLabels_en_US

The required resource can be used by using getBundle() method of ResourceBundle class in the following manner:
Locale locale= new Locale("en","US"); ResourceBundle labels = ResourceBundle.getBundle("MyLabel,locale);

The ResourceBundle has two subclasses, namely PropertyResourceBundle and ListResourceBundle. A PropertyResourceBundle is backed by a properties file. A property file is a plain text file containing editable text and these files are not part of Java source code. A ListResourceBundle class manages resources with a list which is easy to handle. Each ListResourceBundle is backed by a class file. Any locale-specific object can be stored in ListResourceBundle. A ResourceBundle is flexible and the obtaining of resource is independent of whether it is backed by class or some property files.

Appendix D

The ResourceBundle object consists of an array of key-value pairs. The key, which must be a String, is used to obtain the corresponding value from ResourceBundle. These values are locale-specific. Java SE 6 has introduced some new methods in java.util.ResourceBundle class. Now, we can pass an object of ResourceBundle.Control to the getBundle() method. The value from the ResourceBundle can be obtained by using getString() method passing its key as an argument. All keys can be retrieved as a Set by using the following two methods:
public Set keySet() protected Set handleKeySet()

The keySet() method returns all keys in the ResourceBundle and its parent bundles, while handleKeySet() method returns keys from this ResourceBundle only.

ResourceBundle.Control Class
ResourceBundle.Control is a nested class of ResourceBundle. All methods used by ResourceBundle.getBundle factory methods are defined in this inner class which helps in changing resource bundle loading behaviour. These methods can be overridden to support resource bundle formats, like XML. The new overloaded method getBundle() takes ResourceBundle.Control object as an argument. Without ResourcBundle.Control as an argument, the getBundle() method first tries to load a Java class and then tries to load properties files, if the class can not be located. But using ResouceBundle.Control as an argument, we can instruct our getBundle() method to load a Java class or a property file. Look at the following code lines showing how to create a ResourceBundle.Control object:
ResourceBundle.Control control= ResourceBundle.Control.getControl( ResourceBundle.Control.FORMAT_DEFAULT); or ResourceBundle.Control control= ResourceBundle.Control.getControl( ResourceBundle.Control.FORMAT_CLASS); or ResourceBundle.Control control= ResourceBundle.Control.getControl( ResourceBundle.Control.FORMAT_PROPERTIES);

You can create an object of ResourceBundle.Control class in these three ways. The first one gives the default implementation, i.e. class locating is attempted first before attempting to locate property file. With second type of control, the method getBundle() attempts to locate Java class only and with the third one, only a property file is located. The obtained control is passed to getBundle() method as shown here:
ResourceBundle rb=ResourceBundle.getBundle("MyLabel", locale,control);

Moreover, now we can extend ResourceBundle.Control class and override getFormats() and newBundle() methods and can write our own mechanism for loading key/value pairs. Now in the further topics, well show you how to perform internalization in Java.

Internationalization

Creating an Internationalized Program


Lets start with a program example which is internationalized for a set of locales. The output of the application will change according to the locale selected by the application at runtime. This example is a standard one which creates a fully internationalized program supporting different type of locales. The localized resources have been separated from the locale independent code by using the property files. The application uses a set of property file containing the messages in different languages and according to the locale selected, the message from appropriate property file is displayed. The locale-sensitive text is not hardcoded in the program and need not be recompiled again. The same executable can be used all over the world displaying the message in the language for that country or region.

Create a Set of Property Files


A property file contains data in plain text format and hence can be created by using any text editor. A property file consists of data specific to a locale. We are here creating a set of property files containing text messages in different languages. The messages are stored in property file with a key/value pair. The key, which must be a String, is used to obtain a particular message string from the file. Create the following text format property file with base name MessageBundle:
MessageBundle.properties msg1=Good Morning! How are you? msg2=I am fine. MessageBundle_en_US.properties msg1=Good Morning! How are you? msg2=I am fine.

Messages in the properties files can be translated into different languages without affecting the source code. A properties file for English (en) language and country United States (US) has been created with same base name, i.e. MessageBundle, following en for language and US for country. Similarly, a French translator can create a different properties file for French language (fr) and country France (FR) with name MessagesBundle_fr_FR.properties containing same messages from MessageBundle.properties but translated in French as shown in the following lines:
msg1=Bonjour ! Comment allez-vous ? msg2=Je suis trs bien.

The values at the right side of the messages, i.e. msg1, msg2, and msg3 are keys for different messages and they are same in all of the three files. It is the message which has been changed in different properties file. The name of the properties file is important and should be in basepropertiesfile_languagecode_countrycode.properties format. Same language and country codes are used in creating locale objects.

Create Locale Object


A Locale object represents a specific language and specific country. A Locale object can be created by passing a specific language code and country code to its constructors. The following statement defines how to create a Locale object representing language English (en) and country United States (US):

Appendix D

Locale locale = new Locale("en", "US");

Similarly, for language French (fr) and country France (FR), the locale object can be created as:
Locale locale = new Locale("fr", "FR");

A Locale object is just an identifier of a particular locale and this object can be passed to other localesensitive objects to perform tasks according to this locale.

Create a ResourceBundle
A ResourceBundle object contains locale-specific data and they are used to separate locale-sensitive date from the code. In our program, our ResourceBundle is supported by properties files containing text messages for different set of locales. A ResourceBundle can be created by using the following syntax:
ResourceBundle messages = ResourceBundle.getBundle("MessageBundle", locale);

The getBundle() method of ResourceBundle class returns a ResourceBundle object according to the locale passed. Remember, here the base properties file name is used as first argument.

Displaying Messages
After creating properties files, we write a program which creates a suitable Locale object according to the two passed parameters and creates a ResourceBundle and displays the messages from the suitable properties file by using getString(key) method. Following is the code for MyMessageDemo class (you can find this code file, MyMessageDemo.java on the CD):
import java.util.*; public class MyMessageDemo{ static public void main(String[] args) { String language; String country; if (args.length != 2) { language = new String("en"); country = new String("US"); } else { language = new String(args[0]); country = new String(args[1]); } Locale locale= new Locale(language, country); ResourceBundle messages=ResourceBundle.getBundle("MessageBundle",locale); System.out.println(messages.getString("msg1")); System.out.println(messages.getString("msg2")); } }

Internationalization

Put all the code files and properties files in a folder, say c:\i18n; compile this.java file and run it by using the different set of languages and country codes to see the customized messages displayed for different locales. Here is the output:
C:\i18n>java MyMessageDemo Good Morning! How are you? I am fine. C:\i18n>java MyMessageDemo en US Good Morning! How are you? I am fine. C:\i18n>java MyMessageDemo fr Fr Bonjour ! Comment allez-vous ? Je suis trs bien.

If this is the same output you get for the three different execution of the code then the program is an internationalized program. This can run for different locales and that is without any source code change and hence without any recompilation.

Handling Date and Time


Date and time is represented by a Date object and it can be easily displayed after converting it to a string. But the string here should be in a standard format to conform to the pattern used in a particular country or region. For example, the date can be displayed in dd/mm/yy or mm/dd/yy formats. There may be different formats for the time also. So, the importance of Locale object comes into frame which helps these locale-sensitive objects to function according to the end user of that particular region. The time and date can be displayed in various ways and in a locale-sensitive manner. The DateFormat class helps in formatting date and time according to the Locale object crated and used. The following code, DateTimeDemo.java (you can find this code file, DateTimeDemo.java in CD) displays different date formats for different locales:
import java.text.DateFormat; import java.util.Date; import java.util.Locale; public class DateTimeDemo { public static void main(String[] args) { Locale usLocale=new Locale("en", "US"); Locale frenchLocale=new Locale("fr", "FR"); DateFormat usFormatter=DateFormat.getDateInstance (DateFormat.DEFAULT, usLocale); DateFormat frenchFormatter=DateFormat.getDateInstance (DateFormat.DEFAULT, frenchLocale); DateFormat usTimeFormat=DateFormat.getTimeInstance (DateFormat.DEFAULT, usLocale); DateFormat frenchTimeFormat=DateFormat.getTimeInstance (DateFormat.DEFAULT, frenchLocale); Date today = new Date(); String usDate=usFormatter.format(today); String frenchDate=frenchFormatter.format(today); String usTime=usTimeFormat.format(today); String frechTime=frenchTimeFormat.format(today);

Appendix D System.out.println("Locale: "+usLocale.getDisplayCountry()); System.out.println("Date: "+usDate); System.out.println("Time: "+usTime); System.out.println("\nLocale: "+frenchLocale.getDisplayCountry()); System.out.println("Date: "+frenchDate); System.out.println("Time: "+frechTime); } }

Formatting date and time by using the DateFormat class is a two step process. First, a formatter is created by using getDateInstance() for date and getTimeInstance() for time. Both of these methods take a Locale object as an argument. The second step is to invoke a format() method on this formatter object, which returns a string containing formatted date or time. The output of DateTimeDemo is as follows:
C:\i18n>java DateTimeDemo Locale: United States Date: Feb 14, 2007 Time: 11:28:44 AM Locale: France Date: 14 fvr. 2007 Time: 11:28:44

Handling Number and Currencies


The Number and Currency formats also differ in different countries and regions. The class NumberFormat provides methods to format number and currencies according to the Locale object, i.e. they can operate in a locale-sensitive manner. The formatting with this class is similar to what we have observed with DateFormat class. The first step is to create a formatter by using getNumberInstance() for Number formatting and getCurrencyInstance() for Currency. The format() method invocation over these formatters returns a string after formatting Number or Currency, respectively. The following code for NumberCurrencyDemo (you can find this file, NumberCurrencyDemo.java on CD) class describes the use of NumberFormat class in the process of Internationalization of a source code:
import java.text.NumberFormat; import java.util.Locale; public class NumberCurrencyDemo { public static void main(String[] args) { String language; String country; Double amount = new Double(648927.843); Double currency=new Double(3866249.21); if (args.length != 2) { language = new String("en"); country = new String("US"); } else { language = new String(args[0]); country = new String(args[1]); } Locale locale=new Locale(language, country);

Internationalization NumberFormat formatter = NumberFormat.getNumberInstance(locale); NumberFormat formatter1=NumberFormat.getCurrencyInstance(locale); String amountStr = formatter.format(amount); String currencyStr=formatter1.format(currency); System.out.println(locale.getDisplayCountry()); System.out.println("Number: "+amountStr); System.out.println("Currency: "+currencyStr); } }

The output of the NumberCurrencyDemo class is as follows:


United States Number: 648,927.843 Currency: $3,866,249.21

The format number and currencies according to the Locale object, France:
C:\i18n>java NumberCurrencyDemo fr FR

The output of the NumberCurrencyDemo class is as follows:


France Number: 648927,843 Currency: 3866249,21

The format number and currencies according to the Locale object, Germany:
C:\i18n>java NumberCurrencyDemo de DE

The output of the NumberCurrencyDemo class is as follows:


Germany Number: 648.927,843 Currency: 3.866.249,21

The format number and currencies according to the Locale object, United States:
C:\i18n>java NumberCurrencyDemo en US

The output of the NumberCurrencyDemo class is as follows:


United States Number: 648,927.843 Currency: $3,866,249.21

Appendix D

This was the discussion about how a program can be internationalized to support various Locales in the world. It helps in the efficient maintenance of the application and makes it more scalable to work for the users from different Locales. The single program is capable of displaying customized messages in different languages and showing date, time, number and currency in various formats according to the Locale of the user and that is without any change in the code. This has become possible only with the help of various classes and methods provided in JDK supporting number of Locales and Localized resources.

Anda mungkin juga menyukai