dk.statsbiblioteket.util.i18n.Translator.java Source code

Java tutorial

Introduction

Here is the source code for dk.statsbiblioteket.util.i18n.Translator.java

Source

/* $Id: Translator.java,v 1.9 2007/12/04 13:22:01 mke Exp $
 * $Revision: 1.9 $
 * $Date: 2007/12/04 13:22:01 $
 * $Author: mke $
 *
 * The SB Util Library.
 * Copyright (C) 2005-2007  The State and University Library of Denmark
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package dk.statsbiblioteket.util.i18n;

import dk.statsbiblioteket.util.qa.QAInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

/**
 * Convenience class to ease usage of resource bundles for translation
 * purposes.
 *
 * <b>Note:</b> {@link ResourceBundle} does internal caching of the parsed
 * bundles so there is not need for a static factory for this class.
 *
 * @see BundleCache
 * @see ResourceBundle
 */
@QAInfo(state = QAInfo.State.QA_NEEDED, level = QAInfo.Level.NORMAL)
public class Translator {

    /**
     * Name of the default {@link ResourceBundle} to load translations from.
     */
    public static final String DEFAULT_BUNDLE = "messages";

    /**
     * Default {@link Locale}. Used in case no bundle is found for the
     * provided locale.
     */
    public static final Locale DEFAULT_LOCALE = Locale.ENGLISH;

    private ResourceBundle bundle;
    private Locale locale;
    private MessageFormat formatter;
    private HashMap<String, String> unknownMessages;
    private Log log;
    private boolean usingFallBack;

    /**
     * Create a Translator for a named {@link ResourceBundle} and a given
     * {@link Locale}.
     *
     * If no resource bundle matching the request can be found this
     * class will try to fall back to the {@link #DEFAULT_LOCALE}. If this fails
     * too it will fall back to an empty resource bundle. This means that all
     * requests to {@link #translate} will return a String where '.' is
     * replaced by a white space. See {@link #translate} documentation.
     *
     * @param bundleName the name of the ResourceBundle to look up
     * @param locale     the locale to translate to
     */
    public Translator(String bundleName, Locale locale) {
        this.locale = locale;
        this.formatter = new MessageFormat("", locale);
        this.unknownMessages = new HashMap<String, String>();
        this.log = LogFactory.getLog(Translator.class);

        try {
            this.bundle = BundleCache.getBundle(bundleName, locale);
            usingFallBack = false;
        } catch (MissingResourceException e) {
            usingFallBack = true;
            log.warn("Unable to find resource bundle '" + bundleName + "' for locale '" + locale
                    + "'. Trying default: '" + DEFAULT_LOCALE + "'.");
            try {
                this.bundle = BundleCache.getBundle(bundleName, DEFAULT_LOCALE);
            } catch (MissingResourceException ee) {
                log.warn("Unable to load bundle '" + bundleName + "' for default locale '" + DEFAULT_LOCALE
                        + "'. Falling back to raw translations.");
                this.bundle = new EmptyResourceBundle();
            }
        }
    }

    /**
     * Create a Translator for the {@link #DEFAULT_BUNDLE}.
     * See {@link #Translator(String, java.util.Locale)} for fallback strategy.
     *
     * @param locale the locale to use for all translations.
     */
    public Translator(Locale locale) {
        this(DEFAULT_BUNDLE, locale);
    }

    /**
     * Return translation corresponding to a given key. If the key is not
     * found in the underlying {@link ResourceBundle} the string with periods
     * replaced by white spaces will be returned.
     *
     * Because of the above described fallback behavior it is strongly
     * advised to make translation keys in the reverse format. Ie replace
     * white spaces by periods.
     *
     * If the key is not found this will be reported to the log on the first
     * occurence only. This is to avoid flooding the log with translation
     * warnings.
     *
     * @param key    the key to lookup translation for.
     * @param values the values to replace in the translated string
     * @return the translated string - or best effort described as above.
     */
    public String translate(String key, Object... values) {
        String message;
        try {
            message = bundle.getString(key);
        } catch (MissingResourceException e) {
            message = unknownMessages.get(key);
            if (message == null) {
                log.warn("Unknown key '" + key + "' falling back to raw format"
                        + ". This warning will only be logged once.");
                message = key.replace('.', ' ');
                unknownMessages.put(key, message);
            }
        }

        formatter.applyPattern(message);
        return formatter.format(values);
    }

    /**
     * Get the bundle used for translation. Note that this may be an empty bundle in case none was found.
     *
     * @return the translation bundle.
     */
    public ResourceBundle getBundle() {
        return bundle;
    }

    public Locale getLocale() {
        return locale;
    }
}