Allow "System language" to be set as language option
Populate "System language" as a first class item in the language preference list so that users can select it in scenarios where they have previously selected a specific language, and wish to go back to the default.
This commit is contained in:
@@ -78,8 +78,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
if (!languageLoaded)
|
if (!languageLoaded)
|
||||||
{
|
{
|
||||||
var language = PreferenceManager.GetDefaultSharedPreferences(c).GetString(c.GetString(Resource.String.app_language_pref_key), null);
|
var langPref = PreferenceManager.GetDefaultSharedPreferences(c).GetString(c.GetString(Resource.String.app_language_pref_key), null);
|
||||||
Language = language;
|
Language = LanguageEntry.PrefCodeToLanguage(langPref);
|
||||||
}
|
}
|
||||||
return Language;
|
return Language;
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,68 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A small container/wrapper that helps with the building and sorting of the
|
||||||
|
/// Language Preference list, and interoperability between it and LocaleManager
|
||||||
|
/// </summary>
|
||||||
|
class LanguageEntry
|
||||||
|
{
|
||||||
|
// "System language" preference code; maps to LocaleManager.Language = null
|
||||||
|
private const string SYS_LANG_CODE = "SysLang";
|
||||||
|
|
||||||
public class Util {
|
// Preference code (2-char lowercase, or SYS_LANG_CODE)
|
||||||
|
public readonly string Code;
|
||||||
|
// Localized display name
|
||||||
|
public readonly string Name;
|
||||||
|
// True if this LanguageEntry is the "System language", false otherwise
|
||||||
|
public readonly bool IsSystem;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a LanguageEntry from a Locale
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static LanguageEntry OfLocale(Java.Util.Locale from)
|
||||||
|
{
|
||||||
|
return new LanguageEntry(from.Language, from.DisplayLanguage, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the "System language" LanguageEntry with the given localized display name,
|
||||||
|
/// special preference code, marked as a System entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static LanguageEntry SystemDefault(string displayName)
|
||||||
|
{
|
||||||
|
return new LanguageEntry(SYS_LANG_CODE, displayName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LanguageEntry(string code, string name, bool isSystem)
|
||||||
|
{
|
||||||
|
this.Code = code;
|
||||||
|
this.Name = name;
|
||||||
|
this.IsSystem = isSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a language preference code to a code that is compatible with LocaleManager.Language
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns>A converted code, possibly null</returns>
|
||||||
|
public static string PrefCodeToLanguage(string code)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(code) || SYS_LANG_CODE.Equals(code) ? null : code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "{" + this.Code + ":" + this.Name + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class Util {
|
||||||
|
|
||||||
|
|
||||||
public const String KeyFilename = "fileName";
|
public const String KeyFilename = "fileName";
|
||||||
|
|||||||
@@ -41,10 +41,12 @@ using KeePassLib.Cryptography.KeyDerivation;
|
|||||||
using KeePassLib.Interfaces;
|
using KeePassLib.Interfaces;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
//http://stackoverflow.com/a/27422401/292233
|
//http://stackoverflow.com/a/27422401/292233
|
||||||
public class SettingsFragment : PreferenceFragment
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
public class SettingsFragment : PreferenceFragment
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@@ -177,36 +179,8 @@ namespace keepass2android
|
|||||||
FindPreference(GetString(Resource.String.DebugLog_send_key)).PreferenceClick += OnSendDebug;
|
FindPreference(GetString(Resource.String.DebugLog_send_key)).PreferenceClick += OnSendDebug;
|
||||||
|
|
||||||
HashSet<string> supportedLocales = new HashSet<string>() { "en", "af", "ar", "az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "eu", "fa", "fi", "fr", "gl", "he", "hr", "hu", "id", "in", "it", "iw", "ja", "ko", "ml", "nb", "nl", "nn", "no", "pl", "pt", "ro", "ru", "si", "sk", "sl", "sr", "sv", "tr", "uk", "vi", "zh" };
|
HashSet<string> supportedLocales = new HashSet<string>() { "en", "af", "ar", "az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "eu", "fa", "fi", "fr", "gl", "he", "hr", "hu", "id", "in", "it", "iw", "ja", "ko", "ml", "nb", "nl", "nn", "no", "pl", "pt", "ro", "ru", "si", "sk", "sl", "sr", "sv", "tr", "uk", "vi", "zh" };
|
||||||
|
var languagePref = (ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key));
|
||||||
ListPreference appLanguagePref = (ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key));
|
new AppLanguageManager(this, languagePref, supportedLocales);
|
||||||
|
|
||||||
var localesByCode = new System.Collections.Generic.Dictionary<string, List<Java.Util.Locale>>();
|
|
||||||
foreach (var loc in Java.Util.Locale.GetAvailableLocales())
|
|
||||||
{
|
|
||||||
if (!supportedLocales.Contains(loc.Language))
|
|
||||||
continue;
|
|
||||||
if (!localesByCode.ContainsKey(loc.Language))
|
|
||||||
{
|
|
||||||
localesByCode[loc.Language] = new List<Java.Util.Locale>();
|
|
||||||
}
|
|
||||||
localesByCode[loc.Language].Add(loc);
|
|
||||||
|
|
||||||
}
|
|
||||||
var localesByCodeUnique = localesByCode.Select(l => new KeyValuePair<string, Java.Util.Locale>(l.Key, l.Value.First())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
||||||
List<KeyValuePair<string, List<Java.Util.Locale>>> codesWithMultiple = localesByCode.Where(l => l.Value.Count > 1).ToList();
|
|
||||||
List<KeyValuePair<string, Java.Util.Locale>> localesByLanguageList = localesByCodeUnique
|
|
||||||
.OrderBy(kvp => kvp.Value.DisplayLanguage).ToList();
|
|
||||||
appLanguagePref.SetEntries(localesByLanguageList.Select(kvp => kvp.Value.DisplayLanguage).ToArray());
|
|
||||||
appLanguagePref.SetEntryValues(localesByLanguageList.Select(kvp => kvp.Value.Language).ToArray());
|
|
||||||
string languageCode = appLanguagePref.Value;
|
|
||||||
string summary = GetDisplayLanguage(localesByCodeUnique, languageCode);
|
|
||||||
((ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key))).Summary = summary;
|
|
||||||
appLanguagePref.PreferenceChange += (sender, args) =>
|
|
||||||
{
|
|
||||||
((ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key))).Summary = GetDisplayLanguage(localesByCodeUnique, (string)args.NewValue);
|
|
||||||
LocaleManager.Language = (string)args.NewValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
UpdateAutofillPref();
|
UpdateAutofillPref();
|
||||||
|
|
||||||
@@ -347,16 +321,6 @@ namespace keepass2android
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetDisplayLanguage(Dictionary<string, Java.Util.Locale> localesByCode, string languageCode)
|
|
||||||
{
|
|
||||||
return languageCode != null && localesByCode.ContainsKey(languageCode) ? localesByCode[languageCode]?.DisplayLanguage : GetString(Resource.String.SystemLanguage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AppLanguagePref_PreferenceChange(object sender, Preference.PreferenceChangeEventArgs e)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAutofillPref()
|
private void UpdateAutofillPref()
|
||||||
{
|
{
|
||||||
var autofillScreen = FindPreference(GetString(Resource.String.AutoFill_prefs_screen_key));
|
var autofillScreen = FindPreference(GetString(Resource.String.AutoFill_prefs_screen_key));
|
||||||
@@ -897,10 +861,102 @@ namespace keepass2android
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Activity to configure the application and database settings. The database must be unlocked, and this activity will close if it becomes locked.
|
/// <para>
|
||||||
/// </summary>
|
/// A helper class that manages language preference display and selection.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The idea is to provide a ListPreference with a "System language" item at the top, followed by
|
||||||
|
/// the localized list of supported language names. The items are backed by their corresponding "code".
|
||||||
|
/// For a langauge that's the 2-char lowercase language code, which is exactly the same code that
|
||||||
|
/// LocaleManager.Language expects.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// "System language" is a special case. LocaleManager.Language expects null, but ListPreference
|
||||||
|
/// does not support null as a valid code. To work around this, LanguageEntry.SYS_LANG_CODE
|
||||||
|
/// is used as the preference code. LanguageEntry.PrefCodeToLanguage(string) is used to convert the
|
||||||
|
/// preference codes to language codes as needed.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
internal class AppLanguageManager
|
||||||
|
{
|
||||||
|
private readonly PreferenceFragment _fragment;
|
||||||
|
private readonly ListPreference _langPref;
|
||||||
|
private readonly Dictionary<string, LanguageEntry> _langEntriesByCodeUnique;
|
||||||
|
|
||||||
|
public AppLanguageManager(PreferenceFragment fragment, ListPreference langPref, HashSet<string> supportedLocales)
|
||||||
|
{
|
||||||
|
this._fragment = fragment;
|
||||||
|
this._langPref = langPref;
|
||||||
|
this._langEntriesByCodeUnique = CreateCodeToEntryMapping(fragment, supportedLocales);
|
||||||
|
|
||||||
|
ConfigureLanguageList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, LanguageEntry> CreateCodeToEntryMapping(PreferenceFragment fragment, HashSet<string> supportedLocales)
|
||||||
|
{
|
||||||
|
var localesByCode = new Dictionary<string, List<Java.Util.Locale>>();
|
||||||
|
foreach (var loc in Java.Util.Locale.GetAvailableLocales())
|
||||||
|
{
|
||||||
|
if (!supportedLocales.Contains(loc.Language))
|
||||||
|
continue;
|
||||||
|
if (!localesByCode.ContainsKey(loc.Language))
|
||||||
|
{
|
||||||
|
localesByCode[loc.Language] = new List<Java.Util.Locale>();
|
||||||
|
}
|
||||||
|
localesByCode[loc.Language].Add(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
var langEntriesByCodeUnique = localesByCode
|
||||||
|
.Select(l => new KeyValuePair<string, LanguageEntry>(l.Key, LanguageEntry.OfLocale(l.Value.First())))
|
||||||
|
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||||
|
|
||||||
|
var sysLangEntry = LanguageEntry.SystemDefault(fragment.GetString(Resource.String.SystemLanguage));
|
||||||
|
langEntriesByCodeUnique.Add(sysLangEntry.Code, sysLangEntry);
|
||||||
|
|
||||||
|
return langEntriesByCodeUnique;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureLanguageList()
|
||||||
|
{
|
||||||
|
List<KeyValuePair<string, LanguageEntry>> langEntriesList = _langEntriesByCodeUnique
|
||||||
|
.OrderByDescending(kvp => kvp.Value.IsSystem)
|
||||||
|
.ThenBy(kvp => kvp.Value.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
_langPref.SetEntries(langEntriesList
|
||||||
|
.Select(kvp => kvp.Value.Name)
|
||||||
|
.ToArray());
|
||||||
|
_langPref.SetEntryValues(langEntriesList
|
||||||
|
.Select(kvp => kvp.Value.Code)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
_langPref.Summary = GetDisplayLanguage(LanguageEntry.PrefCodeToLanguage(_langPref.Value));
|
||||||
|
_langPref.PreferenceChange += AppLanguagePrefChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetDisplayLanguage(string languageCode)
|
||||||
|
{
|
||||||
|
if (languageCode != null && this._langEntriesByCodeUnique.ContainsKey(languageCode))
|
||||||
|
return this._langEntriesByCodeUnique[languageCode]?.Name;
|
||||||
|
else
|
||||||
|
return _fragment.GetString(Resource.String.SystemLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppLanguagePrefChange(object sender, Preference.PreferenceChangeEventArgs args)
|
||||||
|
{
|
||||||
|
string langCode = LanguageEntry.PrefCodeToLanguage((string)args.NewValue);
|
||||||
|
LocaleManager.Language = langCode;
|
||||||
|
_langPref.Summary = GetDisplayLanguage(langCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Activity to configure the application and database settings. The database must be unlocked, and this activity will close if it becomes locked.
|
||||||
|
/// </summary>
|
||||||
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
|
[Activity(Label = "@string/app_name", Theme = "@style/MyTheme", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
|
||||||
public class DatabaseSettingsActivity : LockCloseActivity
|
public class DatabaseSettingsActivity : LockCloseActivity
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user