Skip to content

Commit

Permalink
Improve UiText interface
Browse files Browse the repository at this point in the history
Instances of UiText are now data classes, which get the copy constructor
and comparators for free.

Fixed some pre-existing variable substitution issues that surfaced while
adapting to the data classes.
  • Loading branch information
janseeger committed Nov 22, 2023
1 parent f610b02 commit 4a2a68e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,26 @@ import androidx.compose.ui.res.stringResource
sealed interface UiText {
data class DynamicString(val value: String) : UiText

class StringResource(
data class StringResource(
@StringRes val resId: Int,
vararg val args: Any,
) : UiText
val args: List<Any>,
) : UiText {
constructor(
@StringRes resId: Int,
vararg args: Any) : this(resId, args.asList())
}

class MultiLangString(
data class MultiLangString(
private val language: Map<String, String>,
@StringRes val fallbackResource: Int? = null,
vararg val args: Any,
val args: List<Any>,
) : UiText {
constructor(
language: Map<String, String>,
@StringRes fallbackResource: Int? = null,
vararg args: Any,
) : this(language, fallbackResource, args.asList())

fun LocaleList.getStringForLocales(): String? {
val locale = getFirstMatch(language.keys.toTypedArray())
return language[locale?.language]
Expand All @@ -28,21 +38,23 @@ sealed interface UiText {

fun asString(resources: Resources) = when (this) {
is DynamicString -> value
is StringResource -> resources.getString(resId, *args)
is StringResource -> resources.getString(resId, *(args.toTypedArray()))
is MultiLangString -> {
resources.configuration.locales.getStringForLocales()
?: fallbackResource?.let { resources.getString(it, *args) }
val arguments = args.toTypedArray()
resources.configuration.locales.getStringForLocales()?.format(*arguments)
?: fallbackResource?.let { resources.getString(it, *arguments) }
?: throw Resources.NotFoundException("Could not find multilang string")
}
}

@Composable
fun asString() = when (this) {
is DynamicString -> value
is StringResource -> stringResource(id = resId, formatArgs = args)
is StringResource -> stringResource(id = resId, formatArgs = args.toTypedArray())
is MultiLangString -> {
LocalConfiguration.current.locales.getStringForLocales()
?: fallbackResource?.let { stringResource(id = it, formatArgs = args) }
val arguments = args.toTypedArray()
LocalConfiguration.current.locales.getStringForLocales()?.format(*arguments)
?: fallbackResource?.let { stringResource(id = it, formatArgs = *arguments) }
?: throw Resources.NotFoundException("Could not find multilang string")
}
}
Expand Down
27 changes: 27 additions & 0 deletions dachlatten-compose/src/test/kotlin/text/UiTextTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,33 @@ class UiTextTest {
expectResolvedResourceString("String", uiText)
}

@Test
@Config(qualifiers = "en")
fun stringSubstitutionWorks() {
val uiText = UiText.MultiLangString(mapOf("en" to "string %s"),
fallbackResource = null,
"substitution")
expectResolvedResourceString("string substitution", uiText)
}

@Test
@Config(qualifiers = "en")
fun stringSubstitutionWorksForMultipleArguments() {
val uiText = UiText.MultiLangString(mapOf("en" to "string %s and %s"),
fallbackResource = null,
"substitution", "others")
expectResolvedResourceString("string substitution and others", uiText)
}

@Test
@Config(qualifiers = "en")
fun stringSubstitutionWorksFromCompose() {
val uiText = UiText.MultiLangString(mapOf("en" to "string %s and %s"),
fallbackResource = null,
"substitution", "others")
expectResolvedComposeString("string substitution and others", uiText)
}

private fun expectResolvedResourceString(expected: String, uiText: UiText) {
assertEquals(expected, uiText.asString(context.resources))
}
Expand Down

0 comments on commit 4a2a68e

Please sign in to comment.