/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.util.messages;
import org.pentaho.platform.util.logging.Logger;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Locale;
public class LocaleHelper {
private static final ThreadLocal<Locale> threadLocales = new ThreadLocal<Locale>();
private static final ThreadLocal<Locale> threadLocaleOverride = new ThreadLocal<Locale>();
public static final int FORMAT_SHORT = DateFormat.SHORT;
public static final int FORMAT_MEDIUM = DateFormat.MEDIUM;
public static final int FORMAT_LONG = DateFormat.LONG;
public static final int FORMAT_FULL = DateFormat.FULL;
public static final int FORMAT_IGNORE = -1;
private static Locale defaultLocale;
public static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
private static String encoding = LocaleHelper.UTF_8;
public static final String LEFT_TO_RIGHT = "LTR"; //$NON-NLS-1$
private static String textDirection = LocaleHelper.LEFT_TO_RIGHT;
public static final String USER_LOCALE_PARAM = "user_locale";
public static void setDefaultLocale( final Locale newLocale ) {
LocaleHelper.defaultLocale = newLocale;
}
public static Locale getDefaultLocale() {
return LocaleHelper.defaultLocale;
}
/**
* BISERVER-9863 Check if override locale string contains language and country. If so, instantiate Locale with
* two parameters for language and country, instead of just language
*
* @param localeOverride
*/
public static void parseAndSetLocaleOverride( final String localeOverride ) {
if ( localeOverride.contains( "_" ) ) {
String[] parts = localeOverride.split( "_" );
if ( parts.length >= 2 ) {
setLocaleOverride( new Locale( parts[0], parts[1] ) );
}
} else {
setLocaleOverride( new Locale( localeOverride ) );
}
}
public static void setLocaleOverride( final Locale localeOverride ) {
LocaleHelper.threadLocaleOverride.set( localeOverride );
}
public static Locale getLocaleOverride() {
return LocaleHelper.threadLocaleOverride.get();
}
public static void setLocale( final Locale newLocale ) {
LocaleHelper.threadLocales.set( newLocale );
}
public static Locale getLocale() {
Locale override = LocaleHelper.threadLocaleOverride.get();
if ( override != null ) {
return override;
}
Locale rtn = LocaleHelper.threadLocales.get();
if ( rtn != null ) {
return rtn;
}
LocaleHelper.defaultLocale = Locale.getDefault();
LocaleHelper.setLocale( LocaleHelper.defaultLocale );
return LocaleHelper.defaultLocale;
}
public static void setSystemEncoding( final String encoding ) {
Charset platformCharset = Charset.forName( encoding );
Charset defaultCharset = Charset.defaultCharset();
if ( platformCharset.compareTo( defaultCharset ) != 0 ) {
Logger.warn( LocaleHelper.class.getName(), Messages.getInstance().getString(
"LocaleHelper.WARN_CHARSETS_DONT_MATCH", platformCharset.name(), defaultCharset.name() ) );
}
LocaleHelper.encoding = encoding;
}
public static void setTextDirection( final String textDirection ) {
// TODO make this ThreadLocal
LocaleHelper.textDirection = textDirection;
}
public static String getSystemEncoding() {
return LocaleHelper.encoding;
}
public static String getTextDirection() {
// TODO make this ThreadLocal
return LocaleHelper.textDirection;
}
/**
* This method is called to convert strings from ISO-8859-1 (post/get parameters for example) into the default
* system locale.
*
* @param isoString
* @return Re-encoded string
*/
public static String convertISOStringToSystemDefaultEncoding( String isoString ) {
return convertEncodedStringToSystemDefaultEncoding( "ISO-8859-1", isoString ); //$NON-NLS-1$
}
/**
* This method converts strings from a known encoding into a string encoded by the system default encoding.
*
* @param fromEncoding
* @param encodedStr
* @return Re-encoded string
*/
public static String convertEncodedStringToSystemDefaultEncoding( String fromEncoding, String encodedStr ) {
return convertStringEncoding( encodedStr, fromEncoding, LocaleHelper.getSystemEncoding() );
}
/**
* This method converts an ISO-8859-1 encoded string to a UTF-8 encoded string.
*
* @param isoString
* @return Re-encoded string
*/
public static String isoToUtf8( String isoString ) {
return convertStringEncoding( isoString, "ISO-8859-1", "UTF-8" ); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* This method converts a UTF8-encoded string to ISO-8859-1
*
* @param utf8String
* @return Re-encoded string
*/
public static String utf8ToIso( String utf8String ) {
return convertStringEncoding( utf8String, "UTF-8", "ISO-8859-1" ); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* This method converts strings between various encodings.
*
* @param sourceString
* @param sourceEncoding
* @param targetEncoding
* @return Re-encoded string.
*/
public static String convertStringEncoding( String sourceString, String sourceEncoding, String targetEncoding ) {
String targetString = null;
if ( null != sourceString && !sourceString.equals( "" ) ) { //$NON-NLS-1$
try {
byte[] stringBytesSource = sourceString.getBytes( sourceEncoding );
targetString = new String( stringBytesSource, targetEncoding );
} catch ( UnsupportedEncodingException e ) {
throw new RuntimeException( e );
}
} else {
targetString = sourceString;
}
return targetString;
}
/**
* @param aString
* @return true if the provided string is completely within the US-ASCII character set.
*/
public static boolean isAscii( String aString ) {
return isWithinCharset( aString, "US-ASCII" ); //$NON-NLS-1$
}
/**
* @param aString
* @return true if the provided string is completely within the Latin-1 character set (ISO-8859-1).
*/
public static boolean isLatin1( String aString ) {
return isWithinCharset( aString, "ISO-8859-1" ); //$NON-NLS-1$
}
/**
* @param aString
* @param charsetTarget
* @return true if the provided string is completely within the target character set.
*/
public static boolean isWithinCharset( String aString, String charsetTarget ) {
byte[] stringBytes = aString.getBytes();
CharsetDecoder decoder = Charset.forName( charsetTarget ).newDecoder();
try {
decoder.decode( ByteBuffer.wrap( stringBytes ) );
return true;
} catch ( CharacterCodingException ignored ) {
//ignored
}
return false;
}
public static DateFormat getDateFormat( final int dateFormat, final int timeFormat ) {
if ( ( dateFormat != LocaleHelper.FORMAT_IGNORE ) && ( timeFormat != LocaleHelper.FORMAT_IGNORE ) ) {
return DateFormat.getDateTimeInstance( dateFormat, timeFormat, LocaleHelper.getLocale() );
} else if ( dateFormat != LocaleHelper.FORMAT_IGNORE ) {
return DateFormat.getDateInstance( dateFormat, LocaleHelper.getLocale() );
} else if ( timeFormat != LocaleHelper.FORMAT_IGNORE ) {
return DateFormat.getTimeInstance( timeFormat, LocaleHelper.getLocale() );
} else {
return null;
}
}
public static DateFormat getShortDateFormat( final boolean date, final boolean time ) {
if ( date && time ) {
return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, LocaleHelper.getLocale() );
} else if ( date ) {
return DateFormat.getDateInstance( DateFormat.SHORT, LocaleHelper.getLocale() );
} else if ( time ) {
return DateFormat.getTimeInstance( DateFormat.SHORT, LocaleHelper.getLocale() );
} else {
return null;
}
}
public static DateFormat getMediumDateFormat( final boolean date, final boolean time ) {
if ( date && time ) {
return DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.MEDIUM, LocaleHelper.getLocale() );
} else if ( date ) {
return DateFormat.getDateInstance( DateFormat.MEDIUM, LocaleHelper.getLocale() );
} else if ( time ) {
return DateFormat.getTimeInstance( DateFormat.MEDIUM, LocaleHelper.getLocale() );
} else {
return null;
}
}
public static DateFormat getLongDateFormat( final boolean date, final boolean time ) {
if ( date && time ) {
return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG, LocaleHelper.getLocale() );
} else if ( date ) {
return DateFormat.getDateInstance( DateFormat.LONG, LocaleHelper.getLocale() );
} else if ( time ) {
return DateFormat.getTimeInstance( DateFormat.LONG, LocaleHelper.getLocale() );
} else {
return null;
}
}
public static DateFormat getFullDateFormat( final boolean date, final boolean time ) {
if ( date && time ) {
return DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.FULL, LocaleHelper.getLocale() );
} else if ( date ) {
return DateFormat.getDateInstance( DateFormat.FULL, LocaleHelper.getLocale() );
} else if ( time ) {
return DateFormat.getTimeInstance( DateFormat.FULL, LocaleHelper.getLocale() );
} else {
return null;
}
}
public static NumberFormat getNumberFormat() {
return NumberFormat.getNumberInstance( LocaleHelper.getLocale() );
}
public static NumberFormat getCurrencyFormat() {
return NumberFormat.getCurrencyInstance( LocaleHelper.getLocale() );
}
public static String getClosestLocale( String locale, String[] locales ) {
// see if this locale is supported
if ( locales == null || locales.length == 0 ) {
return locale;
}
if ( locale == null || locale.length() == 0 ) {
return locales[0];
}
String localeLanguage = locale.substring( 0, 2 );
String localeCountry = ( locale.length() > 4 ) ? locale.substring( 0, 5 ) : localeLanguage;
int looseMatch = -1;
int closeMatch = -1;
int exactMatch = -1;
for ( int idx = 0; idx < locales.length; idx++ ) {
if ( locales[idx].equals( locale ) ) {
exactMatch = idx;
break;
} else if ( locales[idx].length() > 1 && locales[idx].substring( 0, 2 ).equals( localeLanguage ) ) {
looseMatch = idx;
} else if ( locales[idx].length() > 4 && locales[idx].substring( 0, 5 ).equals( localeCountry ) ) {
closeMatch = idx;
}
}
//CHECKSTYLE IGNORE EmptyBlock FOR NEXT 3 LINES
if ( exactMatch != -1 ) {
// do nothing we have an exact match
} else if ( closeMatch != -1 ) {
locale = locales[closeMatch];
} else if ( looseMatch != -1 ) {
locale = locales[looseMatch];
} else {
// no locale is close , just go with the first?
locale = locales[0];
}
return locale;
}
}