Xamarin.Android : 以编程方式更改应用程序语言?
Xamarin.Android : change app language programmatically?
我在 values-en
和 values-fr
文件夹中有 2 个 strings.xml
文件。当我从 Android 设置更改语言时,应用已正确本地化。
但是,有没有办法以编程方式更改应用程序语言?以下代码(正如最近关于该主题的 Whosebug 帖子所建议的那样)对本地化没有任何影响:
var locale = new Java.Util.Locale("fr");
Java.Util.Locale.Default = locale;
var context = Application.Context;
context.Resources.Configuration.Locale = locale;
BaseContext.ApplicationContext.CreateConfigurationContext(context.Resources.Configuration);
BaseContext.Resources.DisplayMetrics.SetTo(context.Resources.DisplayMetrics);
确实,此代码后的字符串 GetString(Resource.String.stringName)
将保留为英文。
目标版本: Android 8.1 (API 27 - Oreo)
AppCompat Activity 使用 Android.Support.V7.App(仅在 Android.Support.Design.Widget 中使用 FAB)
感谢您的帮助!
createConfigurationContext(configuration)
是不够的,我们需要获取这个方法 returns 的上下文,然后在 attachBaseContext 方法中设置这个上下文。
protected override void AttachBaseContext(Context @base)
{
base.AttachBaseContext(updateBaseContextLocale(@base));
}
private Context updateBaseContextLocale(Context context)
{
var locale = new Java.Util.Locale("sp");
Java.Util.Locale.Default = locale;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
{
Configuration configuration = context.Resources.Configuration;
configuration.SetLocale(locale);
return context.CreateConfigurationContext(configuration);
}
else
{
Resources resources = context.Resources;
Configuration configuration = resources.Configuration;
#pragma warning disable CS0618 // Type or member is obsolete
configuration.Locale = locale;
resources.UpdateConfiguration(configuration, resources.DisplayMetrics);
#pragma warning restore CS0618 // Type or member is obsolete
return context;
}
}
在 OnCreate 方法中获取字符串
string title = GetString(Resource.String.TxtWelcome);
参考
override AttachBaseContext in your activity
受保护的覆盖 void AttachBaseContext(Context @base){base.AttachBaseContext(MyContextWrapper.Wrap(@base,PreferencesManager.Language));}
像这样创建 class MyContextWrapper :
public class MyContextWrapper : ContextWrapper
{
public MyContextWrapper(Context @base) : base(@base)
{
}
[SuppressWarnings(Value = new string[] { "deprecation" })]
public static ContextWrapper Wrap(Context context, string language)
{
Configuration config = context.Resources.Configuration;
Locale sysLocale = null;
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
sysLocale = getSystemLocale(config);
}
else
{
sysLocale = getSystemLocaleLegacy(config);
}
if (!language.Equals("") && !sysLocale.Language.Equals(language))
{
Locale locale = new Locale(language);
Category[] vals = null;
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
vals = Locale.Category.Values();
}
else
{
config.SetLayoutDirection(locale);
}
if (vals != null && vals.Length > 0)
{
Locale.SetDefault(vals[0], locale);
}
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
setSystemLocale(config, locale);
}
else
{
setSystemLocaleLegacy(config, locale);
}
}
if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1)
{
context = context.CreateConfigurationContext(config);
}
else
{
context.Resources.UpdateConfiguration(config, context.Resources.DisplayMetrics);
}
return new MyContextWrapper(context);
}
[SuppressWarnings(Value = new string[] { "deprecation" })]
public static Locale getSystemLocaleLegacy(Configuration config)
{
return config.Locale;
}
[TargetApi(Value = (int)BuildVersionCodes.N)]
public static Locale getSystemLocale(Configuration config)
{
return config.Locales.Get(0);
}
[SuppressWarnings(Value = new string[] { "deprecation" })]
public static void setSystemLocaleLegacy(Configuration config, Locale locale)
{
config.Locale = locale;
}
[TargetApi(Value = (int)BuildVersionCodes.N)]
public static void setSystemLocale(Configuration config, Locale locale)
{
config.SetLocale(locale);
}
}
Blockquote
在您的 Activity 中:
受保护的重写 void AttachBaseContext(Context @base)
{
base.AttachBaseContext(MyContextWrapper.Wrap(@base, PreferencesManager.Language));
}
我在 values-en
和 values-fr
文件夹中有 2 个 strings.xml
文件。当我从 Android 设置更改语言时,应用已正确本地化。
但是,有没有办法以编程方式更改应用程序语言?以下代码(正如最近关于该主题的 Whosebug 帖子所建议的那样)对本地化没有任何影响:
var locale = new Java.Util.Locale("fr");
Java.Util.Locale.Default = locale;
var context = Application.Context;
context.Resources.Configuration.Locale = locale;
BaseContext.ApplicationContext.CreateConfigurationContext(context.Resources.Configuration);
BaseContext.Resources.DisplayMetrics.SetTo(context.Resources.DisplayMetrics);
确实,此代码后的字符串 GetString(Resource.String.stringName)
将保留为英文。
目标版本: Android 8.1 (API 27 - Oreo)
AppCompat Activity 使用 Android.Support.V7.App(仅在 Android.Support.Design.Widget 中使用 FAB)
感谢您的帮助!
createConfigurationContext(configuration)
是不够的,我们需要获取这个方法 returns 的上下文,然后在 attachBaseContext 方法中设置这个上下文。
protected override void AttachBaseContext(Context @base)
{
base.AttachBaseContext(updateBaseContextLocale(@base));
}
private Context updateBaseContextLocale(Context context)
{
var locale = new Java.Util.Locale("sp");
Java.Util.Locale.Default = locale;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
{
Configuration configuration = context.Resources.Configuration;
configuration.SetLocale(locale);
return context.CreateConfigurationContext(configuration);
}
else
{
Resources resources = context.Resources;
Configuration configuration = resources.Configuration;
#pragma warning disable CS0618 // Type or member is obsolete
configuration.Locale = locale;
resources.UpdateConfiguration(configuration, resources.DisplayMetrics);
#pragma warning restore CS0618 // Type or member is obsolete
return context;
}
}
在 OnCreate 方法中获取字符串
string title = GetString(Resource.String.TxtWelcome);
参考
override AttachBaseContext in your activity
受保护的覆盖 void AttachBaseContext(Context @base){base.AttachBaseContext(MyContextWrapper.Wrap(@base,PreferencesManager.Language));} 像这样创建 class MyContextWrapper :
public class MyContextWrapper : ContextWrapper {
public MyContextWrapper(Context @base) : base(@base)
{
}
[SuppressWarnings(Value = new string[] { "deprecation" })]
public static ContextWrapper Wrap(Context context, string language)
{
Configuration config = context.Resources.Configuration;
Locale sysLocale = null;
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
sysLocale = getSystemLocale(config);
}
else
{
sysLocale = getSystemLocaleLegacy(config);
}
if (!language.Equals("") && !sysLocale.Language.Equals(language))
{
Locale locale = new Locale(language);
Category[] vals = null;
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
vals = Locale.Category.Values();
}
else
{
config.SetLayoutDirection(locale);
}
if (vals != null && vals.Length > 0)
{
Locale.SetDefault(vals[0], locale);
}
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
setSystemLocale(config, locale);
}
else
{
setSystemLocaleLegacy(config, locale);
}
}
if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1)
{
context = context.CreateConfigurationContext(config);
}
else
{
context.Resources.UpdateConfiguration(config, context.Resources.DisplayMetrics);
}
return new MyContextWrapper(context);
}
[SuppressWarnings(Value = new string[] { "deprecation" })]
public static Locale getSystemLocaleLegacy(Configuration config)
{
return config.Locale;
}
[TargetApi(Value = (int)BuildVersionCodes.N)]
public static Locale getSystemLocale(Configuration config)
{
return config.Locales.Get(0);
}
[SuppressWarnings(Value = new string[] { "deprecation" })]
public static void setSystemLocaleLegacy(Configuration config, Locale locale)
{
config.Locale = locale;
}
[TargetApi(Value = (int)BuildVersionCodes.N)]
public static void setSystemLocale(Configuration config, Locale locale)
{
config.SetLocale(locale);
}
}
Blockquote
在您的 Activity 中: 受保护的重写 void AttachBaseContext(Context @base) { base.AttachBaseContext(MyContextWrapper.Wrap(@base, PreferencesManager.Language)); }