I18N.java Source code

Java tutorial

Introduction

Here is the source code for I18N.java

Source

import java.text.Format;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

/**
 * Internationalisation (I18N) helper
 * @author eliott bartley
 */
public class I18N {

    private I18N() {
    }

    /**
     * Given a message and parameters, resolve all message's parameter
     *  placeholders with the parameter value. The firstParam can change which
     *  parameter relates to {0} placeholder in the message, and all increment
     *  from this index. If any of the parameters also have placeholders, this
     *  recursively calls itself to fill their placeholders, setting the
     *  firstParam to the index following all parameters that are used by the
     *  current message so params must be in the order p0..pN, p00..p0N..pMN,
     *  p000..p00N..p0MN..pLMN... where each additional index is for nested
     *  placeholders (ones in params) and assumes every message/param contains
     *  N M L placeholders; any that don't contain placeholders can have their
     *  pXXX.. taken out, so long as the order of remaining params don't change
     * @param message Message to format
     * @param firstParam Index of parameter that relates to {0} placeholder,
     *  all parameters following this one relate to incrementing placeholders
     * @param params The parameters used to fill the placeholders
     * @return Message with all placeholders filled with relative parameters
     */
    private static String formatMessage(String message, int firstParam, Object[] params) {

        // Only need to do any formatting if there are parameters to do the
        //  formatting with. If there are none, the message input is returned
        //  unmodified
        if (params != null && firstParam < params.length) {
            MessageFormat parser;
            Locale locale = Locale.getDefault();
            Format[] formats;

            // Set up
            parser = new MessageFormat("");
            parser.setLocale(locale);
            parser.applyPattern(message);
            // Used only to count how many parameters are needed by this message
            formats = parser.getFormatsByArgumentIndex();

            // Recursively format the parameters used by this message
            for (int paramIndex = 0; paramIndex < formats.length; paramIndex++)
                if (params[firstParam + paramIndex] instanceof String)
                    params[firstParam + paramIndex] = formatMessage(params[firstParam + paramIndex].toString(),
                            firstParam + formats.length, params);

            // Format the message using the formatted parameters
            message = parser.format(getParams(params, firstParam, firstParam + formats.length));

        }

        return message;

    }

    /**
     * MessageFormat.format always matches the placeholder's index directly to
     *  the param array index, but because placeholders can be nested, the
     *  zeroth placeholder may not match the zeroth array element, so this
     *  method copies the array so that only the required array elements are
     *  present, and start from the zeroth element
     * @param params Complete param array
     * @param firstParam First element that will be used in complete param array
     * @param lastParam Last element that will be used in complete param array
     * @return Param array containing just the elements from
     *  firstParam..lastParam-1. If lastParam is less or equal to firstParam,
     *  null is returned rather than an empty array
     */
    private static Object[] getParams(Object[] params, int firstParam, int lastParam) {
        Object[] newParams = null;
        if (firstParam < lastParam) {
            newParams = new Object[lastParam - firstParam];
            for (int i = firstParam; i < lastParam; i++)
                newParams[i - firstParam] = params[i];
        }
        return newParams;
    }

}