Javokhir Akramjonov
06/22/2024, 12:53 PMstringResource(Res.string.current_plan)
How can I change locale of app in runtime.
Currently locale is system default. It is taking all strings based on system default language correctly. But I want to get strings in any language I want
Thanks beforehandAlejandro Rios
06/22/2024, 2:50 PMVlad
07/01/2024, 7:00 PMRok Oblak
07/07/2024, 10:40 AMMeet
07/19/2024, 9:40 AMVlad
07/19/2024, 9:42 AMMeet
07/19/2024, 9:43 AMVlad
07/19/2024, 9:44 AMMeet
07/19/2024, 9:44 AMMeet
07/19/2024, 10:39 AMdata class MyString(
val english: String,
val spanish: String
)
val appName = MyString(
english = "My App",
spanish = "Mi aplicación"
)
Vlad
07/19/2024, 10:49 AMenum StringToken(mokoRes: StringResource, appSpecificTranslationKey: String) { Helllo(mokoRes = MR.stringResource.HELLO, appSpecificTranslationKey = "hello")}
I pass only that enum in the app, eg from ViewModel into state.
I have my own @Composable stringResource(token: StringToken)
which will provide actual value from the token.
Under the hood it access singletone to resolve the value.
The singletone is subscribed to DataStore field with "currentLanguage" and whenever it changes I update Mokos Locale + My custom translator.
Since the custom translator is mutableState - all stringResource() recomposed.
Because of all these abstractions we don't really care too much what Res lib we are currently use (because in fact there are only 2 classes actually depend on it) and can extend it with custom translations (loaded from API at runtime)
So when you design
val appName = MyString(
english = "My App",
spanish = "Mi aplicación"
)
first thing you need to be aware - how you gonna force it to automatically pick app.name.spanish when you change the locale to SpanishMeet
07/19/2024, 10:53 AMMeet
07/19/2024, 10:53 AMVlad
07/19/2024, 10:53 AMMeet
07/19/2024, 10:57 AMMeet
07/19/2024, 10:58 AMval nsUserDefaults = NSUserDefaults.standardUserDefaults()
nsUserDefaults.setObject(listOf(language), forKey = "AppleLanguages")
nsUserDefaults.synchronize()
Meet
07/19/2024, 10:58 AMVlad
07/19/2024, 10:59 AMVlad
07/19/2024, 11:00 AMdata class Translator(
val languageCode: String,
val translations: Map<String, String>
)
class AppResourcesProvider(
private val getTranslator: GetTranslator
) {
private var translator: Translator? by mutableStateOf(
null
)
init {
loadTranslator()
}
@Composable
override fun getString(stringToken: StringTokens): String {
return translator?.translate(stringToken.translationKey)
}
}
// [START Local composition] Adds Translator into local composition, put it somewhere on top of the tree
// This is basically connction between functional and OOP
internal val LocalAppResourcesProvider = staticCompositionLocalOf<ResourcesProvider> {
error("App resources provider is not provided for local")
}
object AppRes {
val provider: ResourcesProvider
@Composable
get() = LocalAppResourcesProvider.current
}
// [END Local composition]
// [USAGE from UI] aka Text(text = helloToken).
@Composable
internal fun stringResource(stringToken: StringTokens): String {
return AppRes.provider.getString(stringToken = stringToken)
}
This is our idea. In production it is more complicated because it resolves both Hardcoded resource and optional translationMeet
07/19/2024, 11:04 AM