com.rapiddweller.common.LocaleUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rd-lib-common Show documentation
Show all versions of rd-lib-common Show documentation
'rapiddweller Common' is an open source Java library
forked from Databene Commons by Volker Bergmann.
It provides extensions to the Java core library by utility classes, abstract concepts
and concrete implementations.
/*
* Copyright (C) 2004-2015 Volker Bergmann ([email protected]).
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.rapiddweller.common;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
/**
* Provides locale operations like determining the parent of a locale,
* finding a locale by code, providing the characters of a locale
* and a so-called 'fallback locale'.
* Created: 26.09.2006 23:34:41
*
* @author Volker Bergmann
*/
public final class LocaleUtil {
/**
* The locale to use by default
*/
private static final Locale FALLBACK_LOCALE = Locale.US;
/**
* collects the special letters of locales as set of Characters, indexed by the locale.
*/
private static Map> specialLetters;
/** Static initializer calls readConfigFile(). @see #readConfigFile() */
static {
readConfigFile();
}
// interface -------------------------------------------------------------------------------------------------------
/**
* Returns a set that contains all letters of the specified locale.
*
* @param locale the locale of which the character set is requested
* @return a set of characters that contains all letters of the specified locale
* @throws UnsupportedOperationException if the locale is not supported
*/
public static Set letters(Locale locale) {
Set set = nullTolerantLetters(locale);
if (set == null) {
throw new UnsupportedOperationException("Locale not supported: " + locale);
}
return set;
}
/**
* Determines a locale's parent, e.g. for a locale 'de_DE' it returns 'de'.
*
* @param locale the locale of which to determine the parent
* @return the locale's parent, or null if the locale has no parent.
*/
public static Locale parent(Locale locale) {
String variant = locale.getVariant();
if (!StringUtil.isEmpty(variant)) {
if (variant.contains("_")) {
String[] variantPath = StringUtil.tokenize(variant, '_');
variant = ArrayFormat.formatPart("_", 0, variantPath.length - 1, variantPath);
return new Locale(locale.getLanguage(), locale.getCountry(), variant);
} else {
return new Locale(locale.getLanguage(), locale.getCountry());
}
} else if (!StringUtil.isEmpty(locale.getCountry())) {
return new Locale(locale.getLanguage());
} else {
return null;
}
}
/**
* Returns the fallback locale.
* This differs from the default locale for cases in which it is desirable to
* restrict the used character ranges to an unproblematic minimum.
*
* @return the fallback locale.
*/
public static Locale getFallbackLocale() {
return FALLBACK_LOCALE;
}
/**
* Maps the locale code to a locale, e.g. de_DE to Locale.GERMANY.
*
* @param code the locale colde to map
* @return a locale instance the represents the code
*/
public static Locale getLocale(String code) {
if (StringUtil.isEmpty(code)) {
throw new IllegalArgumentException("code is empty");
}
String[] path = StringUtil.tokenize(code, '_');
switch (path.length) {
case 1:
return new Locale(path[0]);
case 2:
return new Locale(path[0], path[1]);
case 3:
return new Locale(path[0], path[1], path[2]);
default:
return new Locale(path[0], path[1], ArrayFormat.formatPart("_", 2, path.length - 2, path));
}
}
/**
* Available locale url string.
*
* @param baseName the base name
* @param locale the locale
* @param suffix the suffix
* @return the string
*/
public static String availableLocaleUrl(String baseName, Locale locale, String suffix) {
String localeString = locale.toString();
do {
String url = baseName;
if (!StringUtil.isEmpty(localeString)) {
url += "_" + localeString;
}
url += suffix;
if (IOUtil.isURIAvailable(url)) {
return url;
}
localeString = reduceLocaleString(localeString);
} while (localeString != null);
return null;
}
private static String reduceLocaleString(String localeString) {
if (localeString == null || localeString.length() == 0) {
return null;
}
int separatorIndex = localeString.lastIndexOf('_');
if (separatorIndex < 0) {
return "";
}
return localeString.substring(0, separatorIndex);
}
/**
* Gets default country code.
*
* @return the default country code
*/
public static String getDefaultCountryCode() {
String result = Locale.getDefault().getCountry();
if (StringUtil.isEmpty(result)) {
result = getFallbackLocale().getCountry();
}
return result;
}
/**
* Language locale.
*
* @param locale the locale
* @return the locale
*/
public static Locale language(Locale locale) {
Locale result = locale;
Locale parent;
while ((parent = parent(result)) != null) {
result = parent;
}
return result;
}
// private helpers -------------------------------------------------------------------------------------------------
/**
* @param locale the locale of which to get the letters.
* @return the letters of a locale, null if the locale is unknown.
*/
private static Set nullTolerantLetters(Locale locale) {
if (locale == null) {
return null;
}
Set set = specialLetters.get(locale);
if (set != null) {
return set;
}
Locale parent = locale;
while ((parent = parent(parent)) != null) {
set = specialLetters.get(parent);
if (set != null) {
return set;
}
}
return latinSet();
}
/**
* Reads the config file com/rapiddweller/common/special-letters.properties from the file system or the path
* and initializes the internal specialLetters map.
*/
private static void readConfigFile() {
try {
specialLetters = new HashMap<>();
Map properties = IOUtil.readProperties(
"com/rapiddweller/common/special-letters.properties", Encodings.UTF_8);
for (Map.Entry entry : properties.entrySet()) {
Locale locale = getLocale(String.valueOf(entry.getKey()));
String specialChars = String.valueOf(entry.getValue());
Set charSet = latinSet();
for (int i = 0; i < specialChars.length(); i++) {
charSet.add(specialChars.charAt(i));
}
specialLetters.put(locale, charSet);
}
} catch (IOException e) {
throw new ConfigurationError("Setup file for locale-specific letters is missing", e);
}
}
private static Set latinSet() {
return new CharSet('A', 'Z').addRange('a', 'z').getSet();
}
/**
* Run in locale.
*
* @param locale the locale
* @param task the task
*/
public static void runInLocale(Locale locale, Runnable task) {
Locale realLocale = Locale.getDefault();
try {
Locale.setDefault(locale);
task.run();
} finally {
Locale.setDefault(realLocale);
}
}
/**
* Call in locale t.
*
* @param the type parameter
* @param locale the locale
* @param task the task
* @return the t
* @throws Exception the exception
*/
public static T callInLocale(Locale locale, Callable task) throws Exception {
Locale realLocale = Locale.getDefault();
try {
Locale.setDefault(locale);
return task.call();
} finally {
Locale.setDefault(realLocale);
}
}
/**
* Gets decimal separator.
*
* @return the decimal separator
*/
public static char getDecimalSeparator() {
return new DecimalFormat().getDecimalFormatSymbols().getDecimalSeparator();
}
}