SDSU CS 696 Emerging Technologies: Distributed Objects
Spring Semester, 1998
Internationalization

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 07-May-98

Contents of Doc 35, Internationalization

  1. References
  2. Internationalization
    1. Formatting
      1. Languages and Countries Available in JDK1.1.3
    2. Static and Dynamic Text
    3. Internationalization of Text
      1. Hello World Example with Just Classes
      2. Hello World Example - Using Files
      3. A More Complex Example
CS 696 Doc 35 Internationalization


References



Java in a Nutshell, 2nd Ed. David Flanager, Chapter 11

On-line Java Documentation


Doc 35, Internationalization Slide # 2

Internationalization

Formatting



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


Doc 35, Internationalization Slide # 3
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

Doc 35, Internationalization Slide # 4
java.util.Locale

You create a Locale object using one of the two constructors of 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

Doc 35, Internationalization Slide # 5

Languages and Countries Available in JDK1.1.3

LanguageCountry
ArabicEgypt
BelorussianBelarus
BulgarianBulgaria
CatalanSpain
CzechCzech Republic
DanishDenmark
GermanGermany
GermanAustria
GermanSwitzerland
GreekGreece
EnglishCanada
EnglishUnited Kingdom
EnglishIreland
EnglishUnited States
Spanish - Modern SortSpain
EstonianEstonia
FinnishFinland
FrenchFrance
FrenchBelgium
FrenchCanada
FrenchSwitzerland
CroatianCroatia
HungarianHungary
IcelandicIceland
ItalianItaly
ItalianSwitzerland
HebrewIsrael
JapaneseJapan
KoreanKorea
LithuanianLituania
LatvianLatvia
MacedonianMacedonia
DutchNetherlands
DutchBelgium
Norwegian (BokmÂl)Norway
Norwegian (Nynorsk)Norway
PolishPoland
PortuguesePortugal
RomanianRomania
RussianRussia
Serbian (Latin)Serbia
SlovakSlovakia
SloveneSlovenia
AlbanianAlbania
Serbian (Cyrillic)Serbia
SwedishSweden
TurkishTurkey
UkrainianUkraine
ChineseChina
ChineseROC


Doc 35, Internationalization Slide # 6
Using the Default Locale to Format
import java.text.*;
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

Doc 35, Internationalization Slide # 7
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

Doc 35, Internationalization Slide # 8
//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() ));
      }
   }

Doc 35, Internationalization Slide # 9
//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

Doc 35, Internationalization Slide # 10
Parsing Numbers/Dates Etc.

import java.text.*;
import java.util.Locale;
public class Test
   {
   public static void main( String args[] ) throws Exception 
      {
      Locale Spain = new Locale("es", "ES" );
      NumberFormat spanishFormat = 
               NumberFormat.getInstance( Spain );
      
      Number parsed = spanishFormat.parse( "123.456,5");
      System.out.println( parsed.floatValue() );
      
      parsed = spanishFormat.parse( "123.4.5.6,5");
      System.out.println( parsed.floatValue() );
      }
   }
Output
123456.5
123456.5


Doc 35, Internationalization Slide # 11

Static and Dynamic Text

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

Doc 35, Internationalization Slide # 12

Internationalization of Text


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


Doc 35, Internationalization Slide # 13

Hello World Example with Just Classes


import java.util.ResourceBundle;

// The main program, 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
         };
      }
   }


Doc 35, Internationalization Slide # 14
//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

Doc 35, Internationalization Slide # 15
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!

Doc 35, Internationalization Slide # 16
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;
      }
   }


Doc 35, Internationalization Slide # 17

Hello World Example - Using Files


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


Doc 35, Internationalization Slide # 18

A More Complex Example

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?

Doc 35, Internationalization Slide # 19
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( );
      }
      

Doc 35, Internationalization Slide # 20
// 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?


Copyright © 1998 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
All rights reserved.

visitors since 07-May-98