Both functions lived in Calendula's ui/common/LocaleSupport.kt. Neither is
calendar-specific — "lay this date out the way this language writes dates" is
family plumbing — so they move here, where Agendula can reach them too.
localizedDateFormatter(locale, skeleton) takes a field list ("LLLLy", "dMMMy")
and lets the locale arrange it, which is the only way to render a date correctly
in a language you didn't hand-write a template for. Dropping a field from the
skeleton drops it from the output, so callers ask for "no year" by omitting it
rather than post-processing a longer pattern.
currentLocale() reads the display locale from LocalConfiguration. This module's
own AppLanguage.apply() changes the language inside a running process, so a
locale captured once goes stale; keying on the configuration makes the UI follow
the switch.
core-locale gains Compose (runtime + ui only) for currentLocale(). Its build file
previously declared itself Compose-free, but the alternative — parking the hook
in a Compose module that depends back on this one — splits one concern across two
modules to honour a comment. core-crash is the precedent for a core-* module
carrying Compose.
Leaves core-time's Instant.formatDate() family alone despite the overlap: it is
unused by Calendula but visible to Agendula, so reconciling it is that app's
call, not a drive-by here. Noted in the changelog.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
2.4 KiB
Kotlin
71 lines
2.4 KiB
Kotlin
// core-locale — everything "what language are we in", shared across the family:
|
|
// read the shipped languages from res/xml/locales_config.xml, get/set the applied
|
|
// language via AppCompatDelegate, render each language's autonym, observe the
|
|
// current locale from Compose, and format dates in that locale's own field order.
|
|
// App-agnostic — the consuming app passes its own locales_config resource id; no
|
|
// DataStore.
|
|
//
|
|
// Compose is here for currentLocale() alone: applying a language mid-process is
|
|
// this module's own API, so the hook that makes the UI notice belongs beside it
|
|
// rather than in a Compose module that would have to depend back on this one.
|
|
// (core-crash is the precedent for a core-* module carrying Compose.) Deliberately
|
|
// lean: runtime + ui only, no material3, no foundation.
|
|
plugins {
|
|
// AGP 9.x provides built-in Kotlin compilation, so only the Compose plugin is
|
|
// applied alongside the Android library plugin.
|
|
alias(libs.plugins.android.library)
|
|
alias(libs.plugins.kotlin.compose)
|
|
}
|
|
|
|
android {
|
|
namespace = "de.jeanlucmakiola.floret.locale"
|
|
compileSdk = 37
|
|
|
|
defaultConfig {
|
|
minSdk = 29
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
targetCompatibility = JavaVersion.VERSION_17
|
|
}
|
|
|
|
buildFeatures {
|
|
compose = true
|
|
}
|
|
|
|
testOptions {
|
|
unitTests {
|
|
all { it.useJUnitPlatform() }
|
|
isReturnDefaultValues = true
|
|
}
|
|
}
|
|
}
|
|
|
|
kotlin {
|
|
compilerOptions {
|
|
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
// appcompat brings AppCompatDelegate plus its core (LocaleListCompat) and
|
|
// annotation (XmlRes) transitives.
|
|
implementation(libs.androidx.appcompat)
|
|
|
|
// ConfigurationCompat for currentLocale(). Reachable transitively via
|
|
// appcompat, but declared because this module uses it directly.
|
|
implementation(libs.androidx.core.ktx)
|
|
|
|
// currentLocale() only needs the runtime (@Composable, remember) and ui
|
|
// (LocalConfiguration) — api() so consumers can use the returned Locale in
|
|
// their own composables without re-declaring Compose themselves.
|
|
api(platform(libs.androidx.compose.bom))
|
|
implementation(libs.androidx.ui)
|
|
|
|
testImplementation(libs.junit.jupiter.api)
|
|
testRuntimeOnly(libs.junit.jupiter.engine)
|
|
testRuntimeOnly(libs.junit.platform.launcher)
|
|
testImplementation(libs.truth)
|
|
}
|