/*
* Copyright 2001-2013 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package com.uwyn.rife.tools;
import com.uwyn.rife.config.RifeConfig;
import com.uwyn.rife.resources.ResourceFinderClasspath;
import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Localization
{
public final static Pattern URL_PATTERN = Pattern.compile("(?:\\s*(\\w+):((?!//)[^,]+)\\s*)|(?:\\s*([^,]+)\\s*)");
private static HashMap<String, ResourceBundle> resourceBundlesOpened = new HashMap<>();
private static HashMap<String, Long> resourceBundleModificationTimes = new HashMap<>();
private static long lastModificationCheck = 0;
public static String extractLocalizedUrl(String url)
{
if (null == url)
{
return null;
}
if (!url.contains(":"))
{
return url;
}
else
{
Matcher matcher = URL_PATTERN.matcher(url);
String localized_url = null;
String default_lang = RifeConfig.Tools.getDefaultLanguage();
String fallback_url = null;
String group_lang;
String group_url;
String group_fallback;
while (matcher.find())
{
if (3 == matcher.groupCount())
{
group_lang = matcher.group(1);
group_url = matcher.group(2);
group_fallback = matcher.group(3);
if (group_fallback != null)
{
fallback_url = group_fallback;
}
else if (group_lang != null &&
group_url != null &&
default_lang != null &&
default_lang.equals(group_lang))
{
localized_url = group_url;
break;
}
}
}
if (null == localized_url)
{
if (null == fallback_url)
{
localized_url = null;
}
else
{
localized_url = fallback_url;
}
}
return localized_url;
}
}
public static char getChar(String key)
{
return getChar(null, key, null, null);
}
public static char getChar(String key, String language)
{
return getChar(null, key, language, null);
}
public static char getChar(String key, String language, String country)
{
return getString(null, key, null, language, country).charAt(0);
}
public static char getChar(String basename, String key, String language, String country)
{
return getString(basename, key, null, language, country).charAt(0);
}
public static String getString(String key)
{
return getString(null, key, null, null, null);
}
public static String getString(String key, Object[] parameters)
{
return getString(null, key, parameters, null, null);
}
public static String getString(String key, String language)
{
return getString(null, key, null, language, null);
}
public static String getString(String key, Object[] parameters, String language)
{
return getString(null, key, parameters, language, null);
}
public static String getString(String key, String language, String country)
{
return getString(null, key, null, language, country);
}
public static String getString(String key, Object[] parameters, String language, String country)
{
return getString(null, key, parameters, language, country);
}
public static String getString(String basename, String key, String language, String country)
{
return getString(basename, key, null, language, country);
}
public static String getString(String basename, String key, Object[] parameters, String language, String country)
{
ResourceBundle resource_bundle = getResourceBundle(basename, language, country);
if (null != resource_bundle)
{
String result;
if (null == parameters)
{
try
{
result = resource_bundle.getString(key);
}
catch (MissingResourceException e)
{
return key;
}
}
else
{
String pattern_string;
try
{
pattern_string = resource_bundle.getString(key);
}
catch (MissingResourceException e)
{
return key;
}
MessageFormat formatter;
formatter = new MessageFormat(pattern_string);
Locale locale = resource_bundle.getLocale();
if (locale != null)
{
formatter.setLocale(locale);
}
result = formatter.format(parameters);
}
return result;
}
else
{
return key;
}
}
public static Locale getLocale()
{
return getLocale(null, null);
}
public static Locale getLocale(String language)
{
return getLocale(language, null);
}
public static Locale getLocale(String language, String country)
{
if (null == language)
{
language = RifeConfig.Tools.getDefaultLanguage();
}
if (null == country)
{
country = RifeConfig.Tools.getDefaultCountry();
}
Locale locale = null;
if (null != language)
{
if (null == country)
{
locale = new Locale(language);
}
else
{
locale = new Locale(language, country);
}
}
return locale;
}
public static ResourceBundle getResourceBundle(String basename)
{
return getResourceBundle(basename, null, null);
}
public static ResourceBundle getResourceBundle(String basename, String language)
{
return getResourceBundle(basename, language, null);
}
public static ResourceBundle getResourceBundle(String basename, String language, String country)
{
if (null == basename)
{
basename = RifeConfig.Tools.getDefaultResourceBundle();
}
Locale locale = getLocale(language, country);
ResourceBundle result = getResourceBundle(basename, locale);
if (null == result)
{
result = getResourceBundle(basename, Locale.ENGLISH);
}
return result;
}
public static ResourceBundle getResourceBundle(String basename, Locale locale)
{
ResourceBundle result = null;
if (null != locale)
{
String most_detailed_candidate = basename + locale.toString();
// see if the resourcebundle reload is deactivated and thus fetch a previous copy without
// looking up the resource
if (!RifeConfig.Tools.getResourcebundleAutoReload() ||
System.currentTimeMillis() - lastModificationCheck <= RifeConfig.Global.getAutoReloadDelay())
{
result = resourceBundlesOpened.get(most_detailed_candidate);
if (result != null)
{
return result;
}
}
if (RifeConfig.Tools.getResourcebundleAutoReload())
{
lastModificationCheck = System.currentTimeMillis();
}
// build the list of possible candidates
ArrayList<String> candidates = new ArrayList<>();
StringBuilder resource_bundle_id_buffer = new StringBuilder(basename);
candidates.add(basename);
Locale default_locale = Locale.getDefault();
if (default_locale.getLanguage().length() > 0)
{
resource_bundle_id_buffer.append("_");
resource_bundle_id_buffer.append(default_locale.getLanguage());
candidates.add(resource_bundle_id_buffer.toString());
}
if (default_locale.getCountry().length() > 0)
{
resource_bundle_id_buffer.append("_");
resource_bundle_id_buffer.append(default_locale.getCountry());
candidates.add(resource_bundle_id_buffer.toString());
}
if (default_locale.getVariant().length() > 0)
{
resource_bundle_id_buffer.append("_");
resource_bundle_id_buffer.append(default_locale.getVariant());
candidates.add(resource_bundle_id_buffer.toString());
}
resource_bundle_id_buffer = new StringBuilder(basename);
if (locale.getLanguage().length() > 0)
{
resource_bundle_id_buffer.append("_");
resource_bundle_id_buffer.append(locale.getLanguage());
String candidate = resource_bundle_id_buffer.toString();
if (!candidates.contains(candidate))
{
candidates.add(candidate);
}
}
if (locale.getCountry().length() > 0)
{
resource_bundle_id_buffer.append("_");
resource_bundle_id_buffer.append(locale.getCountry());
String candidate = resource_bundle_id_buffer.toString();
if (!candidates.contains(candidate))
{
candidates.add(candidate);
}
}
if (locale.getVariant().length() > 0)
{
resource_bundle_id_buffer.append("_");
resource_bundle_id_buffer.append(locale.getVariant());
String candidate = resource_bundle_id_buffer.toString();
if (!candidates.contains(candidate))
{
candidates.add(candidate);
}
}
while (candidates.size() > 0)
{
String resource_bundle_id = candidates.remove(candidates.size() - 1);
try
{
// try to load the resource bundle as a class
Class resource_class;
try
{
resource_class = Localization.class.getClassLoader().loadClass(resource_bundle_id);
}
catch (ClassNotFoundException e)
{
resource_class = null;
}
if (resource_class != null)
{
if (ResourceBundle.class.isAssignableFrom(resource_class))
{
try
{
result = (ResourceBundle)resource_class.newInstance();
return result;
}
catch (IllegalAccessException | InstantiationException e)
{
resource_class = null;
result = null;
}
}
}
// try to load it as a properties file
resource_bundle_id = resource_bundle_id.replace('.', '/');
// no previous result found or checks should be made to see if the modification time changed
String name = resource_bundle_id + ".properties";
URL resource = ResourceFinderClasspath.getInstance().getResource(name);
if (resource != null)
{
Long previous_modification = resourceBundleModificationTimes.get(most_detailed_candidate);
long modification_time = -1;
if (RifeConfig.Tools.getResourcebundleAutoReload())
{
try
{
modification_time = ResourceFinderClasspath.getInstance().getModificationTime(resource);
}
catch (ResourceFinderErrorException e)
{
// don't do anything, the modification time will simply be negative
}
}
if (previous_modification != null &&
modification_time <= previous_modification)
{
result = resourceBundlesOpened.get(most_detailed_candidate);
}
else
{
try
{
result = new ReloadingBundle(resource);
resourceBundleModificationTimes.put(most_detailed_candidate, modification_time);
resourceBundlesOpened.put(most_detailed_candidate, result);
}
catch (IOException e)
{
result = null;
}
}
}
}
catch (MissingResourceException e)
{
result = null;
}
if (result != null)
{
return result;
}
}
}
return null;
}
}
class ReloadingBundle extends ResourceBundle
{
private Properties mProperties = null;
ReloadingBundle(URL resource)
throws IOException
{
mProperties = new Properties();
URLConnection connection = resource.openConnection();
connection.setUseCaches(false);
InputStream resourceAsStream = connection.getInputStream();
mProperties.load(resourceAsStream);
}
protected Object handleGetObject(String key)
{
return getProperties().get(key);
}
protected Properties getProperties()
{
return mProperties;
}
public Enumeration getKeys()
{
return Collections.enumeration(mProperties.keySet());
}
}