Formatting and Internationalization

Contents

 

 

Applets in archives

Program settings

Program settings are most easily stored as strings in files. Such settings include flags that control program execution. It is initially assumed here that the user can modify these settings. Therefore, these files are not treated as resources.

If you want to import settings that are non-modifiable resources, you can of course access these files as described previously. However, for menu text or messages to be displayed, you should consider using the internationalization tools described below.

Initially, settings are stored in instances of properties . This data type is a child of Hashtable. However, functions exist for reading and writing to streams. Properties contain the properties row by row as follows.

Test=true

Then, to the left of the equals sign are the keys and to the right are the resource values. The following program uses a file called test.properties from the user's home directory.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

public class Test
{

    public static void main (String args[])
    {
        new Test();
    }

    public Test()
    {
        Properties P = new Properties();
        String filename = System.getProperty("user.home")
                + "/test.properties";

        try
        {
            // Read properties:
            FileInputStream in = new FileInputStream(filename);
            P.load(in);
            in.close();
        }
        catch (Exception e)
        {
            System.out.println(e);
        }

        try
        {
            // Print some properties:

            System.out.println(P.getProperty("Tes"));
            System.out.println(P.getProperty("Test"));
            System.out.println(P.getProperty("Test", "no value"));
            System.out.println(toBoolean(P.getProperty("Test", "false")));

            // Add a property
            P.put("Test", "true");

            // Save the properties again:
            FileOutputStream out = new FileOutputStream(filename);
            P.store(out, "Test Properties");
            out.close();
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    }

    public static boolean toBoolean (String s)
    // Interpret true or false
    {
        return s.equals("true");
    }
}

This program should be run twice. The first time, the file test.properties does not yet exist in the user's home directory. Therefore, the following output is displayed.

java.io.FileNotFoundException: C:\Users\reneg\test.properties
   (The system cannot find the specified file)
zero
zero
no value
false

Non-existent properties have the value null . However, you can specify a default value. On the second iteration, the file will exist.

#Test Properties
#Sat Aug 19 09:30:15 CEST 2023
Test=true

The following output will now be displayed.

zero
true
true
true

Some properties are predefined by the system and can be accessed using the System class. The following program lists all these system properties. It also shows how to obtain an enumeration of all keys in a HashTable.

import java.util.Enumeration;
import java.util.Properties;

public class Test
{
    public static void main (String args[])
    {
        Properties P = System.getProperties();
        Enumeration<Object> e = P.keys();
        while (e.hasMoreElements())
        {
            String key = (String) e.nextElement();
            String value = (String) P.get(key);
            System.out.println(key + "=" + value);
        }
    }
}

The beginning of the output of this program on my system is as follows.

java.specification.version=20
sun.cpu.isalist=amd64
sun.jnu.encoding=Cp1252
java.vm.vendor=Oracle Corporation
sun.arch.data.model=64
user.variant=
java.vendor.url=https://java.oracle.com/
java.vm.specification.version=20
os.name=Windows 11
...

Some of these properties are very useful for applications. For example, you can query the Java version being used. Elsewhere, we use `file.separator` and `user.home` .

internationalization

Java programs should be easily usable on any computer in the world. We've already learned about file encoding for input and output of text . However, there are many more national settings, such as number formats , date formats , etc. Furthermore, a program should internationalize menu texts and error messages .

For this purpose, Java uses the Locale class . However, it contains constants for various locales that can be used directly to initialize the NumberFormat .

The selected language now determines how numbers are formatted. The class that formats numbers is `NumberFormat` . You cannot directly create an instance of this class; instead, you need its static `getInstance()` method (and related methods). Using an instance (which can also be initialized with a different language), you can format numbers locally. As an example, let's compare English and German output.

import java.text.NumberFormat;
import java.util.Locale;

public class Test
{
    public static void main (String args[])
    {
        // local edition (here in German)
        NumberFormat numberformat = NumberFormat.getInstance();

        System.out.println(numberformat.format(Math.PI));
        numberformat.setMaximumFractionDigits(16);
        System.out.println(numberformat.format(Math.PI));
        numberformat.setGroupingUsed(true); // Groups three numbers together
        System.out.println(numberformat.format(1000000000.01));

        // English edition (US format):
        numberformat = NumberFormat.getInstance(Locale.ENGLISH);

        System.out.println(numberformat.format(Math.PI));
        numberformat.setMaximumFractionDigits(16);
        System.out.println(numberformat.format(Math.PI));
        numberformat.setGroupingUsed(true);
        System.out.println(numberformat.format(1000000000.01));
    }
}

The output differs due to the use of commas and periods. However, a local computer may also have different settings.

3,142
3,141592653589793
1,000,000,000.01
3,142
3.141592653589793
1,000,000,000.01

Apparently, the language is also important for number input. We add the following lines for this purpose.

        try
        {
            double x = numberformat.parse(numberformat.format(1000000000.01))
                    .doubleValue();
            System.out.println(x);
        }
        catch (ParseException e)
        {
        }

The output shows that a formatter can read its own output (even if it contains groupings, for example). It returns a Number object, whose methods can be used to reformat the output into numbers.

The alternative

System.out.println(Double.valueOf("100.23").doubleValue());

This only works with numbers formatted in English with a decimal point. The wrapper class `Double` for the built-in data type `double` transforms the built-in type into an object. It is intended for storing `double` values ​​in data structures that only accept objects, such as hashtables . `Double` has the statistical method shown for converting ` String` to `Double` .

There are also formatters for currency units, percentages, and dates. We will demonstrate all three in one program.

import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Date;

public class Test
{
    public static void main (String args[])
    {
        NumberFormat price = NumberFormat.getCurrencyInstance();
        NumberFormat percent = NumberFormat.getPercentInstance();
        System.out.println(price.format(12.31));
        percent.setMinimumFractionDigits(2);
        System.out.println(percent.format(0.1231));

        DateFormat date = DateFormat.getDateInstance(DateFormat.SHORT);
        System.out.println(date.format(new Date()));
        date = DateFormat.getDateTimeInstance(
                DateFormat.LONG, DateFormat.LONG);
        System.out.println(date.format(new Date()));
    }
}

The output is

12.31 DM
12.31%
29.06.98
June 29, 1998 11:46:10 GMT+02:00

The Date class handles a date. It is particularly affected by the current time zone.

Another area for internationalization is the release of programs in international formats. As an example, we show a Japanese Java program here.

As you can see, all menu texts are in Japanese. The same should apply to error messages and help texts.

To create such a program, you should read the strings used from a resource. This is done using property files, whose names consist of a string with the language area appended and the file extension .properties. An example is Test_de.properties. Java automatically selects this resource file if you are in the German language area (or have set Locale.setDefault accordingly) and resource bundles are used. The most convenient way to do this is in a static variable of the main class.

As an example, in the directory where the class is used, two property files, Test.properties and Test_de.properties, are created, each containing a property called Test , one with the value English and the other with the value Deutsch . On a German system, the second property file is used. In every other language, the first property file is used.

import java.util.ResourceBundle;

public class Test
{
    static ResourceBundle B; // bundle used

    public static void initBundle()
    // Initialize B
    {
        try
        {
            B = ResourceBundle.getBundle("Test");
        }
        catch (Exception e)
        {
            B = null;
        }
    }

    public static void main (String args[])
    // The circle is called as an application.
    {
        initBundle();

        if (B != null) System.out.println(B.getString("Test"));
    }

}

Exercisetasks

  1. Extend the Help class to automatically open the local help file. For example, assume the help file is named topic_de_DE.txt. Use Local.getDefault().
  2. How often did the 13th of a month fall on each day of the week this century (or more generally, between two years that can be entered on the command line)? Use the GregorianCalendar class and its get(GregorianCalendar.DAY_OF_WEEK) method to find out. First, output the current day of the week so you can interpret the result.

Solutions .

Problems without solutions

  1. Test the input of a date using the parse method of DateFormat.
  2. Pack an applet into an archive and launch it with your browser.
  3. Include a help file and display the file using our Help class.

Back to the Java course