Java SE 8 Programmer II Exam Series: Internationalization and Localization

Suleyman Yildirim
5 min readJun 20, 2020
Photo by Marco Secchi on Unsplash

Introduction

In this post, we will look at how to add internationalization and localization to the Java application. We will learn how to pick a locale, create and use properties files in different languages, and to format the numbers. Note that the localization is also a part of the Java SE 11 Programmer II Certification.

Default Locale

The Locale class is in the java.util package. The first useful Locale to find is the user’s current locale.

Locale locale = Locale.getDefault(); 
System.out.println(locale);

Creating a Locale

There are three different ways of creating local other than the default.

Using Constants

System.out.println(Locale.GERMAN); // de System.out.println(Locale.GERMANY); // de_DE

Using Constructors

System.out.println(new Locale("fr")); // fr
System.out.println(new Locale("hey", "FR")); // hey_FR

Using a Builder

Locale l = new Locale.Builder()
.setLanguage("en")
.setRegion("US")
.build();

Resource Bundle

Resource bundles contain locale-specific objects. When your program needs a locale-specific resource, a String for example, your program can load it from the resource bundle that is appropriate for the current user's locale. There are two different ways of creating a resource bundle:

Creating a Property File

The property file that contains key-value pairs. Let’s create two different locales for English and Turkish language.

Gym_en.properties
name=The Gym
info=The gym is closed due to the Covid-19.

Gym_tr.properties
name=Salon 666
info=Korona'dan dolayi salonumuz kapalidir.

We can access the property files using a ResourceBundle or Properties class.

Using ResourceBundle class

Given the two different locales, the following code prints out the different outputs.

ResourceBundle rb = ResourceBundle.getBundle("Gym", new Locale("en", "US"));
System.out.println(rb.getString("name")); // The Gym
System.out.println(rb.getString("info")); // The gym is closed due to the Covid-19.

ResourceBundle rb = ResourceBundle.getBundle("Gym", new Locale("tr", "TR"););
System.out.println(rb.getString("name")); // Salon 666
System.out.println(rb.getString("info")); // Korona'dan dolayi salonumuz kapalidir.

Using Properties class

The following code converts the resource bundle to Properties, then retrieves the key for the Turkish locale.

Locale tr= new Locale("tr", "TR");
ResourceBundle rb = ResourceBundle.getBundle("Gym", tr);

Properties props = new Properties();
rb.keySet().stream().forEach(k -> props.put(k, rb.getString(k)));

System.out.println(props.getProperty("name")); // Salon 666
System.out.println(props.getProperty("info")); // Korona'dan dolayi salonumuz kapalidir.

Creating a Java Class

Property files have a limitation in that only String values are allowed. Java class resource bundles allow any Java type as the value. Keys must be strings, though. There are two main advantages of using a Java class instead of a property file for a resource bundle:

  • You can use a value type that is not a String.
  • You can create the values of the properties at runtime.

Resource bundles contain key/value pairs. The keys uniquely identify a locale-specific object in the bundle. Here’s an example of a ListResourceBundle that contains two key/value pairs:

public class MyResources extends ListResourceBundle {
protected Object[][] getContents() {
return new Object[][] {
// LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
{"OkKey", "OK"},
{"CancelKey", "Cancel"},
// END OF MATERIAL TO LOCALIZE
};
}
}

Determining Which Resource Bundle to Use

There are two different ways to determine a resource bundle: the default locale and getting from a parent. We will focus on the default locale as you will most likely use this one in your day to day job.

Java chooses the most suitable resource bundle for a given key. It starts with the requested language and country, and then checks the default language and country, and finally looks at the default resource bundle with no locale.

Scenario 1: Get the resource bundle Gym with the locale new Locale(“tr”, “TR”) when the default locale is US English.

Locale.setDefault(new Locale("en", "US"));
ResourceBundle rb = ResourceBundle.getBundle("Gym", new Locale("tr", "TR"));

As we specify the language and country code in the Locale constructor, Java checks the language and country:

Java looks at the following files to choose a resource bundle:

Gym_tr_TR.java
Gym_tr_TR.properties
Gym_tr.java
Gym_tr.properties
Gym_en_US.java
Gym_en_US.properties
Gym_en.java
Gym_en.properties
Gym.java
Gym.properties

Scenario 2: Get the resource bundle Gym with the locale new Locale(“en”) when the default locale is “tr” language.

Locale.setDefault(new Locale("tr")); 
ResourceBundle rb = ResourceBundle.getBundle("Gym", new Locale("en"));

As we only specify the language in the new Locale(“tr”) constructor, Java skips the steps for the country

Java looks at the following files to choose a resource bundle:

Gym_en.java
Gym_en.properties
Gym_tr.java
Gym_tr.properties
Gym.java
Gym.properties

Formatting Numbers

When formating dynamic content, such as dates and prices, the resource bundles are not sufficient. The java.text is useful in those circumstances. Here is the order to format and parse a number.

  • Create a NumberFormat
  • Turn a number into a String using format()
  • Turn a String into a number using parse()

Create a NumberFormat instance

We can use the following factory methods to create a NumberFormat instance. The table below shows the purpose of the methods for the default locale and a specified locale.

For instance, to format a number for a different Locale, specify it in the call to getInstance.

NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);

Turn a number into a String using format()

The code below shows the difference in formatting two different locales.

int number = 420000 / 14; 
NumberFormat us = NumberFormat.getInstance(Locale.US); System.out.println(us.format(number)); //381.818
NumberFormat germany = NumberFormat.getInstance(Locale.GERMANY); System.out.println(germany.format(number));//381,818

Turn a String into a number using parse()

double currency = 12;
NumberFormat us = NumberFormat.getCurrencyInstance(); System.out.println(us.format(currency)); //$12.00

Parsing number

The code below parses a discounted ticket price with different locales

NumberFormat en = NumberFormat.getInstance(Locale.US);
NumberFormat fr = NumberFormat.getInstance(Locale.FRANCE);
String s = "62.85";
System.out.println(en.parse(s)); // 62.85 System.out.println(fr.parse(s)); // 62

Parsing currency

We can also use it for parsing currency. The following code removes out the characters and converts the value to a number.

String currency = "$12,235.99";
NumberFormat cf = NumberFormat.getCurrencyInstance();
double value = (Double) cf.parse(currency); System.out.println(value); // 12235.99

Summary

In this section, we looked at how to add internationalization and localization to a Java application. We learned how to pick a locale, create and use properties files in different languages, and formatting the numbers.

Originally published at http://suleymanyildirim.org on June 20, 2020.

--

--