Justin
Justin

Reputation: 121

How to change language locale in Jetpack Compose

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.sstatic.net/y5kcO.png

Upvotes: 12

Views: 15644

Answers (3)

Eknath
Eknath

Reputation: 174

Here is my solution to this:

Sample App: https://github.com/Eganathan/Compose-LocalizationSample Doc: https://developer.android.com/guide/topics/resources/app-languages

  1. Create Respective String Resources: res > new > Android Resourse File > Select Locale and create a string.xml files

  2. in res/xml create a new file called locales_config.xml and fill in the locale of your choices.

example:

<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
    <locale android:name="en" />
    <locale android:name="ta" />
    <locale android:name="hi" />
    <locale android:name="ml" />
</locale-config>
  1. moving to gradle:
android{
...
   androidResources {
        generateLocaleConfig = true 
    }
...

  defaultConfig {
...
  resourceConfigurations.plus(listOf("ta", "en", "hi","your-langauge-tag"))

  }

}
  1. Moving to Manifest file:
   ... <application ...>
     <service
       android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
            android:enabled="false"
            android:exported="false">
            <meta-data
                android:name="autoStoreLocales"
                android:value="true" />
     </service>
</application>
  1. add the following function anywhere you like:
fun localeSelection(context: Context, localeTag: String) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        context.getSystemService(LocaleManager::class.java).applicationLocales =
            LocaleList.forLanguageTags(localeTag)
    } else {
        AppCompatDelegate.setApplicationLocales(
            LocaleListCompat.forLanguageTags(localeTag)
        )
    }
}
  1. now where ever you want to pass the on click just call the above funciton:
localeSelection(context = context, localeTag = currentLocale.value)

example:

val context = LocalContext.current

Button(onClick = {
                localeSelection(context = context, localeTag = Locale("ta").toLanguageTag())
            }) {
                Text(text = "Tamil")
            }

Please refer to my sample app or the Doc if you have any doubts.

Doc: https://developer.android.com/guide/topics/resources/app-languages

PS: Here the locale is stored and managed by the system itself and I'm using Kotlin.

Upvotes: 3

emAd H
emAd H

Reputation: 59

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

UPDATE:

now you can just use AppCompatDelegate from androidx.appcompat

Example:

AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags("en"))

Upvotes: 2

Richard Onslow Roper
Richard Onslow Roper

Reputation: 6863

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
            )

Upvotes: 1

Related Questions