package com.github.czyzby.lml.uedi.i18n; import java.lang.reflect.Member; import java.util.Locale; import com.github.czyzby.kiwi.util.common.Strings; import com.github.czyzby.kiwi.util.gdx.preference.ApplicationPreferences; import com.github.czyzby.lml.uedi.preferences.impl.AbstractPreference; import com.github.czyzby.uedi.stereotype.Provider; /** Manages application's locale preference. Reloads i18n bundles on preference change. * * @author MJ */ public class LocalePreference extends AbstractPreference implements Provider<Locale> { private final I18NBundleProvider i18nBundleProvider; private Locale locale; /** Constructs locale preference with the default preferences object. * * @param i18nBundleProvider will be used to reload i18n bundles on locale change. */ public LocalePreference(final I18NBundleProvider i18nBundleProvider) { super(ApplicationPreferences.getPreferences()); locale = fromString(getValue()); this.i18nBundleProvider = i18nBundleProvider; } @Override public String getKey() { return "locale"; } @Override public String getDefault() { return "en"; } @Override public Class<? extends Locale> getType() { return Locale.class; } @Override public Locale provide(final Object target, final Member member) { return locale; } @Override public String setValue(final String value) { final String previous = super.setValue(Strings.isEmpty(value) ? getDefault() : value); if (!Strings.equals(previous, value)) { setLocale(fromString(value)); } return previous; } /** Reloads {@link com.badlogic.gdx.utils.I18NBundle i18n bundles} managed by the application if the locale changed. * * @param locale will become current locale. */ public void setLocale(final Locale locale) { if (!equals(this.locale, locale)) { this.locale = locale; super.setValue(toString(locale)); i18nBundleProvider.reloadBundles(locale); } } /** @return current locale used by the {@link com.badlogic.gdx.utils.I18NBundle i18n bundles}. */ public Locale getLocale() { return locale; } /** @param locale will be checked. * @return true if the passed locale is current application's locale. */ public boolean isCurrent(final Locale locale) { return equals(this.locale, locale); } /** A safe, cross-platform way of converting serialized locale string to {@link Locale} instance. Matches * {@link #toString(Locale)} serialization implementation. * * @param locale locale converted to string. * @return {@link Locale} stored the deserialized data. */ public static Locale fromString(final String locale) { final String[] data = Strings.split(locale, '_'); if (data.length == 1) { return new Locale(data[0]); } else if (data.length == 2) { return new Locale(data[0], data[1]); } else if (data.length == 3) { return new Locale(data[0], data[1], data[2]); } throw new IllegalArgumentException("Invalid locale string: " + locale); } /** A safe, cross-platform way of converting {@link Locale} to string. Matches {@link #fromString(String)} * deserialization implementation. * * @param locale will be serialized to string. * @return passed locale serialized as string using '_' to separate locale parts. */ public static String toString(final Locale locale) { // String language, String country, String variant if (Strings.isEmpty(locale.getCountry())) { return locale.getLanguage(); } else if (Strings.isEmpty(locale.getVariant())) { return locale.getLanguage() + '_' + locale.getCountry(); } return locale.getLanguage() + '_' + locale.getCountry() + "_" + locale.getVariant(); } /** Safe cross-platform way of comparing locales. * * @param localeA will be compared. * @param localeB will be compared. * @return true if the passed locales are the same object or represent the same locale. */ public static boolean equals(final Locale localeA, final Locale localeB) { return localeA == localeB || Strings.equals(localeA.getLanguage(), localeB.getLanguage()) && Strings.equals(localeA.getCountry(), localeB.getCountry()) && Strings.equals(localeA.getVariant(), localeB.getVariant()); } }