Reputation: 121
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
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
Create Respective String Resources: res > new > Android Resourse File > Select Locale and create a string.xml files
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>
android{
...
androidResources {
generateLocaleConfig = true
}
...
defaultConfig {
...
resourceConfigurations.plus(listOf("ta", "en", "hi","your-langauge-tag"))
}
}
... <application ...>
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
</application>
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)
)
}
}
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
Reputation: 59
You can try this
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)
}
}
}
setLocale
inside setContent
to change the language at runtime. setContent {
LocaleUtils.setLocale(LocalContext.current, viewModel.pref)
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
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