Add preference to change app language (fixes #742)

This commit is contained in:
Felix Ableitner 2017-07-19 12:24:45 +09:00
parent 6718811c29
commit e8073599ae
6 changed files with 231 additions and 1 deletions

View File

@ -24,7 +24,8 @@
android:theme="@style/Theme.Syncthing" android:theme="@style/Theme.Syncthing"
android:description="@string/app_description" android:description="@string/app_description"
android:supportsRtl="true" android:supportsRtl="true"
android:installLocation="internalOnly"> android:installLocation="internalOnly"
android:name=".SyncthingApp">
<activity <activity
android:name=".activities.FirstStartActivity" android:name=".activities.FirstStartActivity"
android:label="@string/app_name"> android:label="@string/app_name">

View File

@ -0,0 +1,14 @@
package com.nutomic.syncthingandroid;
import android.app.Application;
import com.nutomic.syncthingandroid.util.Languages;
public class SyncthingApp extends Application {
@Override
public void onCreate() {
super.onCreate();
new Languages(this).setLanguage(this);
}
}

View File

@ -7,6 +7,7 @@ import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
@ -22,6 +23,7 @@ import com.nutomic.syncthingandroid.model.Device;
import com.nutomic.syncthingandroid.model.Options; import com.nutomic.syncthingandroid.model.Options;
import com.nutomic.syncthingandroid.service.RestApi; import com.nutomic.syncthingandroid.service.RestApi;
import com.nutomic.syncthingandroid.service.SyncthingService; import com.nutomic.syncthingandroid.service.SyncthingService;
import com.nutomic.syncthingandroid.util.Languages;
import com.nutomic.syncthingandroid.views.WifiSsidPreference; import com.nutomic.syncthingandroid.views.WifiSsidPreference;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
@ -105,6 +107,16 @@ public class SettingsActivity extends SyncthingActivity {
mSyncOnlyWifi.setEnabled(mAlwaysRunInBackground.isChecked()); mSyncOnlyWifi.setEnabled(mAlwaysRunInBackground.isChecked());
mSyncOnlyOnSSIDs.setEnabled(mSyncOnlyWifi.isChecked()); mSyncOnlyOnSSIDs.setEnabled(mSyncOnlyWifi.isChecked());
ListPreference languagePref = (ListPreference) findPreference(Languages.PREFERENCE_LANGUAGE);
Languages languages = new Languages(getActivity());
languagePref.setDefaultValue(Languages.USE_SYSTEM_DEFAULT);
languagePref.setEntries(languages.getAllNames());
languagePref.setEntryValues(languages.getSupportedLocales());
languagePref.setOnPreferenceChangeListener((p, o) -> {
languages.forceChangeLanguage(getActivity(), (String) o);
return false;
});
mDeviceName = (EditTextPreference) findPreference("deviceName"); mDeviceName = (EditTextPreference) findPreference("deviceName");
mListenAddresses = (EditTextPreference) findPreference("listenAddresses"); mListenAddresses = (EditTextPreference) findPreference("listenAddresses");
mMaxRecvKbps = (EditTextPreference) findPreference("maxRecvKbps"); mMaxRecvKbps = (EditTextPreference) findPreference("maxRecvKbps");

View File

@ -0,0 +1,192 @@
package com.nutomic.syncthingandroid.util;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import com.nutomic.syncthingandroid.R;
import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Based on https://gitlab.com/fdroid/fdroidclient/blob/master/app/src/main/java/org/fdroid/fdroid/Languages.java
*/
public final class Languages {
public static final String TAG = "Languages";
public static final String USE_SYSTEM_DEFAULT = "";
private static final Locale DEFAULT_LOCALE;
public static final String PREFERENCE_LANGUAGE = "pref_current_language";
private final SharedPreferences mPreferences;
private static Map<String, String> mAvailableLanguages;
static {
DEFAULT_LOCALE = Locale.getDefault();
}
public Languages(Context context) {
Map<String, String> tmpMap = new TreeMap<>();
for (Locale locale : Arrays.asList(LOCALES_TO_TEST)) {
tmpMap.put(locale.getLanguage(), locale.getDisplayLanguage(locale));
}
// remove the current system language from the menu
tmpMap.remove(Locale.getDefault().getLanguage());
/* SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */
tmpMap.put(USE_SYSTEM_DEFAULT, context.getString(R.string.pref_language_default));
mAvailableLanguages = Collections.unmodifiableMap(tmpMap);
mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
/**
* Handles setting the language if it is different than the current language,
* or different than the current system-wide locale. The preference is cleared
* if the language matches the system-wide locale or "System Default" is chosen.
*/
@TargetApi(17)
public void setLanguage(Context context) {
if (Build.VERSION.SDK_INT >= 24) {
Log.d(TAG, "Languages.setLanguage() ignored on >= android-24");
mPreferences.edit().remove(PREFERENCE_LANGUAGE).apply();
return;
}
String language = mPreferences.getString(PREFERENCE_LANGUAGE, null);
Locale locale;
if (TextUtils.equals(language, DEFAULT_LOCALE.getLanguage())) {
mPreferences.edit().remove(PREFERENCE_LANGUAGE).apply();
locale = DEFAULT_LOCALE;
} else if (language == null || language.equals(USE_SYSTEM_DEFAULT)) {
mPreferences.edit().remove(PREFERENCE_LANGUAGE).apply();
locale = DEFAULT_LOCALE;
} else {
/* handle locales with the country in it, i.e. zh_CN, zh_TW, etc */
String[] localeSplit = language.split("_");
if (localeSplit.length > 1) {
locale = new Locale(localeSplit[0], localeSplit[1]);
} else {
locale = new Locale(language);
}
}
Locale.setDefault(locale);
final Resources resources = context.getResources();
Configuration config = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= 17) {
config.setLocale(locale);
} else {
config.locale = locale;
}
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
/**
* Force reload the {@link Activity to make language changes take effect.}
*
* @param activity the {@code Activity} to force reload
*/
@SuppressLint("ApplySharedPref")
public void forceChangeLanguage(Activity activity, String newLanguage) {
mPreferences.edit().putString(PREFERENCE_LANGUAGE, newLanguage).commit();
setLanguage(activity);
if (Build.VERSION.SDK_INT >= 24) {
Log.d(TAG, "Languages.forceChangeLanguage() ignored on >= android-24");
return;
}
Intent intent = activity.getIntent();
if (intent == null) { // when launched as LAUNCHER
return;
}
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
activity.finish();
activity.overridePendingTransition(0, 0);
activity.startActivity(intent);
activity.overridePendingTransition(0, 0);
}
/**
* @return an array of the names of all the supported languages, sorted to
* match what is returned by {@link Languages#getSupportedLocales()}.
*/
public String[] getAllNames() {
return mAvailableLanguages.values().toArray(new String[mAvailableLanguages.size()]);
}
/**
* @return sorted list of supported locales.
*/
public String[] getSupportedLocales() {
Set<String> keys = mAvailableLanguages.keySet();
return keys.toArray(new String[keys.size()]);
}
private String capitalize(final String line) {
return Character.toUpperCase(line.charAt(0)) + line.substring(1);
}
public static final Locale[] LOCALES_TO_TEST = {
Locale.ENGLISH,
Locale.FRENCH,
Locale.GERMAN,
Locale.ITALIAN,
Locale.JAPANESE,
Locale.KOREAN,
Locale.SIMPLIFIED_CHINESE,
Locale.TRADITIONAL_CHINESE,
new Locale("af"),
new Locale("ar"),
new Locale("be"),
new Locale("bg"),
new Locale("ca"),
new Locale("cs"),
new Locale("da"),
new Locale("el"),
new Locale("es"),
new Locale("eo"),
new Locale("et"),
new Locale("eu"),
new Locale("fa"),
new Locale("fi"),
new Locale("he"),
new Locale("hi"),
new Locale("hu"),
new Locale("hy"),
new Locale("id"),
new Locale("is"),
new Locale("it"),
new Locale("ml"),
new Locale("my"),
new Locale("nb"),
new Locale("nl"),
new Locale("pl"),
new Locale("pt"),
new Locale("ro"),
new Locale("ru"),
new Locale("sc"),
new Locale("sk"),
new Locale("sn"),
new Locale("sr"),
new Locale("sv"),
new Locale("th"),
new Locale("tr"),
new Locale("uk"),
new Locale("vi"),
};
}

View File

@ -271,6 +271,12 @@ Please report any problems you encounter via Github.</string>
<item>None</item> <item>None</item>
</string-array> </string-array>
<string name="preference_language_title">Language</string>
<string name="preference_language_summary">Change the app language</string>
<string name="pref_language_default">Default Language</string>
<string-array name="versioning_types"> <string-array name="versioning_types">
<item>None</item> <item>None</item>
<item>TrashCan</item> <item>TrashCan</item>

View File

@ -49,6 +49,11 @@
android:summary="@string/notification_type_summary" android:summary="@string/notification_type_summary"
android:defaultValue="low_priority" /> android:defaultValue="low_priority" />
<ListPreference
android:key="pref_current_language"
android:title="@string/preference_language_title"
android:summary="@string/preference_language_summary" />
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen <PreferenceScreen