fi.evolver.ai.vaadin.translations.CompositeI18nProvider Maven / Gradle / Ivy
package fi.evolver.ai.vaadin.translations;
import java.io.Serial;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.vaadin.flow.i18n.I18NProvider;
@Component
public class CompositeI18nProvider implements I18NProvider {
@Serial
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(CompositeI18nProvider.class);
final Set providedLocales;
private final List providers;
@Value("${vaadin.provided-languages:}")
private List providedLanguages;
@Value("${vaadin.disable-all-translations:false}")
private boolean disableTranslations;
private static final int MAX_CACHE_ENTRIES = 512;
private static final Map providerCache = Collections.synchronizedMap(
new LinkedHashMap(MAX_CACHE_ENTRIES, 0.75f, true) {
private static final long serialVersionUID = 1L;
@Override
public boolean removeEldestEntry(Map.Entry eldest) {
return size() >= MAX_CACHE_ENTRIES;
}
});
@Autowired
public CompositeI18nProvider(List providers) {
this.providers = providers;
providedLocales = this.providers.stream().flatMap(p -> p.getProvidedLocales().stream()).collect(Collectors.toSet());
LOG.debug("Initializing i18n with providers: {}",
String.join(", ", providers.stream().map(l -> l.getClass().toString()).toList()));
}
@Override
public List getProvidedLocales() {
if (providedLanguages == null || providedLanguages.isEmpty())
return providedLocales.stream().toList();
return providedLocales.stream()
.filter(x -> (x.equals(Locale.ROOT) && providedLanguages.contains("en")) || providedLanguages.contains(x.getLanguage()))
.toList();
}
@Override
public String getTranslation(String key, Locale locale, Object... params) {
if (disableTranslations)
return key;
String value = getTranslationFromProviders(key, locale, params);
if (params != null && params.length > 0)
return new MessageFormat(value, locale).format(params);
return value;
}
public String getTranslationFromProviders(String key, Locale locale, Object... params) {
final String cacheKey = locale.toString() + ";" + key;
TranslationProvider cachedProvider = providerCache.get(cacheKey);
if (cachedProvider != null && cachedProvider.hasTranslation(key, locale))
return cachedProvider.getTranslation(key, locale);
LOG.trace("Getting translation for key \"{}\" and locale: {}", key, locale.toString());
for (TranslationProvider provider : providers) {
if (!providesLocale(provider, locale)) {
LOG.trace("\tSkipping {} because it doesn't provide the requested locale", provider.getClass());
continue;
}
if (provider.hasTranslation(key, locale)) {
providerCache.put(cacheKey, provider);
return provider.getTranslation(key, locale);
}
else
LOG.trace("\tSkipping {} because it doesn't have the translation key", provider.getClass());
}
return key;
}
private static boolean providesLocale(TranslationProvider provider, Locale locale) {
return provider.getProvidedLocales().contains(locale)
|| provider.getProvidedLocales().contains(Locale.ROOT)
|| provider.getProvidedLocales().stream()
.anyMatch(l -> l.getLanguage().equals(locale.getLanguage()));
}
public static void clearCache() {
providerCache.clear();
}
}