简体   繁体   English

Android 使用 JetPack Compose 更改语言

[英]Android Language change using JetPack Compose

I am trying to change locale of the application using jetpack compose function like below我正在尝试使用 jetpack compose function 更改应用程序的语言环境,如下所示

  @Composable
 fun SetLanguage(position: Int) {
    val locale = Locale(
        when (position) {
            0 -> "ar"
            1 -> "en"
            2 -> "fr"
            else -> {
                "ar"
            }
        }
    )
    Locale.setDefault(locale)
    val configuration = LocalConfiguration.current
    configuration.setLocale(locale)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
        configuration.setLocale(locale)
    else
        configuration.locale = locale
    var resources = LocalContext.current.resources
    resources.updateConfiguration(configuration, resources.displayMetrics)

}

you can check the working example (without buttons or textfield ) here https://github.com/MakeItEasyDev/Jetpack-Compose-Multi-Language-Support您可以在此处查看工作示例(没有按钮或文本字段) https://github.com/MakeItEasyDev/Jetpack-Compose-Multi-Language-Support

but the problem that is not working with OutlinedTextField or Buttons as they dont change when this function is called even rightToLeft support is not working and i dont find a good alternative to this solution for my problem as i cant recreate the activity in my project但是不适用于 OutlinedTextField 或 Buttons 的问题,因为当调用此 function 时它们不会改变,甚至 rightToLeft 支持也不起作用,我找不到解决我问题的好方法,因为我无法在我的项目中重新创建活动

The problem many developers make when starting out with Compose is believing that when a recomposition occurs, everything within the composable will get recomposed.许多开发人员在开始使用 Compose 时遇到的问题是,他们认为当重组发生时,可组合项中的所有内容都会被重组。 This isn't true.这不是真的。 Compose looks at the composable signature and tries to determine if anything changes from the last time it was called. Compose 查看可组合签名并尝试确定自上次调用以来是否有任何变化。 Only when the parameter values change will the function be called.只有当参数发生变化时,才会调用 function。 In the source code you posted on Github, it didn't include a button or outline text field to demonstrate the problem, so I added one.在您发布在 Github 上的源代码中,它没有包含用于演示问题的按钮或大纲文本字段,因此我添加了一个。 When you add a button like this:当您添加这样的按钮时:

Button(onClick = {}) {
     Text("Do Something")
}

the Text composable inside of the Button will only be called when the initial composition occurs.仅在初始组合发生时才会调用 Button 内部的可组合文本。 But when the Button is recomposed, the Text will not be recomposed because the last parameter in the Button function hasn't changed.但是当 Button 被重组时,Text 不会被重组,因为 Button function 中的最后一个参数没有改变。 Lambda functions don't change. Lambda 功能不变。 In regard to your case, changing the language does initiate a recomposition of the button, but because the last parameter does not change, the content inside of the lambda (in this example, the Text composable) will never be called.就您的情况而言,更改语言确实会启动按钮的重新组合,但由于最后一个参数没有更改,因此永远不会调用 lambda 内部的内容(在本例中为可组合的文本)。 To get around this, one solution is to make the string resource that is used by the Text composable mutable.为了解决这个问题,一种解决方案是使 Text 可组合使用的字符串资源可变。 Anything that is mutable will automatically cause any composable that uses it to recompose.任何可变的东西都会自动导致使用它的任何可组合对象重新组合。

The following code is what I took from your Github project and added a button.以下代码是我从您的 Github 项目中获取并添加了一个按钮的代码。 Notice how the string resource id is made mutable and this mutable state is used inside the Text:注意字符串资源 id 是如何可变的,并且这个可变的 state 在文本中使用:

@Composable
fun LanguageContentPortrait(
    selectedPosition: Int,
    onLanguageSelected: (Int) -> Unit
) {
    val buttonTextResId by remember { mutableStateOf(R.string.hello) }

    CompositionLocalProvider(
        LocalLayoutDirection provides
                if (LocalConfiguration.current.layoutDirection == LayoutDirection.Rtl.ordinal)
                    LayoutDirection.Rtl
                else LayoutDirection.Ltr
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {

            Spacer(modifier = Modifier.height(100.dp))
            ToggleGroup(selectedPosition = selectedPosition, onClick = onLanguageSelected)
            Spacer(modifier = Modifier.height(60.dp))
            Column(
                modifier = Modifier.fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                Text(
                    text = stringResource(id = R.string.content),
                    modifier = Modifier.fillMaxSize(),
                    textAlign = TextAlign.Center
                )

                Button(onClick = {}) {
                    Text(stringResource(buttonTextResId))
                }
            }
        }
    }
}

So anywhere you use trailing lambda expressions including click event handlers and you need language-dependent changes to occur, you will need to add mutable states to those resources inside those lambdas as shown above.因此,在任何使用尾随 lambda 表达式(包括单击事件处理程序)并且需要发生与语言相关的更改的任何地方,您都需要将可变状态添加到这些 lambda 中的这些资源,如上所示。

Even though the solution above works, I can't recommend using it.即使上面的解决方案有效,我也不推荐使用它。 Most apps will have a lot of language dependent components and having to create a mutable state for every resource string would be a pain.大多数应用程序都会有很多依赖于语言的组件,并且必须为每个资源字符串创建一个可变的 state 会很痛苦。 A better solution is to force your entire app to recompose whenever the language changes.更好的解决方案是在语言更改时强制您的整个应用程序重新组合。 Since Compose-only apps are generally only a single activity, it will cause the entire app to recompose.由于仅 Compose 的应用程序通常只有一个 Activity,因此会导致整个应用程序重新编写。 This will ensure that all screens recompose and force all the Text composables to recompose without the need to have a mutable state for each one.这将确保所有屏幕都重新组合并强制所有文本组合重新组合,而无需为每个屏幕设置一个可变的 state。 There are different ways you can force your app to recompose the entire UI tree.您可以通过多种方式强制您的应用重构整个 UI 树。

Since your app is designed to work with device configuration changes such as language changes, you might want to check out a Compose framework I developed that was specifically designed to handle device configuration changes.由于您的应用程序旨在处理设备配置更改(例如语言更改),您可能需要查看我开发的专门用于处理设备配置更改的 Compose 框架。 It's called Jetmagic.它被称为 Jetmagic。 It not only handles language changes but all the other changes like screen orientation, screen size, screen density and all the other configuration qualifiers that are used with the older view-based system.它不仅处理语言更改,还处理所有其他更改,例如屏幕方向、屏幕大小、屏幕密度以及与旧的基于视图的系统一起使用的所有其他配置限定符。 Jetmagic allows you to treat your composables like resources instead of just a bunch of functions and it handles them in the exact same way xml resources are handled under the view-based system using the same algorithm. Jetmagic 允许您将可组合对象视为资源,而不仅仅是一堆函数,并且它以完全相同的方式处理它们The sample app included also shows how changing your system language causes your composable UIs to recompose rendering the content in the correct language:包含的示例应用程序还显示了更改系统语言如何导致可组合 UI 重新组合以正确语言呈现内容:

https://github.com/JohannBlake/Jetmagic https://github.com/JohannBlake/Jetmagic

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM