package tc.oc.commons.core.localization;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import tc.oc.commons.core.util.CacheUtils;
import tc.oc.commons.core.util.Pair;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a single message resource file across all languages
*/
public class TranslationSet {
private final String name;
private final LoadingCache<Locale, Optional<ResourceBundle>> bundles;
private final LoadingCache<Pair<String, Locale>, Optional<MessageFormat>> messages;
public TranslationSet(String name) {
this.name = checkNotNull(name);
bundles = CacheUtils.newCache(locale -> {
try {
return Optional.of(ResourceBundle.getBundle(name, locale, new ResourceBundle.Control() {
@Override
public Locale getFallbackLocale(String baseName, Locale locale) {
// This prevents the OS locale from being used instead of Locale.ENGLISH
return null;
}
}));
} catch(MissingResourceException e) {
return Optional.empty();
}
});
bundles.refresh(Locales.DEFAULT_LOCALE);
messages = CacheUtils.newCache(key -> {
try {
return bundles.getUnchecked(key.second)
.map(bundle -> Formats.quotedMessage(bundle.getString(key.first), key.second));
} catch(MissingResourceException e) {
return Optional.empty();
}
});
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object that) {
return this == that || (that instanceof TranslationSet &&
this.name.equals(((TranslationSet) that).name));
}
public boolean hasLocale(Locale locale) {
return bundles.getUnchecked(locale).isPresent();
}
public boolean hasKey(Locale locale, String key) {
return pattern(key, locale).isPresent();
}
public boolean hasKey(String key) {
return hasKey(Locales.DEFAULT_LOCALE, key);
}
public Set<String> getKeys(Locale locale) {
return bundles.getUnchecked(locale)
.map(ResourceBundle::keySet)
.orElse(ImmutableSet.of());
}
public Set<String> getKeys() {
return getKeys(Locales.DEFAULT_LOCALE);
}
public Optional<MessageFormat> pattern(String key, Locale locale) {
return messages.getUnchecked(Pair.of(key, locale));
}
public @Nullable String render(String key, Locale locale, Object... arguments) {
return pattern(key, locale).map(message -> message.format(arguments))
.orElse(null);
}
}