Skip to content

Commit

Permalink
[resources] Select default resource if there are no exact language+re…
Browse files Browse the repository at this point in the history
…gion or default language match (#4577)

We need to filter by language and region together because there is
slightly different logic:
1) if there is the exact match language+region then use it
2) if there is the language WITHOUT region match then use it
3) in other cases use items WITHOUT language and region qualifiers at
all

Given resources:
values
values-en-rUS
values-de

Filter results:
"en" -> values
"en-US" -> values-en-rUS
"en-GB" -> values
"de-IT" -> values-de

fixes #4571
  • Loading branch information
terrakok committed Apr 5, 2024
1 parent d87aa7f commit 2bb6ec5
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ internal var getResourceEnvironment = ::getSystemEnvironment
internal fun Resource.getResourceItemByEnvironment(environment: ResourceEnvironment): ResourceItem {
//Priority of environments: https://developer.android.com/guide/topics/resources/providing-resources#table2
items.toList()
.filterBy(environment.language)
.also { if (it.size == 1) return it.first() }
.filterBy(environment.region)
.filterByLocale(environment.language, environment.region)
.also { if (it.size == 1) return it.first() }
.filterBy(environment.theme)
.also { if (it.size == 1) return it.first() }
Expand Down Expand Up @@ -84,4 +82,34 @@ private fun List<ResourceItem>.filterBy(qualifier: Qualifier): List<ResourceItem
return filter { item ->
item.qualifiers.none { it::class == qualifier::class }
}
}

// we need to filter by language and region together because there is slightly different logic:
// 1) if there is the exact match language+region then use it
// 2) if there is the language WITHOUT region match then use it
// 3) in other cases use items WITHOUT language and region qualifiers at all
// issue: https://github.com/JetBrains/compose-multiplatform/issues/4571
private fun List<ResourceItem>.filterByLocale(language: LanguageQualifier, region: RegionQualifier): List<ResourceItem> {
val withLanguage = filter { item ->
item.qualifiers.any { it == language }
}

val withExactLocale = withLanguage.filter { item ->
item.qualifiers.any { it == region }
}

//if there are the exact language + the region items
if (withExactLocale.isNotEmpty()) return withExactLocale

val withDefaultRegion = withLanguage.filter { item ->
item.qualifiers.none { it is RegionQualifier }
}

//if there are the language without a region items
if (withDefaultRegion.isNotEmpty()) return withDefaultRegion

//items without any locale qualifiers
return filter { item ->
item.qualifiers.none { it is LanguageQualifier || it is RegionQualifier }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ResourceTest {
ResourceItem(setOf(), "default", -1, -1),
ResourceItem(setOf(LanguageQualifier("en")), "en", -1, -1),
ResourceItem(setOf(LanguageQualifier("en"), RegionQualifier("US"), XHDPI), "en-rUS-xhdpi", -1, -1),
ResourceItem(setOf(LanguageQualifier("de"), RegionQualifier("US")), "de-rUS", -1, -1),
ResourceItem(setOf(LanguageQualifier("fr"), LIGHT), "fr-light", -1, -1),
ResourceItem(setOf(DARK), "dark", -1, -1),
)
Expand All @@ -48,6 +49,18 @@ class ResourceTest {
"en",
resource.getResourceItemByEnvironment(env("en", "IN", LIGHT, LDPI)).path
)
assertEquals(
"de-rUS",
resource.getResourceItemByEnvironment(env("de", "US", LIGHT, LDPI)).path
)
assertEquals(
"default",
resource.getResourceItemByEnvironment(env("de", "", LIGHT, LDPI)).path
)
assertEquals(
"default",
resource.getResourceItemByEnvironment(env("de", "IN", LIGHT, LDPI)).path
)
assertEquals(
"default",
resource.getResourceItemByEnvironment(env("ch", "", LIGHT, MDPI)).path
Expand Down

0 comments on commit 2bb6ec5

Please sign in to comment.