get language names from system, instead of hard coded list

closes #858
This commit is contained in:
Hans-Christoph Steiner 2017-04-01 20:54:17 +02:00
parent 7f261b339a
commit 019964387a
7 changed files with 289 additions and 194 deletions

View File

@ -13,7 +13,6 @@ before_script:
test: test:
script: script:
- cd app - cd app
- ./tools/langs-list-check.py
- ./tools/check-string-format.py - ./tools/check-string-format.py
- cd .. - cd ..
- ./gradlew assemble -PdisablePreDex - ./gradlew assemble -PdisablePreDex

View File

@ -227,6 +227,7 @@ public class FDroidApp extends Application {
Preferences.setup(this); Preferences.setup(this);
curTheme = Preferences.get().getTheme(); curTheme = Preferences.get().getTheme();
Preferences.get().configureProxy(); Preferences.get().configureProxy();
Languages.setup(getClass(), R.string.pref_language_default);
InstalledAppProviderService.compareToPackageManager(this); InstalledAppProviderService.compareToPackageManager(this);
AppUpdateStatusService.scanDownloadedApks(this); AppUpdateStatusService.scanDownloadedApks(this);

View File

@ -0,0 +1,277 @@
package org.fdroid.fdroid;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public final class Languages {
public static final String TAG = "Languages";
public static final String USE_SYSTEM_DEFAULT = "";
private static final Locale DEFAULT_LOCALE;
private static final Locale TIBETAN = new Locale("bo");
private static final String DEFAULT_STRING = "System Default";
private static Locale locale;
private static Languages singleton;
private static Class<?> clazz;
private static int resId;
private static Map<String, String> tmpMap = new TreeMap<>();
private static Map<String, String> nameMap;
static {
DEFAULT_LOCALE = Locale.getDefault();
}
private Languages(Activity activity) {
AssetManager assets = activity.getAssets();
Configuration config = activity.getResources().getConfiguration();
// Resources() requires DisplayMetrics, but they are only needed for drawables
DisplayMetrics ignored = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(ignored);
Resources resources;
Set<Locale> localeSet = new LinkedHashSet<>();
for (Locale locale : LOCALES_TO_TEST) {
config.locale = locale;
resources = new Resources(assets, ignored, config);
if (!TextUtils.equals(DEFAULT_STRING, resources.getString(resId))
|| locale.equals(Locale.ENGLISH)) {
localeSet.add(locale);
}
}
for (Locale locale : localeSet) {
if (locale.equals(TIBETAN)) {
// include English name for devices without Tibetan font support
tmpMap.put(TIBETAN.getLanguage(), "Tibetan བོད་སྐད།"); // Tibetan
} else if (locale.equals(Locale.SIMPLIFIED_CHINESE)) {
tmpMap.put(Locale.SIMPLIFIED_CHINESE.toString(), "中文 (中国)"); // Chinese (China)
} else if (locale.equals(Locale.TRADITIONAL_CHINESE)) {
tmpMap.put(Locale.TRADITIONAL_CHINESE.toString(), "中文 (台灣)"); // Chinese (Taiwan)
} else {
tmpMap.put(locale.getLanguage(), locale.getDisplayLanguage(locale));
}
}
/* SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */
localeSet.add(null);
tmpMap.put(USE_SYSTEM_DEFAULT, activity.getString(resId));
nameMap = Collections.unmodifiableMap(tmpMap);
}
/**
* Get the instance of {@link Languages} to work with, providing the
* {@link Activity} that is will be working as part of, as well as the
* {@code resId} that has the exact string "Use System Default",
* i.e. {@code R.string.use_system_default}.
* <p/>
* That string resource {@code resId} is also used to find the supported
* translations: if an included translation has a translated string that
* matches that {@code resId}, then that language will be included as a
* supported language.
*
* @param clazz the {@link Class} of the default {@code Activity},
* usually the main {@code Activity} from where the
* Settings is launched from.
* @param resId the string resource ID to for the string "System Default",
* e.g. {@code R.string.pref_language_default}
*/
public static void setup(Class<?> clazz, int resId) {
if (Languages.clazz == null) {
Languages.clazz = clazz;
Languages.resId = resId;
} else {
throw new RuntimeException("Languages singleton was already initialized, duplicate call to Languages.setup()!");
}
}
/**
* @param activity the {@link Activity} this is working as part of
* @return the singleton to work with
*/
public static Languages get(Activity activity) {
if (singleton == null) {
singleton = new Languages(activity);
}
return singleton;
}
@TargetApi(17)
public static void setLanguage(final ContextWrapper contextWrapper, String language, boolean refresh) {
if (locale != null && TextUtils.equals(locale.getLanguage(), language) && (!refresh)) {
return; // already configured
} else if (language == null || language.equals(USE_SYSTEM_DEFAULT)) {
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);
}
}
final Resources resources = contextWrapper.getBaseContext().getResources();
Configuration config = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= 17) {
config.setLocale(locale);
} else {
config.locale = locale;
}
resources.updateConfiguration(config, resources.getDisplayMetrics());
Locale.setDefault(locale);
}
/**
* Force reload the {@link Activity to make language changes take effect.}
*
* @param activity the {@code Activity} to force reload
*/
public static void forceChangeLanguage(Activity activity) {
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 the name of the language based on the locale.
*/
public String getName(String locale) {
String ret = nameMap.get(locale);
// if no match, try to return a more general name (i.e. English for en_IN)
if (ret == null && locale.contains("_")) {
ret = nameMap.get(locale.split("_")[0]);
}
return ret;
}
/**
* @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 nameMap.values().toArray(new String[nameMap.size()]);
}
public int getPosition(Locale locale) {
String localeName = locale.getLanguage();
int i = 0;
for (String key : nameMap.keySet()) {
if (TextUtils.equals(key, localeName)) {
return i;
} else {
i++;
}
}
return -1;
}
/**
* @return sorted list of supported locales.
*/
public String[] getSupportedLocales() {
Set<String> keys = nameMap.keySet();
return keys.toArray(new String[keys.size()]);
}
private static final Locale[] LOCALES_TO_TEST = {
Locale.ENGLISH,
Locale.FRENCH,
Locale.GERMAN,
Locale.ITALIAN,
Locale.JAPANESE,
Locale.KOREAN,
Locale.SIMPLIFIED_CHINESE,
Locale.TRADITIONAL_CHINESE,
TIBETAN,
new Locale("af"),
new Locale("am"),
new Locale("ar"),
new Locale("az"),
new Locale("be"),
new Locale("bg"),
new Locale("bn"),
new Locale("ca"),
new Locale("cs"),
new Locale("da"),
new Locale("el"),
new Locale("es"),
new Locale("et"),
new Locale("eu"),
new Locale("fa"),
new Locale("fi"),
new Locale("gl"),
new Locale("hi"),
new Locale("hr"),
new Locale("hu"),
new Locale("hy"),
new Locale("in"),
new Locale("hy"),
new Locale("in"),
new Locale("is"),
new Locale("it"),
new Locale("iw"),
new Locale("ka"),
new Locale("kk"),
new Locale("km"),
new Locale("kn"),
new Locale("ky"),
new Locale("lo"),
new Locale("lt"),
new Locale("lv"),
new Locale("mk"),
new Locale("ml"),
new Locale("mn"),
new Locale("mr"),
new Locale("ms"),
new Locale("my"),
new Locale("nb"),
new Locale("ne"),
new Locale("nl"),
new Locale("pl"),
new Locale("pt"),
new Locale("rm"),
new Locale("ro"),
new Locale("ru"),
new Locale("si"),
new Locale("sk"),
new Locale("sl"),
new Locale("sn"),
new Locale("sr"),
new Locale("sv"),
new Locale("sw"),
new Locale("ta"),
new Locale("te"),
new Locale("th"),
new Locale("tl"),
new Locale("tr"),
new Locale("uk"),
new Locale("ur"),
new Locale("uz"),
new Locale("vi"),
new Locale("zu"),
};
}

View File

@ -12,19 +12,19 @@ import android.preference.Preference;
import android.preference.PreferenceCategory; import android.preference.PreferenceCategory;
import android.support.v4.preference.PreferenceFragment; import android.support.v4.preference.PreferenceFragment;
import android.text.TextUtils; import android.text.TextUtils;
import com.geecko.QuickLyric.view.AppCompatListPreference;
import info.guardianproject.netcipher.NetCipher;
import info.guardianproject.netcipher.proxy.OrbotHelper;
import org.fdroid.fdroid.AppDetails2; import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.CleanCacheService; import org.fdroid.fdroid.CleanCacheService;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Languages;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.installer.InstallHistoryService; import org.fdroid.fdroid.installer.InstallHistoryService;
import org.fdroid.fdroid.installer.PrivilegedInstaller; import org.fdroid.fdroid.installer.PrivilegedInstaller;
import info.guardianproject.netcipher.NetCipher;
import info.guardianproject.netcipher.proxy.OrbotHelper;
public class PreferencesFragment extends PreferenceFragment public class PreferencesFragment extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener { implements SharedPreferences.OnSharedPreferenceChangeListener {
@ -62,6 +62,12 @@ public class PreferencesFragment extends PreferenceFragment
enableProxyCheckPref = (CheckBoxPreference) findPreference(Preferences.PREF_ENABLE_PROXY); enableProxyCheckPref = (CheckBoxPreference) findPreference(Preferences.PREF_ENABLE_PROXY);
updateAutoDownloadPref = findPreference(Preferences.PREF_AUTO_DOWNLOAD_INSTALL_UPDATES); updateAutoDownloadPref = findPreference(Preferences.PREF_AUTO_DOWNLOAD_INSTALL_UPDATES);
updatePrivilegedExtensionPref = findPreference(Preferences.PREF_UNINSTALL_PRIVILEGED_APP); updatePrivilegedExtensionPref = findPreference(Preferences.PREF_UNINSTALL_PRIVILEGED_APP);
AppCompatListPreference languagePref = (AppCompatListPreference) findPreference(Preferences.PREF_LANGUAGE);
Languages languages = Languages.get(getActivity());
languagePref.setDefaultValue(Languages.USE_SYSTEM_DEFAULT);
languagePref.setEntries(languages.getAllNames());
languagePref.setEntryValues(languages.getSupportedLocales());
} }
private void checkSummary(String key, int resId) { private void checkSummary(String key, int resId) {

View File

@ -44,126 +44,4 @@
<item>night</item> <item>night</item>
</string-array> </string-array>
<string-array name="languageValues">
<item></item>
<item>en</item>
<item>af</item>
<item>ar</item>
<item>ast</item>
<item>be</item>
<item>bg</item>
<item>ca</item>
<item>cs</item>
<item>da</item>
<item>de</item>
<item>el</item>
<item>eo</item>
<item>es</item>
<item>et</item>
<item>eu</item>
<item>fa</item>
<item>fi</item>
<item>fr</item>
<item>gl</item>
<item>he</item>
<item>hi</item>
<item>hr</item>
<item>hu</item>
<item>hy</item>
<item>id</item>
<item>is</item>
<item>it</item>
<item>ja</item>
<item>ko</item>
<item>lt</item>
<item>lv</item>
<item>mk</item>
<item>my</item>
<item>nb</item>
<item>nl</item>
<item>pl</item>
<item>pt-rBR</item>
<item>pt-rPT</item>
<item>ro</item>
<item>ru</item>
<item>sc</item>
<item>sk</item>
<item>sl</item>
<item>sn</item>
<item>sq</item>
<item>sr</item>
<item>sv</item>
<item>ta</item>
<item>th</item>
<item>tr</item>
<item>ug</item>
<item>uk</item>
<item>ur</item>
<item>vi</item>
<item>zh-rCN</item>
<item>zh-rHK</item>
<item>zh-rTW</item>
</string-array>
<string-array name="languageNames">
<item>@string/pref_language_default</item>
<item>English</item>
<item>Afrikaans</item>
<item>ﺎﻠﻋﺮﺒﻳﺓ</item>
<item>Asturian</item>
<item>белорусский</item>
<item>Български</item>
<item>Català</item>
<item>Čeština</item>
<item>Dansk</item>
<item>Deutsch</item>
<item>Ελληνικά</item>
<item>Esperanto</item>
<item>Español</item>
<item>Eesti</item>
<item>Euskara</item>
<item>ﻑﺍﺮﺳی</item>
<item>Suomi</item>
<item>Français</item>
<item>Galego</item>
<item>עברית</item>
<item>हिन्दी</item>
<item>Hrvatski</item>
<item>Magyar</item>
<item>հայերեն</item>
<item>Bahasa Indonesia</item>
<item>Íslenska</item>
<item>Italiano</item>
<item>日本語</item>
<item>한국어</item>
<item>Lietuvių</item>
<item>Latviešu</item>
<item>македонски</item>
<item>မြန်မာစာ</item>
<item>Norsk bokmål</item>
<item>Nederlands</item>
<item>Polski</item>
<item>Português (Brasil)</item>
<item>Português (Portugal)</item>
<item>Română</item>
<item>Русский</item>
<item>Sardinian</item>
<item>Slovenčina</item>
<item>Slovenščina</item>
<item>ChiSona</item>
<item>Shqip</item>
<item>Српски</item>
<item>Svenska</item>
<item>தமிழ்</item>
<item>ไทย</item>
<item>Türkçe</item>
<item>ﺉۇﻲﻏۇﺭچە</item>
<item>Українська</item>
<item>اردو</item>
<item>Tiếng Việt</item>
<item>中文 (中国)</item>
<item>中文 (香港)</item>
<item>中文 (台湾)</item>
</string-array>
</resources> </resources>

View File

@ -43,10 +43,7 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/display"> <PreferenceCategory android:title="@string/display">
<com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/pref_language" <com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/pref_language"
android:key="language" android:key="language"/>
android:defaultValue=""
android:entries="@array/languageNames"
android:entryValues="@array/languageValues" />
<com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/theme" <com.geecko.QuickLyric.view.AppCompatListPreference android:title="@string/theme"
android:key="theme" android:key="theme"
android:defaultValue="light" android:defaultValue="light"

View File

@ -1,63 +0,0 @@
#!/usr/bin/env python3
# List supported languages missing from the preference array
import glob
import os
import sys
import re
from xml.etree import ElementTree
prefs = set([''])
trans = set(['', 'en'])
donottranslate = os.path.join('src', 'main', 'res', 'values', 'donottranslate.xml')
for e in ElementTree.parse(donottranslate).getroot().findall('.//string-array'):
if e.attrib['name'] != 'languageValues':
continue
for i in e.findall('.//item'):
lang = i.text
if not lang:
continue
prefs.add(lang)
for d in glob.glob(os.path.join('src', 'main', 'res', 'values-*')):
lang = d[len(os.path.join('src', 'main', 'res', 'values-')):]
if not lang:
continue
if re.match('^sw[0-9]+dp|v[0-9]+$', lang):
continue
if lang == 'ldrtl':
continue
if os.path.islink(d):
continue
trans.add(lang)
print("In the settings array: %s" % ' '.join(sorted(prefs)))
print("Actually translated: %s" % ' '.join(sorted(trans)))
missing = []
for lang in trans:
if lang not in prefs:
missing.append(lang)
if missing:
print("Missing:")
for lang in missing:
print(" %s" % lang)
extra = []
for lang in prefs:
if lang not in trans:
extra.append(lang)
if extra:
print("Extra:")
for lang in extra:
print(" %s" % lang)
if not missing and not extra:
print("All good.")
else:
sys.exit(1)