All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.freya02.botcommands.api.localization.Localization Maven / Gradle / Ivy

package com.freya02.botcommands.api.localization;

import com.freya02.botcommands.api.Logging;
import com.freya02.botcommands.api.localization.providers.DefaultLocalizationMapProvider;
import com.freya02.botcommands.api.localization.providers.LocalizationMapProvider;
import com.freya02.botcommands.api.localization.providers.LocalizationMapProviders;
import com.freya02.botcommands.internal.commands.application.localization.BCLocalizationFunction;
import com.freya02.botcommands.internal.core.SingleLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import org.slf4j.Logger;

import java.util.*;

/**
 * Provides a low level API for localization.
 * 
You can get an instance using {@link #getInstance(String, Locale)}, as well as invalidate cached localization data, as to reload them on next use. *
You can customize localization providers, as well as the localization templates they give, each provider is tested until one returns a valid localization bundle, see {@link DefaultLocalizationMapProvider} for the default specification. *

* You can add more localization bundle providers using {@link LocalizationMapProviders#registerProvider(LocalizationMapProvider)}. */ public class Localization { private static final Logger LOGGER = Logging.getLogger(); private static final ResourceBundle.Control CONTROL = ResourceBundle.Control.getNoFallbackControl(ResourceBundle.Control.FORMAT_DEFAULT); private static final Map> localizationMap = Collections.synchronizedMap(new HashMap<>()); private final Map templateMap; private final Locale effectiveLocale; private Localization(@NotNull LocalizationMap bundle) { this.effectiveLocale = bundle.effectiveLocale(); this.templateMap = bundle.templateMap(); } @Nullable private static BestLocale chooseBestLocale(String baseName, Locale targetLocale) { final List candidateLocales = CONTROL.getCandidateLocales(baseName, targetLocale); for (Locale candidateLocale : candidateLocales) { //Try to retrieve with the locale final LocalizationMap localizationBundle = LocalizationMapProviders.cycleProviders(baseName, candidateLocale); if (localizationBundle != null) { return new BestLocale(localizationBundle.effectiveLocale(), localizationBundle); } } return null; } @Nullable private static Localization retrieveBundle(String baseName, Locale targetLocale) { final BestLocale bestLocale = chooseBestLocale(baseName, targetLocale); if (bestLocale == null) { if (SingleLogger.current().tryLog(baseName)) LOGGER.warn("Could not find localization resources for '{}'", baseName); return null; } else { if (!bestLocale.locale().equals(targetLocale)) { //Not default if (bestLocale.locale().toString().isEmpty()) { //neutral lang if (SingleLogger.current().tryLog(baseName, targetLocale.toLanguageTag())) LOGGER.warn("Unable to find bundle '{}' with locale '{}', falling back to neutral lang", baseName, targetLocale); } else { if (SingleLogger.current().tryLog(baseName, targetLocale.toLanguageTag(), bestLocale.locale.toLanguageTag())) LOGGER.warn("Unable to find bundle '{}' with locale '{}', falling back to '{}'", baseName, targetLocale, bestLocale.locale()); } } return new Localization(bestLocale.bundle()); } } /** * Invalidates all the localization bundles with the specified base name * * @param baseName The base name of the bundles to invalidate */ public static void invalidateLocalization(@NotNull String baseName) { SingleLogger.get(BCLocalizationFunction.class).clear(); SingleLogger.current().clear(); localizationMap.remove(baseName); } /** * Invalidates the localization bundles with the specified base name and locale * * @param baseName The base name of the bundles to invalidate * @param locale The locale of the bundle to invalidate */ public static void invalidateLocalization(@NotNull String baseName, @NotNull Locale locale) { SingleLogger.get(BCLocalizationFunction.class).clear(); SingleLogger.current().clear(); localizationMap.computeIfAbsent(baseName, x -> Collections.synchronizedMap(new HashMap<>())).remove(locale); } /** * Gets the localization instance for the specified bundle name and locale *
This cycles through all the available {@link LocalizationMapProvider LocalizationBundleProviders} until one returns a valid localization bundle * * @param baseName The name of the bundle * @param locale The locale of the bundle * * @return The localization instance for this bundle */ @Nullable public static Localization getInstance(@NotNull String baseName, @NotNull Locale locale) { final Map localeMap = localizationMap.computeIfAbsent(baseName, x -> Collections.synchronizedMap(new HashMap<>())); final Localization value = localeMap.get(locale); if (value != null) { return value; } else { try { final Localization newValue = retrieveBundle(baseName, locale); localeMap.put(locale, newValue); return newValue; } catch (Exception e) { throw new RuntimeException("Unable to get bundle '%s' for locale '%s'".formatted(baseName, locale), e); } } } /** * Returns an unmodifiable view of the localization path -> LocalizationTemplate map * * @return An unmodifiable view of the localization path -> LocalizationTemplate map */ @NotNull @UnmodifiableView public Map getTemplateMap() { return Collections.unmodifiableMap(templateMap); } /** * Returns the {@link LocalizationTemplate} for the specified localization path * * @param path The localization path of the template * * @return The {@link LocalizationTemplate} for the specified localization path */ @Nullable public LocalizationTemplate get(String path) { return templateMap.get(path); } /** * Returns the effective Locale for this Localization instance *
This might not be the same as the one supplied in {@link #getInstance(String, Locale)} due to missing bundles * * @return The effective Locale for this Localization instance */ public Locale getEffectiveLocale() { return effectiveLocale; } private record BestLocale(Locale locale, LocalizationMap bundle) {} public record Entry(String key, Object value) { /** * Create a new localization entry, this binds a key (from a templated string) into a value * Highly recommended to use this method with a static import * * @param key The key from the templated string * @param value The value to assign it to * * @return The entry */ @NotNull public static Entry entry(@NotNull String key, @NotNull Object value) { return new Entry(key, value); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy