0

I have 2 strings.xml files in their values-en and values-fr folders. When I change language from Android settings, app is correctly localized.

However, is there a way to change app language programmatically ? The following code (as suggested by recents stackoverflow posts on that subject) does not have any effect on localization :

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);

Indeed, a string after this code with GetString(Resource.String.stringName) will remain in english.

target version : Android 8.1 (API 27 - Oreo)

AppCompat Activity using Android.Support.V7.App (only to use a FAB in Android.Support.Design.Widget)

Thanks for your help !

sayah imad
  • 1,507
  • 3
  • 16
  • 24
Elaws
  • 1
  • 5

2 Answers2

0

createConfigurationContext(configuration) is not enough, We need need to get the context that this method returns and then to set this context in the attachBaseContext method.

    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;
        }         
    }

Get string in OnCreate method

   string title = GetString(Resource.String.TxtWelcome);

Refer to

https://stackoverflow.com/a/44571077/8187800

ColeX
  • 14,062
  • 5
  • 43
  • 240
  • I used this code in the `OnCreate` method, the only modification being `var locale = new Java.Util.Locale("en");`but the language remains in french. Moreother, it seems that `Resources.UpdateConfiguration` is deprecated. Hence I tried to use `CreateConfigurationContext` that should replace it. – Elaws Jul 21 '20 at 18:50
  • It works, thanks a lot ! I was unable to find proper documentation on that subject. – Elaws Jul 23 '20 at 19:57
0

override AttachBaseContext in your activity

protected override void AttachBaseContext(Context @base){base.AttachBaseContext(MyContextWrapper.Wrap(@base,PreferencesManager.Language));} Create class MyContextWrapper like this :

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

In your Activity : protected override void AttachBaseContext(Context @base) { base.AttachBaseContext(MyContextWrapper.Wrap(@base, PreferencesManager.Language)); }

sajad khajeh
  • 311
  • 2
  • 8