Tuesday, October 13, 2015

How to create display message in correct form of singular and plural

Putting the message into resource bundle properties allows this message to be translated into other languages. This is not the end of the story because there are messages need to conform to the language's grammar. The most classic example is the singular and plural form in the English message as below:
There are no plugins available for installation.
There is one plugin available for installation.
There are 3 plugins available for installation.
The highlighted part is a numeric variant and the message change its form based on this variant.


Solution 1: Deficient

Bundle.properties:
none.msg = There are no plugins available for installation.
singular.msg = There is one plugin available for installation.
plural.msg = There are {0} plugins available for installation.
Code:
    private static ResourceBundle BUNDLE = ResourceBundle.getBundle("Bundle");

    private static void showMessage(int total) {
        if (total == 1) {
            System.out.println(BUNDLE.getString("singular.msg"));
        } else if (total > 1) {
            System.out.println(
                    MessageFormat.format(BUNDLE.getString("plural.msg"), total));
        } else {
            System.out.println(BUNDLE.getString("none.msg"));
        }
    }

    public static void main(String[] args) {
        showMessage(0);
        showMessage(1);
        showMessage(2);
    }

Result:
There are no plugins available for installation.
There is one plugin available for installation.
There are 2 plugins available for installation.
Summary:
Although the intention is good, but solution 1 is deficient because
  • The showMessage() implementation does more than just showing a message.
  • A message appears in 3 forms which most likely not true for non-English language. Translator has to provide the same message for 3 different keys in the Bundle.properties.


Solution 2: Not good enough

Bundle.properties:
msg = There is {0} plugin(s) available for installation.
Code:
    private static ResourceBundle BUNDLE = ResourceBundle.getBundle("Bundle");

    private static void showMessage(int total) {
        System.out.println(MessageFormat.format(BUNDLE.getString("msg"), total));
    }

    public static void main(String[] args) {
        showMessage(0);
        showMessage(1);
        showMessage(2);
    }

Result:
There is 0 plugin(s) available for installation.
There is 1 plugin(s) available for installation.
There is 2 plugin(s) available for installation..
Summary:
Solution 2 resolved the problems given by solution 1. However, it gives up the English grammar.


Solution 3: Good

Bundle.properties:
msg = There {0, choice, 0#are no plugins|1#is one plugin|1<are {0, number, integer} plugins} available for installation.
Code:
    private static ResourceBundle BUNDLE = ResourceBundle.getBundle("Bundle");

    private static void showMessage(int total) {
        System.out.println(MessageFormat.format(BUNDLE.getString("msg"), total));
    }

    public static void main(String[] args) {
        showMessage(0);
        showMessage(1);
        showMessage(2);
    }

Result:
There are no plugins available for installation.
There is one plugin available for installation.
There are 2 plugins available for installation.
Summary:
The message in the Bundle.properties is a java.text.ChoiceFormat pattern. It can be digested by MessageFormat. With a single message in Bundle.properties, solution 3 is able to meet the requirement perfectly.



References:
http://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html
http://docs.oracle.com/javase/7/docs/api/java/text/ChoiceFormat.html

No comments: