Search code examples
androidkotlinlocalizationandroid-notificationsandroid-deep-link

Localization sometimes reset to system locale


I have a single activity application, language setting mostly works as intended. I set every view's texts in onCreateView() by the resource id of the text. But sometimes, when I enter my application, the language is the system default instead of the selected language. The same happens when I navigate to the app from deep link (widget or notification).And when I navigate to another fragment and return, everything becomes right with right locale.

I tried to debug my application to discover the reason. Every text by resource id I got according to system default, not the language selected. When I instead wrap my fragment context and then fetch the text, I get the corect result.

This is how I set my language:

private fun changeLang(lang: String, country: String) {
        activity?.let {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                updateResources(it, lang, country)
            }
            updateResourcesLegacy(it, lang, country)
        }
    }

    @TargetApi(Build.VERSION_CODES.N)
    private fun updateResources(context: Context, language: String, country: String) {
        val locale = Locale(language, country)
        Locale.setDefault(locale)
        val resources: Resources = context.resources
        val configuration: Configuration = resources.configuration
        configuration.setLocale(locale)
        context.createConfigurationContext(configuration)
    }

    private fun updateResourcesLegacy(context: Context, language: String, country: String) {
        val locale = Locale(language, country)
        Locale.setDefault(locale)
        val resources: Resources = context.resources
        val configuration: Configuration = resources.configuration
        configuration.locale = locale
        resources.updateConfiguration(configuration, resources.displayMetrics)
    }

In my activity I overrode the following method:

override fun attachBaseContext(newBase: Context?) {
        newBase?.let {
            val pref = Preference(PreferenceHelper.customPrefs(it))
            super.attachBaseContext(ContextWrapper.wrap(newBase, pref.language, pref.country))
        }
    }
class ContextWrapper(base: Context?) : android.content.ContextWrapper(base) {
    companion object {

        fun wrap(context: Context?, lang: String? = "uz", country: String? = ""): ContextWrapper =
            wrap(context, Locale(lang, country))

        fun wrap(context: Context?, newLocale: Locale): ContextWrapper {
            var localizedContext = context

            val res = localizedContext?.resources
            val configuration = res?.configuration

            when {
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> {
                    configuration?.setLocale(newLocale)

                    val localeList = LocaleList(newLocale)
                    LocaleList.setDefault(localeList)
                    configuration?.setLocales(localeList)

                    localizedContext = localizedContext?.createConfigurationContext(configuration!!)

                }

                else -> {
                    configuration?.setLocale(newLocale)
                    localizedContext = localizedContext?.createConfigurationContext(configuration!!)
                }
            }

            res?.updateConfiguration(configuration, res.displayMetrics)

            return ContextWrapper(localizedContext)
        }
    }
}

Solution

  • The reason was not setting the language for application context. Application resources did not get updated. I applied the locale on attachBaseContext method of my application class.