From 2bb6ec5e65fa89fa0032309918cf17ea71e3695f Mon Sep 17 00:00:00 2001 From: Konstantin Date: Fri, 5 Apr 2024 15:42:07 +0200 Subject: [PATCH] [resources] Select default resource if there are no exact language+region 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 https://github.com/JetBrains/compose-multiplatform/issues/4571 --- .../compose/resources/ResourceEnvironment.kt | 34 +++++++++++++++++-- .../compose/resources/ResourceTest.kt | 13 +++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.kt b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.kt index b39ce64153..00f322fb09 100644 --- a/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.kt +++ b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.kt @@ -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() } @@ -84,4 +82,34 @@ private fun List.filterBy(qualifier: Qualifier): List 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.filterByLocale(language: LanguageQualifier, region: RegionQualifier): List { + 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 } + } } \ No newline at end of file diff --git a/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt b/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt index 8f1f8b36de..61bccc16c0 100644 --- a/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt +++ b/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt @@ -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), ) @@ -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