| CS 535: Object-Oriented Programming & Design |
|
---|
Fall Semester, 1997
Doc 19, Internationalization
To Lecture Notes Index
San Diego State University -- This page last updated 22-Oct-97
Contents of Doc 19, Internationalization
- References
- Internationalization
- Formatting
- Languages and Countries Available in JDK1.1.3
- Static and Dynamic Text
- Internationalization of Text
- Hello World Example with Just Classes
- Hello World Example - Using Files
- A More Complex Example
Java in a Nutshell, 2nd Ed. David Flanager, Chapter 11
On-line Java Documentation
Are dates formatted as:
- 10/13/97
- 13/10/97
- 13.10.97
Are numbers formatted as:
- 1,234.56
- 1.234,56
- 1;234.56
Java's Solution
An instances of the java.util.Locale class contains the rules for a language in
a location
Each Java virtual machine has a default instance of the Locale class, which
should be for the local language rules in the current country
java.text.NumberFormat
formats numbers, currency, and percents using the default Locale rules
For finer control over formatting numbers use java.text.DecimalFormat
java.text.DateFormat
formats dates and time using the default Locale rules
Dates and times can be formatted in FULL, LONG, MEDIUM, and SHORT versions
For finer control over formatting dates use java.text.SimpleDateFormat
java.util.Locale
You create a Locale object using one of the two constructors in this class:
- Locale(String language, String country)
- Locale(String language, String country, String variant)
The first argument to both constructors is a valid ISO Language Code. These
codes are the lower-case two-letter codes as defined by ISO-639. You can find a
full list of these codes at a number of sites, such as:
http://www.ics.uc.edu/pub/ietf/http/related/iso639.txt
The second argument to both constructors is a valid ISO Country Code. These
codes are the upper-case two-letter codes as defined by ISO-3166. You can find
a full list of these codes at a number of sites, such as:
http://www.chemi.fu-berlin.de/diverse/doc/ISO_3166.html
Language | Country |
Arabic | Egypt |
Belorussian | Belarus |
Bulgarian | Bulgaria |
Catalan | Spain |
Czech | Czech Republic |
Danish | Denmark |
German | Germany |
German | Austria |
German | Switzerland |
Greek | Greece |
English | Canada |
English | United Kingdom |
English | Ireland |
English | United States |
Spanish - Modern Sort | Spain |
Estonian | Estonia |
Finnish | Finland |
French | France |
French | Belgium |
French | Canada |
French | Switzerland |
Croatian | Croatia |
Hungarian | Hungary |
Icelandic | Iceland |
Italian | Italy |
Italian | Switzerland |
Hebrew | Israel |
Japanese | Japan |
Korean | Korea |
Lithuanian | Lituania |
Latvian | Latvia |
Macedonian | Macedonia |
Dutch | Netherlands |
Dutch | Belgium |
Norwegian (BokmÂl) | Norway |
Norwegian (Nynorsk) | Norway |
Polish | Poland |
Portuguese | Portugal |
Romanian | Romania |
Russian | Russia |
Serbian (Latin) | Serbia |
Slovak | Slovakia |
Slovene | Slovenia |
Albanian | Albania |
Serbian (Cyrillic) | Serbia |
Swedish | Sweden |
Turkish | Turkey |
Ukrainian | Ukraine |
Chinese | China |
Chinese | ROC |
Using the Default Locale to Format
class FormatUsingLocalRules
{
public static void main( String args[] ) throws Exception
{
NumberFormat number = NumberFormat.getInstance( );
NumberFormat currency =
NumberFormat.getCurrencyInstance( );
DateFormat shortDate =
DateFormat.getDateInstance(DateFormat.SHORT);
DateFormat fullTime =
DateFormat.getTimeInstance(DateFormat.FULL );
System.out.println( "Number: " + number.format( 123456 ));
System.out.println( "Currency: " +
currency.format( 1234.56 ));
System.out.println( "ShortDate: " +
shortDate.format( new Date() ));
System.out.println( "FullTime: " +
fullTime.format( new Date() ));
}
}
Output
Number: 123,456
Currency: $1,234.56
ShortDate: 10/13/97
FullTime: 5:15:42 oclock PM PDT
International Example
Explicitly use other locales to show that they are different
Usually you do not want to use locales explicitly, usually:
- Use the default give by the VM or
-
- Set the default to what you want
class FormatExplicitlyCallingDifferentLocale
{
public static void main( String args[] )
{
System.out.println( "-------US English------");
internationalPrint( Locale.getDefault() );
System.out.println( "-------Canadian English------");
internationalPrint( new Locale("en", "CA" ));
System.out.println( "-------Spanish Spanish------");
internationalPrint( new Locale("es", "ES" ));
System.out.println( "-------German German------");
internationalPrint( new Locale("de", "DE" ));
}
//internationalPrint on next slide
//International Example - continued
public static void internationalPrint( Locale custom )
{
NumberFormat number =
NumberFormat.getInstance( custom );
NumberFormat currency =
NumberFormat.getCurrencyInstance( custom );
DateFormat shortDate = DateFormat.getDateInstance(
DateFormat.SHORT, custom );
DateFormat fullDate = DateFormat.getDateInstance(
DateFormat.FULL, custom );
DateFormat shortTime = DateFormat.getTimeInstance(
DateFormat.SHORT, custom );
DateFormat longTime = DateFormat.getTimeInstance(
DateFormat.LONG,custom );
System.out.println( "Number: " +
number.format( 123456 ));
System.out.println( "Currency: " +
currency.format( 1234.56 ));
System.out.println( "ShortDate: " +
shortDate.format( new Date() ));
System.out.println( "FullDate: " +
fullDate.format( new Date() ));
System.out.println( "ShortTime: " +
shortTime.format( new Date() ));
System.out.println( "LongTime: " +
longTime.format( new Date() ));
}
}
//International Example - continued
Output
-------US English------
Number: 123,456
Currency: $1,234.56
ShortDate: 10/12/97
FullDate: Sunday, October 12, 1997
ShortTime: 9:45 PM
LongTime: 9:45:46 PM PDT
-------Canadian English------
Number: 123;456
Currency: $1;234.56
ShortDate: 12/10/97
FullDate: Sunday, October 12, 1997
ShortTime: 9:45 PM
LongTime: 9:45:46 PDT PM
-------Spanish Spanish------
Number: 123.456
Currency: 1.234,56 Pts
ShortDate: 13/10/97
FullDate: lunes 13 de octubre de 1997
ShortTime: 6:45
LongTime: 6:45:46 GMT+02:00
-------German German------
Number: 123.456
Currency: 1.234,56 DM
ShortDate: 13.10.97
FullDate: Montag, 13. Oktober 1997
ShortTime: 06:45
LongTime: 06:45:46 GMT+02:00
import java.text.MessageFormat;
import java.util.Date;
class Test
{
public static void main( String args[] ) throws Exception
{
Object[] dynamicText = {"Roger",new Date() };
String staticText = "{0}, it is {1,time,short}";
String publicMessage =
MessageFormat.format(staticText, dynamicText);
System.out.println( publicMessage );
}
}
Output
Roger, it is 10:03 PM
In Java you can write programs that will display text in the native language of
the country in which the program is being run
The programmer has to supply the translations into each language
At run time the program will select the proper language, assuming the program
uses correctly the internationalization features of the JDK
The translations of the text can be placed in data files or in special
classes
import java.util.ResourceBundle;
// The main progam, will display either German, Spanish
// or English depending on where you run the program
class HelloWorld
{
public static void main( String args[] )
{
ResourceBundle greetings =
ResourceBundle.getBundle( "Greetings" );
System.out.println( greetings.getString( "hello" ));
}
}
// The default language, if the local language and/or country
// can not be found this one will be used
import java.util.ListResourceBundle;
public class Greetings extends ListResourceBundle
{
public Object[][] getContents()
{
return new Object[][]
{
{ "hello", "Hello World!" },
{ "language", "English" },
{ "key", "value" } // can have as many pairs as needed
};
}
}
//Hello World - Continued
// Append _language code to base class name for a language
// Append _language_country to base class to indicate both
// langauge and country
// de = 2 letter ISO-639 code for German
public class Greetings_de extends ListResourceBundle
{
public Object[][] getContents()
{
return new Object[][]
{
{ "hello", "Hallo, Welt!" },
{ "language", "Deutsch" }
};
}
}
// de = 2 letter ISO-639 code for Spanish
public class Greetings_es extends ListResourceBundle
{
public Object[][] getContents()
{
return new Object[][]
{
{ "hello", "\u00A1Hola mundo!" },
{ "language", "Espa\u00F1ol" }
};
}
}
// \u00A1 = inverted ! \u00BF = inverted ?
// \u00D1 = N with a tilde \u00F1 = n with a tilde
Hello World Tested
import java.util.Locale;
import java.util.ResourceBundle;
class ThreeHellos
{
public static void main( String args[] )
{
foreignTest( );
Locale.setDefault( new Locale("es", "ES" ));
foreignTest();
Locale.setDefault( new Locale("de", "DE" ));
foreignTest( );
}
public static void foreignTest( )
{
ResourceBundle greetings =
ResourceBundle.getBundle( "Greetings");
System.out.println( "----" +
greetings.getString( "language") +
"----");
System.out.println( greetings.getString( "hello" ));
}
}
Output
----English----
Hello World!
----Español----
¡Hola mundo!
----Deutsch----
Hallo, Welt!
Warning about Class Structure
Here are two ways to structure the Greetings class. The first was used just to
save room on the slide (I print these out on 8.5 by 11 paper using 18 point
font size). The first creates the array each time the method getContents is
called (unless the compiler optimizes the call). The second only creates the
array once, hence should be more efficient. I do not have any data to indicate
what impact this would have on a program.
public class Greetings extends ListResourceBundle
{
public Object[][] getContents()
{
return new Object[][]
{
{ "hello", "Hello World!" },
{ "language", "English" },
};
}
}
public class Greetings extends ListResourceBundle
{
static final Object[][] contents =
{
{ "hello", "Hello World!" },
{ "language", "English" },
{ "key", "value" } // can have as many pairs as needed
};
public Object[][] getContents()
{
return contents;
}
}
Replace the classes Greetings, Greetings_de, Greetings_es with the following
files below
Then either ThreeHellos or HelloWorld will work the same
In file Greetings.properties
hello = Hello World!
language = English
In file Greetings_es.properties
hello = \u00A1Hola mundo!
language = Espa\u00F1ol
# \u00A1 = Unicode for inverted "!"
# \u00F1 = Unicode for n with tilde
In Greetings_de.properties
hello = Hallo, Welt!
language = Deutsch
In file Greetings.properties
hello = Hello World!
language = English
publicService = {0}, it is {1,time,short}, do you know where your children
are?
In file Greetings_es.properties
hello = \u00A1Hola mundo!
language = Espa\u00F1ol
publicService = {0}, son las {1,time,short} -- \u00BFsabes donde estan tus
hijos?
# \u00A1 = inverted !
# \u00BF = inverted ?
# \u00F1 = n with a tilde
In Greetings_de.properties
hello = Hallo, Welt!
language = Deutsch
publicService = {0}, es ist {1,time,short}. Weisst Du, wo Deine Kinder sind?
Testing the Different Locales
import java.text.MessageFormat;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.ListResourceBundle;
class HelloWithPublicService
{
static Object[] dynamicData = {
System.getProperty( "user.name" ),
new Date()
};
public static void main( String args[] )
{
foreignTest( );
Locale.setDefault( new Locale("es", "ES" ));
foreignTest();
Locale.setDefault( new Locale("de", "DE" ));
foreignTest( );
}
// HelloWithPublicService - Continued
public static void foreignTest( )
{
ResourceBundle greetings =
ResourceBundle.getBundle( "Greetings");
MessageFormat publicMessage;
publicMessage = new MessageFormat(
greetings.getString( "publicService"));
System.out.println( "----" + greetings.getString( "language") +
"----");
System.out.println( greetings.getString( "hello" ));
System.out.println( publicMessage.format( dynamicData ));
}
}
Output
----English----
Hello World!
Roger Whitney, it is 10:11 PM, do you know where your children are?
----Español----
¡Hola mundo!
Roger Whitney, son las 6:11 -- ¿sabes donde estan tus hijos?
----Deutsch----
Hallo, Welt!
Roger Whitney, es ist 06:11. Weisst Du, wo Deine Kinder sind?