All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.arc.pds.tools.util.LocaleUtils Maven / Gradle / Ivy

Go to download

The PDS3 Product Tools Library project supports design/generation, validation and submission of archival products to the PDS. This project consists of a library of software classes to support the development of tools to perform these functions and is designed to be utilized by developers from the Engineering Node, Discipline Nodes and the PDS community.

The newest version!
// Copyright 2019, California Institute of Technology ("Caltech").
// U.S. Government sponsorship acknowledged.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// • Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// • Redistributions must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
// • Neither the name of Caltech nor its operating division, the Jet Propulsion
// Laboratory, nor the names of its contributors may be used to endorse or
// promote products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package gov.nasa.arc.pds.tools.util;

import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A helper class for Locale functionality and locale specific functionality.
 * This includes message retrieval and formatting from message bundles.
 * 
 * @author jagander
 * @version $Revision: $
 * 
 */
public class LocaleUtils {

	public static final String DEFAULT_LOCALE_KEY = "en_US"; //$NON-NLS-1$

	public static final String DEFAULT_LANGUAGE = "en"; //$NON-NLS-1$

	public static final Locale DEFAULT_LOCALE = new Locale(DEFAULT_LOCALE_KEY);

	public static final String DEFAULT_BUNDLE_ROOT = "resources"; //$NON-NLS-1$

	public static final boolean DEFAULT_DEV_MODE = false;

	private Locale locale;

	public ResourceBundle bundle;

	private Boolean devMode = false;

	// capture 2 letter language designation followed by optional 2 letter
	// country code followed by optional variant
	// NOTE: variant may contain an underscore (ex. "Traditional_WIN") so a
	// split won't help
	// NOTE: country code and variant are preceded by an underscore
	// NOTE: language and country code are always 2 letter but variant may be
	// any length
	public final static Pattern LOCALE_PATTERN = Pattern
			.compile("(\\w{2})(_(\\w{2}))?(_(\\w+))?"); //$NON-NLS-1$

	public final static String NUMERIC_FORMAT = "{0,number,integer}"; //$NON-NLS-1$

	public static final Map, ResourceBundle> BUNDLE_CACHE = new HashMap, ResourceBundle>();

	public LocaleUtils() {
		this(null, null, DEFAULT_BUNDLE_ROOT);
	}

	public LocaleUtils(final Locale locale) {
		this(locale, DEFAULT_DEV_MODE, DEFAULT_BUNDLE_ROOT);
	}

	public LocaleUtils(final Boolean devMode) {
		this(null, devMode, DEFAULT_BUNDLE_ROOT);
	}

	public LocaleUtils(final String bundleRoot) {
		this(null, DEFAULT_DEV_MODE, bundleRoot);
	}

	public LocaleUtils(final ResourceBundle bundle) {
		this(bundle.getLocale(), DEFAULT_DEV_MODE, bundle);
	}

	public LocaleUtils(final Locale locale, final Boolean devMode) {
		this(locale, devMode, DEFAULT_BUNDLE_ROOT);
	}

	public LocaleUtils(final Locale locale, final String bundleRoot) {
		this(locale, DEFAULT_DEV_MODE, bundleRoot);
	}

	public LocaleUtils(final Locale locale, final ResourceBundle bundle) {
		this(locale, DEFAULT_DEV_MODE, bundle);
	}

	public LocaleUtils(final Locale locale, final Boolean devMode,
			final String bundleRoot) {
		setLocale(locale);
		setDevMode(devMode);
		this.bundle = ResourceBundle.getBundle(bundleRoot, this.locale);
	}

	// NOTE: not getting locale from bundle since, if did not find properties
	// file specific to that locale, it will set locale to a fallback. We still
	// want originally specified locale for formatting even if that is the case.
	public LocaleUtils(final Locale locale, final Boolean devMode,
			final ResourceBundle bundle) {
		setLocale(locale);
		setDevMode(devMode);
		this.bundle = bundle;
	}

	protected void setLocale(final Locale locale) {
		this.locale = (locale == null) ? DEFAULT_LOCALE : locale;
	}

	public Locale getLocale() {
		return this.locale;
	}

	protected void setDevMode(final Boolean devMode) {
		if (devMode != null) {
			this.devMode = devMode;
		}
	}

	public boolean isDevMode() {
		return this.devMode;
	}

	// override bundle
	protected void setBundle(final ResourceBundle bundle) {
		this.bundle = bundle;
	}

	// get the resource bundle
	public ResourceBundle getBundle() {
		return this.bundle;
	}

	// override bundle by name
	protected void setBundleName(String bundleName) {
		this.bundle = ResourceBundle.getBundle(bundleName, this.locale);
	}

	// since you can instantiate invalid locales, the best check is to see if
	// it's in the list of available locales
	public static boolean isValidLocale(final Locale locale) {
		Locale[] availLocales = Locale.getAvailableLocales();
		for (Locale testLocale : availLocales) {
			if (testLocale.equals(locale)) {
				return true;
			}
		}
		return false;
	}

	// get locale from locale string
	public static Locale stringToLocale(final String localeName) {
		String language = null;
		String country = null;
		String variant = null;
		Locale locale = null;

		final Matcher matcher = LOCALE_PATTERN.matcher(localeName);
		// check if locale string appears to be in correct form
		if (!matcher.matches()) {
			throw new RuntimeException(
					"Invalid locale name. The form must be LL[_CC][_VVV] where LL = 2 char language code, CC is an optional 2 char country code and VVV is an optional N character variant.");
		}

		// get parts of locale string
		language = matcher.group(1);
		country = matcher.group(3);
		variant = matcher.group(5);

		// create Locale from parts if present
		if (variant != null) {
			locale = new Locale(language, country, variant);
		} else if (country != null) {
			locale = new Locale(language, country);
		} else if (language != null) {
			locale = new Locale(language);
		}

		return locale;
	}

	// convert locale to a string representation
	// NOTE: toString() should be sufficient to identify the locale
	// this method exists to make that clear and to make central point
	// for further changes if necessary
	public static String localeToString(final Locale locale) {
		return locale.toString();
	}

	/**
	 * This retrieves a message from the appropriate properties file for your
	 * given Locale. It also uses any provided arguments to make substitutions
	 * and formatting changes to the found message. Note that this uses the OGNL
	 * expression language syntax for formatting.
	 * 
	 * @param key
	 *            - properties key used to look up message
	 * @param arguments
	 *            - an array of arguments to be used in the message, uses OGNL
	 *            syntax
	 * @return found and formatted message
	 * @throws KeyNotFoundException
	 */
	public String getText(final String key, final Object... arguments) {
		return getText(key, getBundle(), arguments);
	}

	// translation retrieval
	// TODO: throw exception on failure to find?
	private String getText(final String key, final ResourceBundle bundle,
			Object... arguments) {
		// some resources may be null rather than a key with empty value, short
		// circuit here
		if (key == null) {
			return null;
		}
		String message = null;
		try {
			// TODO: try to find in overriding bundle first then look in default
			message = bundle.getString(key);
		} catch (MissingResourceException e) {
			if (this.devMode) {
				throw new RuntimeException("Unable to find message for key \""
						+ key + "\".");
			}
			// return key as message if not in dev mode
			return key;
		}
		// substitute arguments and format
		return formatText(message, arguments);
	}

	public String formatText(final String message, Object... arguments) {
		Object[] args = null;
		// allow use of List to reduce legacy issues and increase
		// flexibility
		if (arguments != null && arguments.length == 1
				&& arguments[0] instanceof List) {
			args = ((List) arguments[0]).toArray();
		} else {
			args = arguments;
		}

		MessageFormat format = new MessageFormat(message, this.locale);

		return format.format(args);
	}

	// helper method returns locale specific formatting for a single number
	public String getNumber(final Number number) {
		return formatText(NUMERIC_FORMAT, number);
	}

	public String formatBytes(final double memory) {
		return formatBytes(memory, null);
	}

	/**
	 * Format bytes to human readable text
	 * 
	 * @param memory
	 *            The memory value to format.
	 * @param override
	 *            The locale to be used (determines decimal and grouping
	 *            separators).
	 * @return The formatted number string.
	 */
	@SuppressWarnings("nls")
	public String formatBytes(final double memory, final Locale override) {
		String result = "";
		final Locale curLocale = override != null ? override : this.locale;
		final NumberFormat format = NumberFormat.getInstance(curLocale);

		final double value = memory;
		if (value < 0.9 * FileUtils.ONE_KB) {
			result = format.format(value) + " B";
		} else if (value < 0.9 * FileUtils.ONE_MB) {
			result = format.format(value / FileUtils.ONE_KB) + " KB";
		} else if (value < 0.9 * FileUtils.ONE_GB) {
			result = format.format(value / FileUtils.ONE_MB) + " MB";
		} else if (value < 0.9 * FileUtils.ONE_TB) {
			result = format.format(value / FileUtils.ONE_GB) + " GB";
		} else if (value < 0.9 * FileUtils.ONE_PB) {
			result = format.format(value / FileUtils.ONE_TB) + " TB";
		} else {
			result = format.format(value / FileUtils.ONE_PB) + " PB";
		}

		return result;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy