How to change language locale in Jetpack Compose

Viewed 2864

I want to change language programmatically in Jetpack Compose. I've read quite some posts and watch videos but still can't find the way to do it. (The post and video are in Android view system.)

How to change language in kotlin (locale)
https://www.youtube.com/watch?v=xxPzi2h0Vvc

I want my app works like below image. After clicking the language, the whole app will change the language. Below code is the clickable's part. What should I do in this clickable part and MainActivity.kt?

@Composable
fun LanguageScreen(
    navController: NavController,
) {
    val context = LocalContext.current
    val langList = arrayOf("English", "繁體中文", "简体中文", "日本語")
    var items by remember {
        mutableStateOf(
            langList.map {
                LanguageItem(
                    title = it,
                    isSelected = false
                )
            }
        )
    }
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
    ) {
        items(items.size) { i ->
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {

                        items = items.mapIndexed { j, item ->
                            if (i == j) {
                                item.copy(isSelected = true)
                            } else item.copy(isSelected = false)
                        }

                        if (i == 0) {
                            setLocaleLang("", context)
                        } else if (i == 1) {
                            setLocaleLang("zh-rTW", context)
                        } else if (i == 2) {
                            setLocaleLang("zh-rCN", context)
                        } else {
                            setLocaleLang("ja", context)
                        }

                    }
                    .padding(16.dp),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(text = items[i].title, fontSize = 20.sp)
                if (items[i].isSelected) {
                    Icon(
                        imageVector = Icons.Default.Check,
                        contentDescription = "Selected",
                        tint = Color.Blue,
                        modifier = Modifier.size(24.dp)
                    )
                }
            }
            Spacer(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(1.dp)
                    .background(Color.LightGray)
            )
        }
    }
}


fun setLocaleLang(lang: String, context: Context) {
    val locale = Locale(lang)
    Locale.setDefault(locale)
    val resources = context.resources
    val configuration = resources.configuration
    configuration.setLocale(locale)
    resources.updateConfiguration(configuration, resources.displayMetrics)

    val editor = context.getSharedPreferences("Settings", Context.MODE_PRIVATE).edit()
    editor.putString("My_Lang", lang)
    editor.apply()
}

fun loadLocale(context: Context) {
    val sharedPreferences = context.getSharedPreferences("Settings", Activity.MODE_PRIVATE)
    val language = sharedPreferences.getString("My_Lang", "")
    setLocaleLang(language!!, context)
}

MainActivity.kt

class MainActivity : ComponentActivity() {
    @ExperimentalFoundationApi
    override fun onCreate(savedInstanceState: Bundle?) {

        loadLocale(this)

        super.onCreate(savedInstanceState)
        setContent {
            SpanishTravelTheme {

Image: https://i.stack.imgur.com/y5kcO.png

2 Answers

Try this

 val context = LocalContext.current
 Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                           val locale = Locale(language) //Here I assume you have access to the language you want
        Locale.setDefault(locale)
        val resources = context.getResources()
        val configuration = resources.getConfiguration()
        configuration.locale = locale
        resources.updateConfiguration(configuration, resources.getDisplayMetrics())
                    }
                    .padding(16.dp),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            )

You can try this

  1. Create a helper object

LocaleUtils.kt

object LocaleUtils {

// [AppPrefs] is sharedpreferences or datastore
fun setLocale(c: Context, pref: AppPrefs) = updateResources(c, pref.language ?: "en") //use locale codes

private fun updateResources(context: Context, language: String) {
    context.resources.apply {
        val locale = Locale(language)
        val config = Configuration(configuration)

        context.createConfigurationContext(configuration)
        Locale.setDefault(locale)
        config.setLocale(locale)
        context.resources.updateConfiguration(config, displayMetrics)
    }
  }
}
  1. Call setLocale inside setContent to change the language at runtime.
    setContent {
        LocaleUtils.setLocale(LocalContext.current, viewModel.pref)
  1. To change the App language
    fun changeAppLanguage(languageISO: String) {
        sharedPrefs.edit().putString(LANGUAGE_KEY, languageISO).apply()
    }

Please remember to use language ISO 639-1 Code

here's a list of Locale codes https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/localization

Related