How to implement in app localization with Jetpack Compose

Viewed 106

How to implement in app localization with Jetpack Compose? I mean I don't want the user to change their device language, instead, let them change only the app language. How to achieve that? All of the resources I found talks about changing the device language.

1 Answers

This is what I did based on this answer here.

In your application class, do the following:

class MyApp : Application() {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(LocaleHelper.setLocale(base, myLang))
    }

    companion object {
        var myLang = "en"
    }
}

I'm saving the language in myLang variable, but in practice you will save in Shared Preferences.

In onAttachBaseContext the setLocale is called (it's declared below).

Then, in your activity you will do the same:

class MainActivity : AppCompatActivity() {
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(
            LocaleHelper.setLocale(newBase, MyApp.myLang)
        )
    }
}

The object below will set the language in MyApp.myLang and update the Context object.

object LocaleHelper {
    fun setLocale(context: Context, language: String): Context? {
        MyApp.myLang = language
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }
        return updateResourcesLegacy(context, language);
    }

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

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

Finally, in your composable, you can do the following:

@Composable
fun TestLanguage() {
    val context = LocalContext.current
    Text(text = stringResource(id = R.string.activity_java_text))
    Button(onClick = {
        LocaleHelper.setLocale(context, "pt")
        (context as? Activity)?.recreate()
    }) {
        Text(text = stringResource(id = R.string.btn_ok))
    }
}

Notice the recreate method is called to recreate the current activity and apply the language change.

Related