Android context.getResources.updateConfiguration() deprecated
Asked Answered
N

10

128

Just recently context.getResources().updateConfiguration() has been deprecated in Android API 25 and it is advised to use context.createConfigurationContext() instead.

Does anyone know how createConfigurationContext can be used to override android system locale?

before this would be done by:

Configuration config = getBaseContext().getResources().getConfiguration();
config.setLocale(locale);
context.getResources().updateConfiguration(config,
                                 context.getResources().getDisplayMetrics());
Naashom answered 24/10, 2016 at 15:7 Comment(4)
How about applyOverrideConfiguration (untested)?Stonecrop
there is also a simple solution here , very similar to this one #39706239Vincent
[updateConfiguration was deprecated in API level 25] developer.android.com/reference/android/content/res/ResourcesCelebrate
for changing app locale in latest way, you can check this - https://mcmap.net/q/67088/-refresh-navigationview-menu-after-change-localeBengal
N
151

Inspired by Calligraphy, I ended up creating a context wrapper. In my case, I need to overwrite system language to provide my app users with the option of changing app language but this can be customized with any logic that you need to implement.

    import android.annotation.TargetApi;
    import android.content.Context;
    import android.content.ContextWrapper;
    import android.content.res.Configuration;
    import android.os.Build;
    
    import java.util.Locale;
    
    public class MyContextWrapper extends ContextWrapper {

    public MyContextWrapper(Context base) {
        super(base);
    }

    @SuppressWarnings("deprecation")
    public static ContextWrapper wrap(Context context, String language) {
        Configuration config = context.getResources().getConfiguration();
        Locale sysLocale = null;
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
            sysLocale = getSystemLocale(config);
        } else {
            sysLocale = getSystemLocaleLegacy(config);
        }
        if (!language.equals("") && !sysLocale.getLanguage().equals(language)) {
            Locale locale = new Locale(language);
            Locale.setDefault(locale);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                setSystemLocale(config, locale);
            } else {
                setSystemLocaleLegacy(config, locale);
            }
            
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             context = context.createConfigurationContext(config);
        } else {
             context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
            }
        return new MyContextWrapper(context);
    }

    @SuppressWarnings("deprecation")
    public static Locale getSystemLocaleLegacy(Configuration config){
        return config.locale;
    }

    @TargetApi(Build.VERSION_CODES.N)
    public static Locale getSystemLocale(Configuration config){
        return config.getLocales().get(0);
    }

    @SuppressWarnings("deprecation")
    public static void setSystemLocaleLegacy(Configuration config, Locale locale){
        config.locale = locale;
    }

    @TargetApi(Build.VERSION_CODES.N)
    public static void setSystemLocale(Configuration config, Locale locale){
        config.setLocale(locale);
    }
}

and to inject your wrapper, in every activity add the following code:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr"));
}

UPDATE 22/12/2020 After android Material library implementation of ContextThemeWrapper to support dark mode, the language setting would break and language setting is lost. After months of head scratching, problem was resolved by adding the following code to Activity and Fragment onCreate method

Context context = MyContextWrapper.wrap(this/*in fragment use getContext() instead of this*/, "fr");
   getResources().updateConfiguration(context.getResources().getConfiguration(), context.getResources().getDisplayMetrics());

UPDATE 10/19/2018 Sometimes after orientation change, or activity pause/resume the Configuration object resets to default system Configuration and in result we will see the app displaying English "en" text even though we wrapped the context with French "fr" locale. Therefore and as a good practice, never retain the Context/Activity object in a global variable in activities or fragments.

furthermore, create and use the following in a MyBaseFragment or MyBaseActivity:

public Context getMyContext(){
    return MyContextWrapper.wrap(getContext(),"fr");
}

This practice will provide you with 100% bug free solution.

Naashom answered 20/11, 2016 at 12:36 Comment(50)
if i place it more than 1 activity then it is not working for me, can't i just place it in BaseActivity to make effect on whole app?Barghest
@UsmanRana I've applied this to a base activity and it seems to be working for me.Johst
I have one concern with this approach... This is currently being applied to activities only and not the whole application. What will happen for app components which might not start from activities, like services?Johst
@RicardoAmaral in that case you can wrap the service context before using it. pretty easy, since services don't have any GUI rendering to worry about.Naashom
This is still incomplete. What about BroadcastReceiver? How can you apply the change to the context that comes with it?Skater
Why would you extend the ContextWrapper? You don't have anything in it, just static methods?Swearingen
MyContextWrapper cannot be cast to android.app.ContextImplSwithbert
I had to take out createConfigurationContext/updateConfiguration from if-else branch and add below it, else in first Activity everything was ok, but when opened second, the language changed back to device default. Couldn't find the reason.Thiouracil
@BasselMourjan, have you tried this approach on Android 4.4? I have an app with language selection made using this approach. On Android 4.x each time I re-select the language, several Contexts leak (checked using tool Memory usage) and on some devices this leakage causes out of memory crash. See my post here: #41478969Haldis
while this is an awesome answer, it does not support direction changes, RTL <-> LTROur
I added the needed line and post it as this gist: gist.github.com/muhammad-naderi/…Our
@Haldis sorry I still haven't applied this solution on my current active app and waiting for the last second to so do.Naashom
@Thiouracil is right. The system locale is changed correctly, but the configuration goes back to default. As a result, the strings resource file gets back to default. Is there any other way, other than setting configuration everytime in every activityDochandorrach
@Thiouracil Append with @Yash Landia 's answer, so you should add attachBaseContext() method like this post to all your activity (or base activity if you have). It will be called before onCreate().Osugi
@BasselMourjan Is "fr" is default language in your case? super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr")); how about super.attachBaseContext(MyContextWrapper.wrap(newBase,prefs.getLang()));Macaulay
@Macaulay I specified "fr" just as an example for everyone. In my case I have an algorithm which checks if the device language is the same as the selected app language, if that is the case then I do nothing, else I wrap the context to overwrite system language. and my app supports English and ArabicNaashom
what if I need to change the configuration from a service?Emulate
@Emulate you would do something like getContext or getBaseContext and wrap it with provided ContextWrapper then use it accordingly within the service itselfNaashom
@BasselMourjan How should we use it now together with Calligraphy library? I used to call super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)). How should it work now? Thanks in advance1! :)Geranium
@Geranium that is easy, all you have to do is to overwrite the attachBaseContext to look like this: super.attachBaseContext(CalligraphyContextWrapper.wrap(MyContextWrapper.wrap(newBase,"fr")));Naashom
@UsmanRana you can override Application#attachBaseContext in exactly the same fashion, then the Service contexts will be wrapped.Ridicule
It is only important to do this in Activity to handle when the locale is changed after the Application is created. And yes, there is no reason to place these static methods in a ContextWrapper extended class.Ridicule
what method should I call when I want to change the locale for ex: en -> fr given that locale changed on button click, and do I need to recreate the activity after changing the locale, anCapo
how to change language on user selection?Archicarp
@Archicarp you have to save user selection and restart activity.. I hope you get the ideaNaashom
this works but can you tell me how to implement this solution with Calligraphy library as they also use this method with their ContextWrapper .Dahna
@Dahna you can easily do so like this super.attachBaseContext(CalligraphyContextWrapper.wrap(MyContextWrapper.wrap(newBase,"fr")));Naashom
I had an issue: after second activity using attachBaseContext locale was not able to change anymore. Solution: I removed condition that checks current locale. So get methods were useless. That did the trick.Severn
Bassel, could you please add more of your code? super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr")); does not help. I need to get proper string resources based on selected language by the user.Dorison
@Dorison to be honest that was all I needed to support a different language. in case you have problems and wanna be more explicit.. before using myContext.getString(...) you could try and wrap your context with myContext=MyContextWrapper.wrap(newBase,"fr"); to ensure that it was wrapped properlyNaashom
@BasselMourjan, thanks for the answer. Just want to ask you if context.createConfigurationContext(config); is actually switching string resources correctly like in case the user would like to change app language from english to arabic without changing the device language. I've been trying to use it, it's only changing the layout directions but not the string resources. Other answers also add activity.reacreate() in their solutions and I did not see that in yours, so just wondering how would the activity know the user wants to change the app language while the app is open.Dives
@Dives of course after the user selects a different language for application (from your settings activity for example) you would save the language value in preferences and RESTART the activity then after in attachBaseContext you would read the language value from preferences and apply it. my coding was very basic and simple. but you can play around with it however suits your needsNaashom
None of the solutions worked in my case except this! Thanks, Man!Steading
@NiravDangi I will edit soon with some minor improvements, that toggles some bugs related to orientation change or resume/pause behavior or dialogs... so make sure to revisit this within 2 days or so.. cheersNaashom
For Samsung devices with 6.0.1, there is a issue. Locale is working for only 1st time.. from second time it is taking device default.. Any solution for this?Stipple
@PandiriDeepak that is why you should create a method to call for wrapped context and not use context directlyNaashom
@BasselMourjan Where are you using getMyContext() method?Alderson
@Alderson everywhere. whenever I need to call getActivity() or getContext() I call getMyContext() or getMyActivity() which always wraps the context before using it.Naashom
This is very buggy answer. If you pass existing configuration to createConfigurationContext method, you will end up with lots of bugs, for example device orientation will never change. Please see my answerCarberry
"100% bug free" are you sure? not working in androidx.appcompat:appcompat:1.1.0Allegorize
@RahmatIhsan I am using androidx library and everything is still working smoothly. do review your implementation. there must be something that you are missing.Naashom
It works very well for Android 10. But it does not change the language for Android 6(LG Nexus 5). I think something is missing. Please check it out.Virtual
@SerdarDidan it seems that I had a bug caused by copy and paste from last edit. I fixed it by changing Build.VERSION_CODES.JELLY_BEAN_MR1 to Build.VERSION_CODES.NNaashom
@Bassel Mourjan Thanks. But i found another solution.Virtual
Reuse context.getResources().getConfiguration() or create new configuration? I have always done former, but it stoppped working with Android 10, where latter worksGoverness
@Governess I don't know about your case, but I am facing problems with applying this solution while implementing Light/Dark mode theme.. other than that, this solution worksNaashom
This seems to affect the original Context instance. Is there any way to prevent it? For example, to force using English for this function (in some languages it shows differently, such as Arabic) : developer.android.com/reference/android/text/format/… ?Borlow
I'm confused... the 22/12/20 addition/edit suggests to add getResources().updateConfiguration() to every onCreate method... but this just reintroduces the deprecated function... what am I misunderstanding?Vines
@FatMonk all I know is that's what worked for me after couple of months being puzzled after implementing the dark mode theme.Naashom
The best answer, but I changed it to static functionRegulation
L
47

Probably like this :

Configuration overrideConfiguration = getBaseContext().getResources().getConfiguration();
overrideConfiguration.setLocales(LocaleList);
Context context  = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();

Bonus : A blog article who use createConfigurationContext()

Loring answered 27/10, 2016 at 18:16 Comment(9)
Thank you for pointing me in the right direction, I guess eventually one will have to create a ContextWrapper and attach it to activities like it is done by Calligraphy. Anyways the award is yours, but will not consider it as a final answer not until I post the right coding of the workaround.Naashom
@BasselMourjan Thank you ! I look forward to reading your codeLoring
API 24+... Stupid google, can't they just provide us with a simple way?Mayers
@Ab_ yes, google has provided you the simple method setLocale which goes back to API 17. If you need to go back further see the complete solution from Mourjan.Ridicule
@Ridicule Saying "It's simple if you only target these devices" doesn't really make it simple.Encratia
@Encratia There is a simple method if you don't need to support devices that were made before 2012. Welcome to application development!Ridicule
I think i will stick to old deprecated methods, see how far that goes!Orian
from where did you get LocaleListMechanician
If you pass existing configuration to createConfigurationContext method, you will end up with lots of bugs, for example device orientation will never change. Please see my answerCarberry
S
28

I have resolved this without creating any custom ContextWrapper.

First I created an extension function

fun Context.setAppLocale(language: String): Context {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = resources.configuration
    config.setLocale(locale)
    config.setLayoutDirection(locale)
    return createConfigurationContext(config)
}

Then in the activity's attachBaseContext method, simply replacing the context with the new one.

override fun attachBaseContext(newBase: Context) {
  super.attachBaseContext(ContextWrapper(newBase.setAppLocale("bn")))
}
Shoemaker answered 26/6, 2021 at 4:56 Comment(7)
It's should be the best answer in 2022. Thanks.Cashbox
So I have to do this for each of my activities? We do not have a base one (and should not)Foundry
If you can not have a base Activity then yes, you have to do this in each activity.Shoemaker
Hi. I'am curious. How you are inform your activity about configuration change? I mean, you are getting new context instance with the new configuration with that extension method but how your activity gets that new context?Lactoprotein
attachBaseContext() is overridden in the Activity. There you are getting the new config and providing it to its superclass. Therefore, your activity knows about the new configuration.Shoemaker
does this work with androidx.appcompat:appcompat:1.4.0 ?Ender
@MdImranChoudhury not work for me on real phone android 11. but work in android studio on api v.30. You don't know what could be the problem?Ender
G
8

It's 2023 now. I decided to look at the methods I use to change themes and found this method for changing languages. You should know what languages you have.

AppCompatDelegate.setApplicationLocales(
    LocaleListCompat.create(Locale.forLanguageTag("ru"))
)
Giagiacamo answered 8/11, 2023 at 17:8 Comment(3)
This is the best possible working Answer :)Seigniorage
It is important to notice that if you are using Compose and don't need the activity to be recreated as per official documentation you need to set android:configChanges to locale|layoutDirection in activity block of your manifest.Decigram
This works perfectly but , there is slight jerk after this call.Transpolar
A
6

Inspired by Calligraphy & Mourjan & myself, i created this.

first you must create a subclass of Application:

public class MyApplication extends Application {
    private Locale locale = null;

    @Override
    public void onCreate() {
        super.onCreate();

        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

        Configuration config = getBaseContext().getResources().getConfiguration();

        String lang = preferences.getString(getString(R.string.pref_locale), "en");
        String systemLocale = getSystemLocale(config).getLanguage();
        if (!"".equals(lang) && !systemLocale.equals(lang)) {
            locale = new Locale(lang);
            Locale.setDefault(locale);
            setSystemLocale(config, locale);
            updateConfiguration(config);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (locale != null) {
            setSystemLocale(newConfig, locale);
            Locale.setDefault(locale);
            updateConfiguration(newConfig);
        }
    }

    @SuppressWarnings("deprecation")
    private static Locale getSystemLocale(Configuration config) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return config.getLocales().get(0);
        } else {
            return config.locale;
        }
    }

    @SuppressWarnings("deprecation")
    private static void setSystemLocale(Configuration config, Locale locale) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            config.setLocale(locale);
        } else {
            config.locale = locale;
        }
    }

    @SuppressWarnings("deprecation")
    private void updateConfiguration(Configuration config) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            getBaseContext().createConfigurationContext(config);
        } else {
            getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
        }
    }
}

then you need set this to your AndroidManifest.xml application tag:

<application
    ...
    android:name="path.to.your.package.MyApplication"
    >

and add this to your AndroidManifest.xml activity tag.

<activity
    ...
    android:configChanges="locale"
    >

note that pref_locale is a string resource like this:

<string name="pref_locale">fa</string>

and hardcode "en" is default lang if pref_locale is not setted

Absinthe answered 4/8, 2017 at 7:44 Comment(1)
This is not enough, you also need to override context in every activity. As you will end up with situation that your baseContext have one locale, and you application will have another. As a result you will got mixed languages in your ui. Please see my answer.Carberry
C
6

Here is no 100% working solution. You need to use both createConfigurationContext and applyOverrideConfiguration. Otherwise even if you replace baseContext in every activity with new configuration, activity would still use Resources from ContextThemeWrapper with old locale.

So here is mine solution which works up to API 29:

Subclass your MainApplication class from:

abstract class LocalApplication : Application() {

    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(
            base.toLangIfDiff(
                PreferenceManager
                    .getDefaultSharedPreferences(base)
                    .getString("langPref", "sys")!!
             )
        )
    }
}

Also every Activity from:

abstract class LocalActivity : AppCompatActivity() {

    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(            
            PreferenceManager
                .getDefaultSharedPreferences(base)
                    .getString("langPref", "sys")!!
        )
    }

    override fun applyOverrideConfiguration(overrideConfiguration: Configuration) {
        super.applyOverrideConfiguration(baseContext.resources.configuration)
    }
}

Add LocaleExt.kt with next extension functions:

const val SYSTEM_LANG = "sys"
const val ZH_LANG = "zh"
const val SIMPLIFIED_CHINESE_SUFFIX = "rCN"


private fun Context.isAppLangDiff(prefLang: String): Boolean {
    val appConfig: Configuration = this.resources.configuration
    val sysConfig: Configuration = Resources.getSystem().configuration

    val appLang: String = appConfig.localeCompat.language
    val sysLang: String = sysConfig.localeCompat.language

    return if (SYSTEM_LANG == prefLang) {
        appLang != sysLang
    } else {
        appLang != prefLang
                || ZH_LANG == prefLang
    }
}

fun Context.toLangIfDiff(lang: String): Context =
    if (this.isAppLangDiff(lang)) {
        this.toLang(lang)
    } else {
        this
    }

@Suppress("DEPRECATION")
fun Context.toLang(toLang: String): Context {
    val config = Configuration()

    val toLocale = langToLocale(toLang)

    Locale.setDefault(toLocale)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        config.setLocale(toLocale)

        val localeList = LocaleList(toLocale)
        LocaleList.setDefault(localeList)
        config.setLocales(localeList)
    } else {
        config.locale = toLocale
    }

    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        config.setLayoutDirection(toLocale)
        this.createConfigurationContext(config)
    } else {
        this.resources.updateConfiguration(config, this.resources.displayMetrics)
        this
    }
}

/**
 * @param toLang - two character representation of language, could be "sys" - which represents system's locale
 */
fun langToLocale(toLang: String): Locale =
    when {
        toLang == SYSTEM_LANG ->
            Resources.getSystem().configuration.localeCompat

        toLang.contains(ZH_LANG) -> when {
            toLang.contains(SIMPLIFIED_CHINESE_SUFFIX) ->
                Locale.SIMPLIFIED_CHINESE
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ->
                Locale(ZH_LANG, "Hant")
            else ->
                Locale.TRADITIONAL_CHINESE
        }

        else -> Locale(toLang)
    }

@Suppress("DEPRECATION")
private val Configuration.localeCompat: Locale
    get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        this.locales.get(0)
    } else {
        this.locale
    }

Add to your res/values/arrays.xml your supported languages in array:

<string-array name="lang_values" translatable="false">
    <item>sys</item> <!-- System default -->
    <item>ar</item>
    <item>de</item>
    <item>en</item>
    <item>es</item>
    <item>fa</item>
    ...
    <item>zh</item> <!-- Traditional Chinese -->
    <item>zh-rCN</item> <!-- Simplified Chinese -->
</string-array>

I want to mention:

  • Use config.setLayoutDirection(toLocale); to change layout direction when you use RTL locales like Arabic, Persian, etc.
  • "sys" in the code is a value that means "inherit system default language".
  • Here "langPref" is a key of preference where you put user current language.
  • There is no need to recreate the context if it already uses needed locale.
  • There is no need for ContextWraper as posted here, just set new context returned from createConfigurationContext as baseContext
  • This is very important! When you call createConfigurationContext you should pass configuration crated from scratch and only with Locale property set. There shouldn't be any other property set to this configuration. Because if we set some other properties for this config (orientation for example), we override that property forever, and our context no longer change this orientation property even if we rotate the screen.
  • It is not enough only to recreate activity when user selects a different language, because applicationContext will remain with old locale and it could provide unexpected behaviour. So listen to preference change and restart whole application task instead:

fun Context.recreateTask() {
    this.packageManager
        .getLaunchIntentForPackage(context.packageName)
        ?.let { intent ->
            val restartIntent = Intent.makeRestartActivityTask(intent.component)
            this.startActivity(restartIntent)
            Runtime.getRuntime().exit(0)
         }
}
Carberry answered 25/9, 2019 at 12:3 Comment(2)
This does not work. Also consider making a base activity for all activities instead of duplicating code in every activity. As well, the recreateTask(Context context) method is not working properly as I still see layout without any change.Alderson
@Alderson I have updated the samples. There was some bugs previously. But currently it should work, this is the code from my production app. The fun recreateTask could not work, you could display a toast like "The language will be changed after restart"..Carberry
A
3

Here's @bassel-mourjan's solution with a bit of kotlin goodness :) :

import android.annotation.TargetApi
import android.content.ContextWrapper
import android.os.Build
import java.util.*

@Suppress("DEPRECATION")
fun ContextWrapper.wrap(language: String): ContextWrapper {
    val config = baseContext.resources.configuration
    val sysLocale: Locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        this.getSystemLocale()
    } else {
        this.getSystemLocaleLegacy()
    }

    if (!language.isEmpty() && sysLocale.language != language) {
        val locale = Locale(language)
        Locale.setDefault(locale)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            this.setSystemLocale(locale)
        } else {
            this.setSystemLocaleLegacy(locale)
        }
    }

    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        val context = baseContext.createConfigurationContext(config)
        ContextWrapper(context)
    } else {
        baseContext.resources.updateConfiguration(config, baseContext.resources.displayMetrics)
        ContextWrapper(baseContext)
    }

}

@Suppress("DEPRECATION")
fun ContextWrapper.getSystemLocaleLegacy(): Locale {
    val config = baseContext.resources.configuration
    return config.locale
}

@TargetApi(Build.VERSION_CODES.N)
fun ContextWrapper.getSystemLocale(): Locale {
    val config = baseContext.resources.configuration
    return config.locales[0]
}


@Suppress("DEPRECATION")
fun ContextWrapper.setSystemLocaleLegacy(locale: Locale) {
    val config = baseContext.resources.configuration
    config.locale = locale
}

@TargetApi(Build.VERSION_CODES.N)
fun ContextWrapper.setSystemLocale(locale: Locale) {
    val config = baseContext.resources.configuration
    config.setLocale(locale)
}

And here is how you use it:

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(ContextWrapper(newBase).wrap(defaultLocale.language))
}
Alternate answered 7/4, 2019 at 22:0 Comment(1)
This line val config = baseContext.resources.configuration is very very wrong. You will end up with lots of bugs because of this. You need create new configuration instead. See my answer.Carberry
V
0

there is a simple solution with contextWrapper here : Android N change language programatically Pay attention to the recreate() method

Vincent answered 14/3, 2017 at 18:16 Comment(2)
The link is helpful, and a good reference. I believe it's better to include the actual answer here though rather than requiring an additional click.Schmaltzy
you are right i am just new to stackoverflow and i thought it would be wrong to take credits for the answer so i post the link of original authorVincent
R
0

Insperred by Bassel Mourjan (accepted answer) I have created my own Kotlin static function:

fun Context.setCustomAppLanguage(language: String? = null) {
    val candidateLanguage = language ?: PreferenceManager.getDefaultSharedPreferences(this)
        .getString(LOCALE_KEY, Locale.ENGLISH.language)!!
    val config = resources.configuration
    if (candidateLanguage.isNotBlank() && config.locales[0].language != candidateLanguage) {
        val locale = Locale(candidateLanguage)
        Locale.setDefault(locale)
        config.setLocale(locale)
        val wrappedContext = ContextWrapper(createConfigurationContext(config))
        resources.updateConfiguration(
            wrappedContext.resources.configuration,
            wrappedContext.resources.displayMetrics
        )
    }
}

It can changes the language on the fly and works on SDK 34. You need to call it for every each context, so I do it in the base fragment (single activity approach) + in the App class for applicationContext. After executing function you need invalidate you UI - don't forget to do it.

Regulation answered 13/10, 2023 at 10:2 Comment(0)
M
-1

Try this:

Configuration config = getBaseContext().getResources().getConfiguration();
config.setLocale(locale);
context.createConfigurationContext(config);
Marroquin answered 24/10, 2016 at 15:11 Comment(1)
It just creates the activity u need to switch context with new oneBeech

© 2022 - 2024 — McMap. All rights reserved.