Change locale programmatically in Kotlin
Asked Answered
A

3

6

I had some codes for change locale programmatically in Java. But when my application migrated to Kotlin, I can't change locale any more.

For example this code in Java worked very good :

public static final void setAppLocale(String language, Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Resources resources = activity.getResources();
        Configuration configuration = resources.getConfiguration();
        configuration.setLocale(new Locale(language));
        activity.getApplicationContext().createConfigurationContext(configuration);
    } else {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
        Configuration config = activity.getResources().getConfiguration();
        config.locale = locale;
        activity.getResources().updateConfiguration(config,
                activity.getResources().getDisplayMetrics());
    }
}

I tried many codes in Kotlin but non of them worked for me. This is my last try:

fun changeLanguage(context: Context, language : String) {
    val locale = Locale(language)
    Locale.setDefault(locale)

    val config = context.resources.configuration
    config.setLocale(locale)
    context.createConfigurationContext(config)
    context.resources.updateConfiguration(config, context.resources.displayMetrics)
}

How can I change application's local in Kotlin? Old codes that were written in Java did not work in Kotlin application.

Attraction answered 10/6, 2018 at 16:35 Comment(6)
You can use Android Studio Java to Kotlin convertor => Menu -> Code -> Convert Java file to Kotlin file.Intercede
Possible duplicate of Change app language programmatically in AndroidBrauer
Converted codes did not work @RuhollahツAttraction
I saw them but non of them worked for me in Kotlin @ZoeAttraction
@ArashHatami Kotlin is Android. It's the same SDK, just different syntax. You're using it wrong with the new one, you have to use the context returned from createConfigurationContext, all which is mentioned in the target duplicate.Brauer
As for the edit: the fact that they're written in Java is completely irrelevant. You have to use the appropriate APIs and not create a hackish solution combining old, deprecated API's with new ones.Brauer
U
9

Create a Context helper class let's say

class ApplicationLanguageHelper(base: Context) : ContextThemeWrapper(base, R.style.AppTheme) {
companion object {

    fun wrap(context: Context, language: String): ContextThemeWrapper {
        var context = context
        val config = context.resources.configuration
        if (language != "") {
            val locale = 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.JELLY_BEAN_MR1) {
                config.setLayoutDirection(locale)
                context = context.createConfigurationContext(config)
            } else {
                context.resources.updateConfiguration(config, context.resources.displayMetrics)
            }
        }
        return ApplicationLanguageHelper(context)
    }

    @SuppressWarnings("deprecation")
    fun setSystemLocaleLegacy(config: Configuration, locale: Locale) {
        config.locale = locale
    }

    @TargetApi(Build.VERSION_CODES.N)
    fun setSystemLocale(config: Configuration, locale: Locale) {
        config.setLocale(locale)
    }
}

}

And in your Activity you can override attachBaseContext

    override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(ApplicationLanguageHelper.wrap(newBase!!, "fa"))
}

To Change the language you can use a Spinner or any other preferred way, to call the following method OnClick

   private fun changeApplicationLanguage(language:String){
    val sharedPreferencesEditor = sharedPreferences.edit()
    when (language) {
        ENGLISH -> sharedPreferencesEditor?.putString(SELECTED_LANGUAGE, ENGLISH)
        PERSIAN -> sharedPreferencesEditor?.putString(SELECTED_LANGUAGE, PERSIAN)
        PASHTO -> sharedPreferencesEditor?.putString(SELECTED_LANGUAGE, PASHTO)
    }
    sharedPreferencesEditor.putBoolean(LANGUAGE_IS_SELECTED, true)
    sharedPreferencesEditor?.apply()
    recreate()
}

make sure you define sharedPreferences and also SELECTED_LANGUAGE , ENGLISH etc, consts

const val SELECTED_LANGUAGE = "language"
const val ENGLISH = "en"
const val PERSIAN = "fa"
const val PASHTO = "ps"

 private lateinit var sharedPreferences: SharedPreferences

and also initialize sharedPreferences in onCreate method after setContent

sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this@Your_Activity_Name)

also Override the base context by adding the following code

 // Overwrite the context
override fun attachBaseContext(newBase: Context?) {
    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(newBase)
    val lang = sharedPreferences.getString(SELECTED_LANGUAGE, "en")
    super.attachBaseContext(ApplicationLanguageHelper.wrap(newBase!!, lang!!))
}

I am sure this method is not an optimal solution, but, this might help

Updraft answered 17/6, 2019 at 11:37 Comment(3)
After spinner selection, the language should load accordingly? How to do that?Yellowweed
@AnbuselvanRocky, I edited the post, hope this help youUpdraft
Note that in case of using an AppCompatActivity activity this answer is not sufficient, you should also follow the guidelines given in this other question. In case it might be of help to anyone, here is a full diff of a working locale change implementation based on these two answers.Alexine
O
1

Try this

fun setAppLocale(languageFromPreference: String?, context: Context) 
{
    
    if (languageFromPreference != null) {

        val resources: Resources = context.resources
        val dm: DisplayMetrics = resources.displayMetrics
        val config: Configuration = resources.configuration
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            config.setLocale(Locale(languageFromPreference.toLowerCase(Locale.ROOT)))
        } else {
            config.setLocale(Locale(languageFromPreference.toLowerCase(Locale.ROOT)))
        }
        resources.updateConfiguration(config, dm)
    }
}

You can set the App Locale within activities by accessing this function from the activities

    ..
    super.onCreate(savedInstanceState)
    setAppLocale(pref.getLanguageFromPreference().toString(), this)
    setContentView(R.layout.activity_main)
    ...

pref.getLanguageFromPreference() returns the langugae string (For example : "en")

Osullivan answered 17/1, 2021 at 20:54 Comment(0)
R
0

You can try using the following function:

private fun change(lang: String) {
    val config = resources.configuration
    val locale = Locale(lang)
    Locale.setDefault(locale)
    config.setLocale(locale)
            
    resources.updateConfiguration(config, resources.displayMetrics)
            
    this.setContentView(R.layout.activity_main)
recreate()
Racial answered 14/5, 2023 at 8:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.