diff --git a/README.md b/README.md index 9fb5529..301abfa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Polyglot -Polyglot is an advanced and multifunctional library for localizing strings for Luminia Development projects. +Polyglot is an advanced and multifunctional library for localizing strings. ## Example of usage ```java @@ -26,12 +26,24 @@ Translation translation = context.createTranslation(new YamlFileProvider( new File("lang"), context.getLanguageStandard() )); translation.setDefaultLanguage(SimpleLanguage.ENG); // Default language -translation.setFallbackStrategy(key -> key + "-fallback"); // Fallback strategy for missing localizations + +// Strategy for determining the language when the requested language is not available. +// For example: return Russian when Ukrainian is not available, instead of the default English. +translation.setLanguageStrategy(LanguageStrategy.mappingsBuilder() + .put(SimpleLanguage.UKR, SimpleLanguage.RUS) + .build()); +// We can also set the default language using `LanguageStrategy.defaultResult(SimpleLanguage.ENG)`. + +// Fallback strategy for missing localizations +// You can also do the same thing this way: `translation.setFallbackStrategy(FallbackStrategy.suffix(“-fallback”));`. +// Or you can use `FallbackStrategy.keyToKey()` if you want the result to be the key of the missing locale. +translation.setFallbackStrategy(key -> key + "-fallback"); + translation.addTranslation(SimpleLanguage.ENG, "local.translation", "Local message with param [0]"); // Adding local translation // Translating the messages String local = translation.translate(SimpleLanguage.RUS, "local.translation", 1); -String global = translation.translate(SimpleLanguage.RUS, "local.translation", new KeyedTrParameters().put("local", "Parameter")); +String global = translation.translate(SimpleLanguage.RUS, "global.translation", new KeyedTrParameters().put("local", "Parameter")); System.out.println("Translated local message: " + local); System.out.println("Translated global message: " + global); diff --git a/api/src/main/java/com/luminiadev/polyglot/api/Translation.java b/api/src/main/java/com/luminiadev/polyglot/api/Translation.java index f8778f7..c4e72d1 100644 --- a/api/src/main/java/com/luminiadev/polyglot/api/Translation.java +++ b/api/src/main/java/com/luminiadev/polyglot/api/Translation.java @@ -4,6 +4,7 @@ import com.luminiadev.polyglot.api.parameter.TrParameters; import com.luminiadev.polyglot.api.parameter.formatter.TrParameterFormatter; import com.luminiadev.polyglot.api.util.FallbackStrategy; +import com.luminiadev.polyglot.api.util.LanguageStrategy; import java.util.Set; @@ -19,6 +20,8 @@ public interface Translation { void setDefaultLanguage(Language language); + void setLanguageStrategy(LanguageStrategy languageStrategy); + void setFallbackStrategy(FallbackStrategy fallbackStrategy); void addTranslation(Language language, String key, String value); diff --git a/api/src/main/java/com/luminiadev/polyglot/api/util/LanguageMappingBuilder.java b/api/src/main/java/com/luminiadev/polyglot/api/util/LanguageMappingBuilder.java new file mode 100644 index 0000000..b94253b --- /dev/null +++ b/api/src/main/java/com/luminiadev/polyglot/api/util/LanguageMappingBuilder.java @@ -0,0 +1,20 @@ +package com.luminiadev.polyglot.api.util; + +import com.luminiadev.polyglot.api.language.Language; + +import java.util.HashMap; +import java.util.Map; + +public final class LanguageMappingBuilder { + + private final Map mappings = new HashMap<>(); + + public LanguageMappingBuilder put(Language missingLanguage, Language mappedLanguage) { + this.mappings.put(missingLanguage, mappedLanguage); + return this; + } + + public LanguageStrategy build() { + return LanguageStrategy.mappingsOf(mappings); + } +} diff --git a/api/src/main/java/com/luminiadev/polyglot/api/util/LanguageStrategy.java b/api/src/main/java/com/luminiadev/polyglot/api/util/LanguageStrategy.java new file mode 100644 index 0000000..f609095 --- /dev/null +++ b/api/src/main/java/com/luminiadev/polyglot/api/util/LanguageStrategy.java @@ -0,0 +1,50 @@ +package com.luminiadev.polyglot.api.util; + +import com.luminiadev.polyglot.api.language.Language; + +import java.util.Map; + +/** + * Missing language strategy interface. Defines how to resolve missing language. + */ +@FunctionalInterface +public interface LanguageStrategy { + + /** + * Resolves a value for the given missing language. + * + * @param missingLanguage the missing language + * @return resolved value + */ + Language get(Language missingLanguage); + + /** + * Returns a default language. + * + * @param defaultLanguage default language + * @return strategy returning the specified language + */ + static LanguageStrategy defaultResult(Language defaultLanguage) { + return missingLanguage -> defaultLanguage; + } + + /** + * Returns a strategy based on passed mappings. + * + * @param mappings the map with language mappings + * @return strategy based on passed mappings + */ + static LanguageStrategy mappingsOf(Map mappings) { + return missingLanguage -> mappings.getOrDefault(missingLanguage, null); + } + + /** + * Crates the new language mappings builder. + * + * @return crated LanguageMappingBuilder + */ + static LanguageMappingBuilder mappingsBuilder() { + return new LanguageMappingBuilder(); + } +} + diff --git a/core/src/main/java/com/luminiadev/polyglot/core/BaseTranslation.java b/core/src/main/java/com/luminiadev/polyglot/core/BaseTranslation.java index 948ae76..2595f14 100644 --- a/core/src/main/java/com/luminiadev/polyglot/core/BaseTranslation.java +++ b/core/src/main/java/com/luminiadev/polyglot/core/BaseTranslation.java @@ -7,6 +7,7 @@ import com.luminiadev.polyglot.api.parameter.TrParameters; import com.luminiadev.polyglot.api.parameter.formatter.TrParameterFormatter; import com.luminiadev.polyglot.api.provider.TranslationProvider; +import com.luminiadev.polyglot.api.util.LanguageStrategy; import com.luminiadev.polyglot.core.parameter.KeyedTrParameters; import com.luminiadev.polyglot.core.parameter.SimpleTrParameters; import com.luminiadev.polyglot.core.parameter.formatter.BraceKeyedParameterFormatter; @@ -27,6 +28,7 @@ public class BaseTranslation implements Translation { private final Map, TrParameterFormatter> formatters; private Language defaultLanguage; + private LanguageStrategy languageStrategy; private FallbackStrategy fallbackStrategy; public BaseTranslation(TranslationContext context, TranslationProvider provider) { @@ -70,10 +72,23 @@ private Language resolveLanguage(Language requestedLanguage) { if (this.isLanguageAvailable(requestedLanguage)) { return requestedLanguage; } + + Language candidateLanguage = requestedLanguage; + while (true) { + candidateLanguage = this.languageStrategy != null ? this.languageStrategy.get(candidateLanguage) : null; + if (candidateLanguage == null) { + break; + } + if (this.isLanguageAvailable(candidateLanguage)) { + return candidateLanguage; + } + } + Language defaultLanguage = this.defaultLanguage != null ? this.defaultLanguage : context.getDefaultLanguage(); if (this.isLanguageAvailable(defaultLanguage)) { return defaultLanguage; } + return requestedLanguage; } @@ -163,6 +178,11 @@ public void setDefaultLanguage(Language language) { this.defaultLanguage = language; } + @Override + public void setLanguageStrategy(LanguageStrategy languageStrategy) { + this.languageStrategy = languageStrategy; + } + @Override public void setFallbackStrategy(FallbackStrategy fallbackStrategy) { this.fallbackStrategy = fallbackStrategy;