Saturday, October 10, 2015

How to internationalize a display message

The requirement is to display the following message from our Java program.
Your last transaction was on October 11, 2015 at 8:46:03 AM with transaction amount $100.00.
The message has to be able to support the localization process. That means the message could be translated and conform to the expectations of a given user community. The highlighted parts are variances of date, time, and currency that are supplied to the message.

Solution 1: Deficient

Bundle.properties:
msgPart1 = Your last transaction was on
msgPart2 = at
msgPart3 = with transaction amount
Code:
// Message stored as parts in Bundle.properties
ResourceBundle bundle = ResourceBundle.getBundle("Bundle");

// Retrieve message parts from resource bundle
String msgPart1 = bundle.getString("msgPart1");
String msgPart2 = bundle.getString("msgPart2");
String msgPart3 = bundle.getString("msgPart3");

// Variants
double trxnAmount = 100;
Date trxnDateTime = new Date();

// Applying formating based on user default locale
DateFormat shortDateFormat = SimpleDateFormat.getDateInstance(DateFormat.LONG);
DateFormat shortTimeFormat = SimpleDateFormat.getTimeInstance(DateFormat.MEDIUM);
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();

// Construct message
StringBuilder message = new StringBuilder();
message.append(msgPart1).append(' ').append(shortDateFormat.format(trxnDateTime)).append(' ')
        .append(msgPart2).append(' ').append(shortTimeFormat.format(trxnDateTime)).append(' ')
        .append(msgPart3).append(' ').append(currencyFormat.format(trxnAmount))
        .append('.');

// Print and display the message
System.out.println(message.toString());

Result:
Your last transaction was on October 11, 2015 at 11:54:24 AM with transaction amount $100.00.
Summary:
Solution 1 is deficient because
  • The message is split into a few parts and this make translation unfriendly.
  • All the message parts are required to be concatenated and it is awkward to append space and period to construct to the whole message.
  • Verbose line of code to construct the message.

Solution 2: Good

Bundle.properties:
msg = Your last transaction was on {0} at {1} with transaction amount {2}.
Code:
    // Message stored in Bundle.properties
    ResourceBundle bundle = ResourceBundle.getBundle("Bundle");

    // Retrieve message parts from resource bundle
    String msg = bundle.getString("msg");

    // Variants
    double trxnAmount = 100;
    Date trxnDateTime = new Date();

    // Applying formating based on user default locale
    DateFormat shortDateFormat = SimpleDateFormat.getDateInstance(DateFormat.LONG);
    DateFormat shortTimeFormat = SimpleDateFormat.getTimeInstance(DateFormat.MEDIUM);
    NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
    
    // Collect variants into array
    Object[] arguments = new String[] {
        shortDateFormat.format(trxnDateTime),
        shortTimeFormat.format(trxnDateTime),
        currencyFormat.format(trxnAmount)
    };
    
    // Print and display the message
    System.out.println(MessageFormat.format(msg, arguments));

Result:
Your last transaction was on October 11, 2015 at 11:54:24 AM with transaction amount $100.00.
Summary:
Solution 2 makes use of java.text.MessageFormat. This allows the message to includes the variants in it and hence is translation friendly.

Solution 3: Better

Bundle.properties:
msg = Your last transaction was on {0, date, long} at {0, time, medium} with transaction amount {1, number, currency}.
Explanation:
{0, date, long} : Use the Date Formatter to format the arguments[0] object and apply with DateFormat.LONG style.
{0, time, medium} : Use the Time Formatter to format the arguments[0] object and apply with DateFormat.MEDIUM style.
{0, number, currency} : Use the Currency Formatter to format the arguments[1].

Code:
    // Message stored in Bundle.properties
    ResourceBundle bundle = ResourceBundle.getBundle("Bundle");

    // Retrieve message parts from resource bundle
    String msg = bundle.getString("msg");

    // Variants
    double trxnAmount = 100;
    Date trxnDateTime = new Date();
    
    // Collect variants into array
    Object[] arguments = new Object[] {
        trxnDateTime,
        trxnAmount
    };
    
    // Print and display the message
    System.out.println(MessageFormat.format(msg, arguments));

Result:
Your last transaction was on October 11, 2015 at 11:54:24 AM with transaction amount $100.00.
Summary:
Solution 3 is even better because
  • The formatting jobs are not required in the code because they are delegated to java.text.MessageFormat.
  • The formatting style such as LONG or MEDIUM date could be configured in the properties file instead of hardcoded in the source code.

References:

No comments: