/*
* PS3 Media Server, for streaming any medias to your PS3.
* Copyright (C) 2008 A.Brochard
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License only.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.pms;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Class Messages provides a mechanism to localize the text messages found in
* UMS. It is based on {@link ResourceBundle}.
*
*/
public class Messages {
private static final String BUNDLE_NAME = "resources.i18n.messages";
private static ReadWriteLock resourceBundleLock = new ReentrantReadWriteLock();
private static ResourceBundle resourceBundle;
private static final ResourceBundle ROOT_RESOURCE_BUNDLE;
static {
/*
* This is called when the first call to any of the static class
* methods are done. PMS.setLocale() will call setLocaleBundle() to
* access the correct resource bundle, but we need something in the
* mean time if this is invoked before PM.setLocale() has been called.
* This can happen if any code calls getString() before configuration
* has been loaded, in which case the default locale will be used.
*/
resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
ROOT_RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME, Locale.ROOT, new ResourceBundle.Control() {
@Override
public List<Locale> getCandidateLocales(String name,
Locale locale) {
return Collections.singletonList(Locale.ROOT);
}
});
}
private Messages() {
}
/**
* Creates a resource bundle based on the given <code>Local</code> and
* keeps this for use by any calls to {@link #getString(String)}. If
* no matching <code>ResourceBundle</code> can be found, one is chosen
* from a number of candidates according to
* <a href="https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html#default_behavior">
* ResourceBundle default behavior</a>.
*
* @param locale the <code>Locale</code> from which the
* <code>ResourceBundle</code> is selected.
*/
public static void setLocaleBundle(Locale locale) {
if (locale == null) {
throw new IllegalArgumentException("locale cannot be null");
}
resourceBundleLock.writeLock().lock();
try {
if (isRootEnglish(locale)) {
resourceBundle = ROOT_RESOURCE_BUNDLE;
} else {
resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME, locale);
}
} finally {
resourceBundleLock.writeLock().unlock();
}
}
/**
* Returns the locale-specific string associated with the key.
*
* @param key
* Keys in UMS follow the format "group.x". group states where
* this key is likely to be used. For example, StatusTab refers
* to the status tab in the UMS GUI. "x" can be anything.
* @return Descriptive string if key is found or a copy of the key string if
* it is not.
*/
public static String getString(String key) {
resourceBundleLock.readLock().lock();
try {
return getString(key, resourceBundle);
} finally {
resourceBundleLock.readLock().unlock();
}
}
public static String getString(String key, Locale locale) {
if (locale == null) {
return getString(key);
}
// Selecting base bundle (en-US) for all English variants but British
if (isRootEnglish(locale)) {
return getRootString(key);
}
ResourceBundle rb = ResourceBundle.getBundle(BUNDLE_NAME, locale);
if (rb == null) {
rb = ROOT_RESOURCE_BUNDLE;
}
return getString(key, rb);
}
/**
* Returns the string from the root language file (messages.properties)
* regardless of default <code>Locale</code>. Java will otherwise choose
* a <code>Locale</code> for a "similar" language or the default
* <code>Locale</code> if the requested locale can't be found. The root
* <code>Locale</code> is only chosen as a last resort. See
* <a href="https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html#default_behavior">
* ResourceBundle default behavior</a> for more information about the
* selection process.<br><br>
*
* For parameter and return value see {@link #getString(String)}
*/
public static String getRootString(String key) {
return getString(key, ROOT_RESOURCE_BUNDLE);
}
private static String getString(String key, ResourceBundle rb) {
try {
return rb.getString(key);
} catch (MissingResourceException e) {
return '!' + key + '!';
}
}
/**
* Checks if the given <code>Locale</code> should use the root language
* file (messages.properties) which is en-US. Currently that is all variants
* of English but British English.
* @param locale the <code>Locale</code> to check
* @return The result
*/
private static boolean isRootEnglish(Locale locale) {
return locale.getLanguage().toLowerCase(Locale.ENGLISH).equals("en") && !locale.getCountry().equals("GB");
}
}