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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Arash Hatami
  • 5,297
  • 5
  • 39
  • 59
  • You can use Android Studio Java to Kotlin convertor => Menu -> Code -> Convert Java file to Kotlin file. – RuNo280 Jun 10 '18 at 17:11
  • 1
    Possible duplicate of [Change app language programmatically in Android](https://stackoverflow.com/questions/2900023/change-app-language-programmatically-in-android) – Zoe Jun 10 '18 at 17:20
  • Converted codes did not work @Ruhollahツ – Arash Hatami Jun 10 '18 at 17:31
  • I saw them but non of them worked for me in Kotlin @Zoe – Arash Hatami Jun 10 '18 at 17:32
  • @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. – Zoe Jun 10 '18 at 17:33
  • 3
    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. – Zoe Jun 10 '18 at 17:37

3 Answers3

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

Seddiq Sorush
  • 2,709
  • 2
  • 20
  • 20
  • After spinner selection, the language should load accordingly? How to do that? – Anbuselvan Rocky Oct 21 '19 at 18:50
  • @AnbuselvanRocky, I edited the post, hope this help you – Seddiq Sorush Oct 25 '19 at 10:00
  • 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](https://stackoverflow.com/a/58004553/4807429). In case it might be of help to anyone, [here](https://github.com/CNugteren/NLWeer/pull/20/files) is a full diff of a working locale change implementation based on these two answers. – CNugteren Oct 20 '20 at 14:34
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")

Kavya Goyal
  • 126
  • 1
  • 2
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()
allexiusw
  • 1,533
  • 2
  • 16
  • 23