diff --git a/app/build.gradle b/app/build.gradle index 55d78a3..c6f1f96 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,6 +21,12 @@ android { versionCode 25 versionName = getVersionName() testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + def supportedLocales = ["en", "ast", "ru", "it", "ca", "cs", "zh-CN", "ja", "pt", "pt-BR", + "pl", "sl", "sk", "lt", "eu", "iw", "fr", "es", "hr", "hu", "nl", + "bg", "de", "ko", "uk"] + buildConfigField "String[]", "SUPPORTED_LOCALES", "new String[]{\""+ + supportedLocales.join("\",\"")+"\"}" } File keystoreFile = file('keystore.properties') diff --git a/app/src/main/java/org/xbmc/kore/Settings.java b/app/src/main/java/org/xbmc/kore/Settings.java index 3f8ad50..83bb7e2 100644 --- a/app/src/main/java/org/xbmc/kore/Settings.java +++ b/app/src/main/java/org/xbmc/kore/Settings.java @@ -171,6 +171,9 @@ public class Settings { public static final String KEY_PREF_DISABLE_LOCAL_PLAY = "pref_disable_local_play"; public static final boolean DEFAULT_PREF_DISABLE_LOCAL_PLAY = false; + public static final String KEY_PREF_LANGUAGE = "pref_language"; + public static final String KEY_PREF_SELECTED_LANGUAGE = "pref_selected_language"; + /** * Determines the bit flags used by {@link DownloadManager.Request} to correspond to the enabled network connections * from the settings screen. diff --git a/app/src/main/java/org/xbmc/kore/ui/BaseActivity.java b/app/src/main/java/org/xbmc/kore/ui/BaseActivity.java index 9c3d42b..08b96ac 100644 --- a/app/src/main/java/org/xbmc/kore/ui/BaseActivity.java +++ b/app/src/main/java/org/xbmc/kore/ui/BaseActivity.java @@ -22,6 +22,7 @@ import android.support.v7.app.AppCompatActivity; import org.xbmc.kore.Settings; import org.xbmc.kore.utils.UIUtils; +import org.xbmc.kore.utils.Utils; /** * Base activity, where common behaviour is implemented @@ -33,9 +34,19 @@ public abstract class BaseActivity extends AppCompatActivity { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); setTheme(UIUtils.getThemeResourceId( prefs.getString(Settings.KEY_PREF_THEME, Settings.DEFAULT_PREF_THEME))); + + setPreferredLocale(); super.onCreate(savedInstanceState); } + private void setPreferredLocale() { + String preferredLocale = android.preference.PreferenceManager.getDefaultSharedPreferences(this) + .getString(Settings.KEY_PREF_SELECTED_LANGUAGE, ""); + if (! preferredLocale.isEmpty()) { + Utils.setLocale(this, preferredLocale); + } + } + // @Override // public boolean onCreateOptionsMenu(Menu menu) { // getMenuInflater().inflate(R.menu.global, menu); diff --git a/app/src/main/java/org/xbmc/kore/ui/sections/settings/SettingsFragment.java b/app/src/main/java/org/xbmc/kore/ui/sections/settings/SettingsFragment.java index 1da75ed..6942b09 100644 --- a/app/src/main/java/org/xbmc/kore/ui/sections/settings/SettingsFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/sections/settings/SettingsFragment.java @@ -15,8 +15,8 @@ */ package org.xbmc.kore.ui.sections.settings; -import android.annotation.TargetApi; import android.Manifest; +import android.annotation.TargetApi; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; @@ -33,6 +33,7 @@ import android.support.v7.preference.PreferenceFragmentCompat; import android.support.v7.preference.TwoStatePreference; import android.widget.Toast; +import org.xbmc.kore.BuildConfig; import org.xbmc.kore.R; import org.xbmc.kore.Settings; import org.xbmc.kore.host.HostManager; @@ -43,8 +44,12 @@ import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.Utils; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Locale; import static org.xbmc.kore.service.NotificationObserver.NOTIFICATION_ID; +import static org.xbmc.kore.utils.Utils.getLocale; /** * Simple fragment to display preferences screen @@ -60,7 +65,7 @@ public class SettingsFragment extends PreferenceFragmentCompat public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.preferences); + setPreferencesFromResource(R.xml.preferences, null); // Get the preference for side menu items and change its Id to include // the current host @@ -105,6 +110,17 @@ public class SettingsFragment extends PreferenceFragmentCompat } setupPreferences(); + + ListPreference languagePref = (ListPreference) findPreference(Settings.KEY_PREF_LANGUAGE); + Locale currentLocale = getCurrentLocale(); + languagePref.setSummary(currentLocale.getDisplayLanguage(currentLocale)); + languagePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + setupLanguagePreference((ListPreference) preference); + return true; + } + }); } @Override @@ -130,15 +146,15 @@ public class SettingsFragment extends PreferenceFragmentCompat setupPreferences(); if (key.equals(Settings.KEY_PREF_THEME) || key.equals(Settings.getNavDrawerItemsPrefKey(hostId)) - || key.equals((Settings.getRemoteBarItemsPrefKey(hostId)))) { + || key.equals((Settings.getRemoteBarItemsPrefKey(hostId)))) { // Explicitly clear cache of resource ids that is maintained in the activity UIUtils.playPauseIconsLoaded = false; // restart to apply new theme (actually build an entirely new task stack) TaskStackBuilder.create(getActivity()) - .addNextIntent(new Intent(getActivity(), RemoteActivity.class)) - .addNextIntent(new Intent(getActivity(), SettingsActivity.class)) - .startActivities(); + .addNextIntent(new Intent(getActivity(), RemoteActivity.class)) + .addNextIntent(new Intent(getActivity(), SettingsActivity.class)) + .startActivities(); } // If the pause during call is selected, make sure we have permission to read phone state @@ -203,7 +219,7 @@ public class SettingsFragment extends PreferenceFragmentCompat String nameAndVersion = getActivity().getString(R.string.app_name); try { nameAndVersion += " " + - getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName; + getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName; } catch (PackageManager.NameNotFoundException exc) { } Preference aboutPreference = findPreference(Settings.KEY_PREF_ABOUT); @@ -217,4 +233,77 @@ public class SettingsFragment extends PreferenceFragmentCompat } }); } + + private void setupLanguagePreference(final ListPreference languagePref) { + Locale[] locales = getLocales(); + + final Locale currentLocale = getCurrentLocale(); + Arrays.sort(locales, new Comparator() { + @Override + public int compare(Locale o1, Locale o2) { + return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); + } + }); + + String[] displayNames = new String[locales.length]; + String[] entryValues = new String[locales.length]; + for(int index = 0; index < locales.length; index++) { + Locale locale = locales[index]; + displayNames[index] = locale.getDisplayName(locale); + entryValues[index] = getLanguageCountryCode(locale); + } + + languagePref.setValue(getLanguageCountryCode(currentLocale)); + languagePref.setEntries(displayNames); + languagePref.setEntryValues(entryValues); + languagePref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + languagePref.setValue(o.toString()); + updatePreferredLanguage(o.toString()); + return true; + } + }); + } + + private String getLanguageCountryCode(Locale locale) { + String result = locale.getLanguage(); + if (!locale.getCountry().isEmpty()) { + result += "-" + locale.getCountry(); + } + return result; + } + + /** + * Converts the locale names into a list of Locale objects + */ + private Locale[] getLocales() { + Locale[] locales = new Locale[BuildConfig.SUPPORTED_LOCALES.length]; + for (int index = 0; index < BuildConfig.SUPPORTED_LOCALES.length; index++) { + locales[index] = getLocale(BuildConfig.SUPPORTED_LOCALES[index]); + } + return locales; + } + + private void updatePreferredLanguage(String localeName) { + getPreferenceManager().getSharedPreferences().edit().putString(Settings.KEY_PREF_SELECTED_LANGUAGE, localeName).apply(); + + // Restart app to apply locale change + Intent i = getContext().getPackageManager().getLaunchIntentForPackage( getContext().getPackageName() ); + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(i); + } + + private Locale getCurrentLocale() { + String currentLocaleName = getPreferenceManager().getSharedPreferences().getString(Settings.KEY_PREF_SELECTED_LANGUAGE, ""); + + Locale currentLocale; + if (currentLocaleName == null || currentLocaleName.isEmpty()) { + currentLocale = getResources().getConfiguration().locale; + } else { + currentLocale = getLocale(currentLocaleName); + } + + return currentLocale; + } } diff --git a/app/src/main/java/org/xbmc/kore/utils/Utils.java b/app/src/main/java/org/xbmc/kore/utils/Utils.java index ed42b8d..ab9353e 100644 --- a/app/src/main/java/org/xbmc/kore/utils/Utils.java +++ b/app/src/main/java/org/xbmc/kore/utils/Utils.java @@ -17,6 +17,8 @@ package org.xbmc.kore.utils; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; @@ -37,6 +39,7 @@ import org.xbmc.kore.jsonrpc.type.PlaylistType; import java.util.ArrayList; import java.util.List; +import java.util.Locale; /** * Because every project needs one of these @@ -250,4 +253,28 @@ public class Utils { } }, callbackHandler); } + + public static void setLocale(Context context, String localeName) { + Locale locale = getLocale(localeName); + + Locale.setDefault(locale); + + Resources resources = context.getResources(); + + Configuration configuration = resources.getConfiguration(); + configuration.locale = locale; + + resources.updateConfiguration(configuration, resources.getDisplayMetrics()); + } + + public static Locale getLocale(String localeName) { + Locale locale; + String[] languageAndRegion = localeName.split("-", 2); + if (languageAndRegion.length > 1) { + locale = new Locale(languageAndRegion[0], languageAndRegion[1]); + } else { + locale = new Locale(localeName); + } + return locale; + } } diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 5f16305..190cb0b 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -362,4 +362,5 @@ Toont een uitvouwbare balk onderaan het scherm wanneer media wordt afgespeeld De weergavesnelheid wijzigen met de afspeelmelding In grote stappen vooruit of terug springen met de afspeelmelding + Taal diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7b23d74..c52fb75 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -431,4 +431,5 @@ Disable local playback support Disables support for playing media locally on the device running Kore. + Language diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 13e688b..cfb57fb 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -54,6 +54,10 @@ android:entryValues="@array/themes_values_array" android:defaultValue="0"/> + +