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

io.sphere.sdk.models.LocalizedString Maven / Gradle / Ivy

There is a newer version: 1.0.0-M26
Show newest version
package io.sphere.sdk.models;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.type.TypeReference;
import io.sphere.sdk.utils.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collector;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static io.sphere.sdk.utils.IterableUtils.toStream;
import static io.sphere.sdk.utils.MapUtils.immutableCopyOf;
import static io.sphere.sdk.utils.MapUtils.mapOf;
import static java.lang.String.format;
import static java.util.Collections.*;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;

/**
 * A localized string is a object where the keys are {@link Locale}s (HTTP API: ISO language tags),
 * and the values are the corresponding strings used for that language.
 *
 * {@include.example io.sphere.sdk.models.LocalizedStringTest#defaultUseCases()}
 */
public class LocalizedString extends Base {

    private static final Comparator> BY_LOCALE_COMPARATOR = (left, right) -> left.getKey().toString().compareTo(right.getKey().toString());

    @JsonIgnore
    private final Map translations;

    @JsonCreator
    private LocalizedString(final Map translations) {
        //the Jackson mapper may passes null here and it is not possible to use an immutable map
        this.translations = immutableCopyOf(Optional.ofNullable(translations).orElse(new HashMap<>()));
    }

    /**
     * Creates an instance without any value.
     *
     * @return instance without any value
     */
    @JsonIgnore
    public static LocalizedString of() {
        return of(emptyMap());
    }

    /**
     * Creates an instance without any value.
     *
     * @return instance without any value
     */
    public static LocalizedString empty() {
        return of();
    }

    /**
     * Creates an instance with one locale translation pair.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#createFromOneValue()}
     *
     * @param locale the locale for the one translation
     * @param value the translation for the specified locale
     * @return translation for one language
     */
    @JsonIgnore
    public static LocalizedString of(final Locale locale, final String value) {
        requireNonNull(locale);
        requireNonNull(value);
        return of(mapOf(locale, value));
    }

    /**
     * Creates an instance for two different locales.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#createFromTwoValues()}
     *
     * @param locale1 the first locale
     * @param value1 the translation corresponding to {@code locale1}
     * @param locale2 the second locale which differs from {@code locale1}
     * @param value2 the translation corresponding to {@code locale2}
     * @return new instance for two key value pairs
     */
    @JsonIgnore
    public static LocalizedString of(final Locale locale1, final String value1, final Locale locale2, final String value2) {
        return of(mapOf(locale1, value1, locale2, value2));
    }

    /**
     * Creates an instance by supplying a map. Changes to the map won't affect the instance.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#createByMap()}
     *
     * @param translations the key value pairs for the translation
     * @return a new instance which has the same key value pairs as {@code translation} at creation time
     */
    @JsonIgnore
    public static LocalizedString of(final Map translations) {
        requireNonNull(translations);
        return new LocalizedString(translations);
    }

    /**
     * Creates an instance with one translation for English ({@link Locale#ENGLISH}).
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#ofEnglishLocale()}
     *
     * @param value the translation in English
     * @return new instance with one key value pair
     */
    @JsonIgnore
    public static LocalizedString ofEnglishLocale(final String value) {
        requireNonNull(value);
        return of(Locale.ENGLISH, value);
    }

    /**
     * Creates a new {@link LocalizedString} containing the given entries and the new one.
     * It is not allowed to override existing entries.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#createANewLocalizedStringByAddingALocale()}
     *
     * @param locale the additional locale of the new entry
     * @param value the value for the locale
     * @return a LocalizedString containing this data and the from the parameters.
     * @throws IllegalArgumentException if duplicate locales are provided
     */
    public LocalizedString plus(final Locale locale, final String value) {
        if (translations.containsKey(locale)) {
            throw new IllegalArgumentException(format("Duplicate keys (%s) for map creation.", locale));
        }
        final Map newMap = new HashMap<>();
        newMap.putAll(translations);
        newMap.put(locale, value);
        return new LocalizedString(newMap);
    }

    /**
     * Searches the translation for an exact locale and returning the result in an {@link Optional}.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#find()}
     *
     * @param locale the locale which should be searched
     * @return A filled optional with the translation belonging to {@code locale} or an empty optional if the locale is not present.
     */
    @Nonnull
    public Optional find(final Locale locale) {
        return Optional.ofNullable(get(locale));
    }

    /**
     * Searches the translation for an exact locale by using {@code null} in the case the locale ist not present.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#getByOneLocale()}
     *
     * @param locale the locale which should be searched
     * @return the translation belonging to {@code locale} or null if the locale is not present.
     */
    @Nullable
    public String get(final Locale locale) {
        return translations.get(locale);
    }

    /**
     * Searches the translation for some exact locales in the order they appear and returning the result in an {@link Optional}.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#findByMultipleLocales()}
     *
     * @param locales the locale which should be searched, the first exact match wins
     * @return A filled optional with the translation belonging to one of the {@code locales} or an empty optional if none of the locales is not present.
     */
    @Nonnull
    public Optional find(final Iterable locales) {
        final Optional firstFoundLocale = toStream(locales).filter(locale -> translations.containsKey(locale)).findFirst();
        return firstFoundLocale.map(foundLocale -> get(foundLocale));
    }

    /**
     * Searches the translation for some exact locales in the order they appear and using null as result if no match could be found.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#getByMultipleLocales()}
     *
     * @param locales the locale which should be searched, the first exact match wins
     * @return the translation belonging to one of the {@code locales} or null if none of the locales is not present.
     */
    @Nullable
    public String get(final Iterable locales) {
        return find(locales).orElse(null);
    }

    /**
     * Searches a translation which matches a locale in {@code locales} and uses language fallbackes.
     * If locales which countries are used then the algorithm searches also for the pure language locale.
     * So if "en_US" could not be found then "en" will be tried.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#getTranslation()}
     *
     * @param locales the locales to try out
     * @return a translation matching one of the locales or null
     */
    @Nullable
    public String getTranslation(final Iterable locales) {
        return StreamSupport.stream(locales.spliterator(), false)
                .map(localeToFind -> {
                    String match = get(localeToFind);
                    if (match == null) {
                        final Locale pureLanguageLocale = new Locale(localeToFind.getLanguage());
                        match = get(pureLanguageLocale);
                    }
                    return match;
                })
                .filter(x -> x != null)
                .findFirst()
                .orElse(null);
    }

    /**
     * Creates a new instance where each translation value is transformed with {@code function}.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#mapValue()}
     *
     * @param function transforms a value for a locale into a new value
     * @return a new {@link LocalizedString} which consist all elements for this transformed with {@code function}
     */
    public LocalizedString mapValue(final BiFunction function) {
        return stream().map(entry -> {
            final String newValue = function.apply(entry.getLocale(), entry.getValue());
            return LocalizedStringEntry.of(entry.getLocale(), newValue);
        }).collect(streamCollector());
    }

    /**
     * Creates a new Stream of entries.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#streamAndCollector()}
     *
     * @return stream of all entries
     */
    public Stream stream() {
        return translations.entrySet().stream().map(entry -> LocalizedStringEntry.of(entry.getKey(), entry.getValue()));
    }

    /**
     * Collector to collect a stream of {@link LocalizedStringEntry}s to one {@link LocalizedString}.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#streamAndCollector()}
     *
     * @return collector
     */
    public static Collector streamCollector() {
        final Collector, LocalizedString> result =
                Collector.of(HashMap::new, (Map tmpMap, LocalizedStringEntry entry) -> tmpMap.put(entry.getLocale(), entry.getValue()), (Map left, Map right) -> {
                    left.putAll(right);
                    return left;
                }, (Map entryMap) -> LocalizedString.of(entryMap));
        return result;
    }

    /**
     * Creates a new {@link LocalizedString} where all translations are slugified (remove whitespace, etc.).
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#slugified()}
     *
     * @return new instance
     */
    public LocalizedString slugified() {
        return mapValue((locale, value) -> StringUtils.slugify(value));
    }

    /**
     * Creates a new {@link LocalizedString} where all translations are slugified (remove whitespace, etc.) and a random supplement is added.
     * This slugify methods appends a random string for a little uniqueness.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#slugifyUniqueDemo()}
     *
     * @return new instance
     */
    public LocalizedString slugifiedUnique() {
        return mapValue((locale, value) -> StringUtils.slugifyUnique(value));
    }

    /**
     * Returns all locales included in this instance.
     *
     * {@include.example io.sphere.sdk.models.LocalizedStringTest#getLocales()}
     * @return locales
     */
    @JsonIgnore
    @Nonnull
    public Set getLocales() {
        return translations.keySet();
    }

    /**
     * Delivers an immutable map of the translation.
     *
     * @return the key-value pairs for the translation
     */
    @JsonAnyGetter//@JsonUnwrap supports not maps, but this construct puts map content on top level
    private Map getTranslations() {
        return immutableCopyOf(translations);
    }

    @Override
    public String toString() {
        return "LocalizedString(" +
                translations
                        .entrySet()
                        .stream()
                        .sorted(BY_LOCALE_COMPARATOR)
                        .map(entry -> entry.getKey() + " -> " + entry.getValue())
                        .collect(joining(", "))
                + ")";
    }

    @SuppressWarnings("unused")//used by Jackson JSON mapper
    @JsonAnySetter
    private void set(final String languageTag, final String value) {
        translations.put(Locale.forLanguageTag(languageTag), value);
    }

    public static TypeReference typeReference() {
        return new TypeReference() {
            @Override
            public String toString() {
                return "TypeReference";
            }
        };
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy