Locale (Localization)
SkillDev toolsThe KMP Starter Template localization system — StarterLocales, StarterLocale, LocaleProvider, and the locale selector UI in features/locale.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Locale (Localization) skill
What this skill tells your AI
The instructions your AI receives, as published by devatrii/kmp-starter-template in .agents/skills/kmp-starter/starter-features/locale/SKILL.md and read by ahel’s review.
In-app language switching with RTL/LTR support. Module: features/locale.
Where things live
| Piece | Path |
|---|---|
StarterLocales (registry) / StarterLocale | features/locale/src/commonMain/.../StarterLocale.kt |
LocaleProvider | features/locale/src/commonMain/.../LocaleProvider.kt |
LocalAppLocale (expect/actual) | .../LocalAppLocale.kt (+ .android.kt, .ios.kt) |
rememberStarterActiveLocale / rememberStarterLocaleDataStore | .../LocaleProvider.kt |
LocaleSelectorDropdown / LocaleSelectorContainer | .../ui/LocaleSelectorDropdown.kt, LocaleSelectorContainer.kt |
Data model
data class StarterLocale(
val emoji: String, // e.g. "🇵🇰"
val langCode: String, // "en", "ur", "es", "es_AR"
val displayName: StringResource, // localized label (Res.string.lang_*)
val layoutDirection: LayoutDirection = LayoutDirection.Ltr,
)
StarterLocales is a registry:
object StarterLocales {
val DEFAULT = StarterLocale("🇺🇸", "en", Res.string.lang_en)
val locales get() = _locales.toSet()
fun add(locale: StarterLocale)
fun add(locales: Iterable<StarterLocale>)
fun findBy(langCode: String): StarterLocale?
}
Register locales + provide them
In App.kt (composeApp), define supported locales and wrap the app with LocaleProvider:
val supportedLocales = setOf(
StarterLocale("🇵🇰", "ur", Res.string.lang_ur, LayoutDirection.Rtl),
StarterLocale("🇮🇳", "hi", Res.string.lang_hi),
StarterLocale("🇪🇸", "es", Res.string.lang_es),
)
LocaleProvider(
locales = supportedLocales,
overrideDefault = StarterLocales.findBy("en"),
) {
// app content — provides LocalAppLocale + LocalLayoutDirection
}
LocaleProvider resolves the active locale with priority: User preference → overrideDefault → System locale → DEFAULT. It provides both LocalAppLocale (lang code) and LocalLayoutDirection (RTL/LTR) to the tree. The selection persists to DataStore.
Locale selector UI
Drop in LocaleSelectorDropdown (Cupertino-style) where users pick a language:
LocaleSelectorDropdown(
label = Res.string.choose_language,
isLast = true,
)
LocaleSelectorContainer wraps the stateful selection; LocaleSelectorDropdown lists StarterLocales.locales and writes the choice back to the DataStore.
Rules
- Add languages as
Res.string.lang_*resources +StarterLocaleentries (see resources-theme skill). - Use
LocaleProviderfor resolution — don't manage locale state manually. - Respect
layoutDirectionfor RTL languages. - No parallel localization system.
Reference
- Docs:
https://starter.atherio.dev/fundamentals/07-multiple-languages/ - Source:
features/locale/*
Signals
- GitHub stars
- 162
- Forks
- 28
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
kmp-starter-feature-locale- Source
- github.com/devatrii/kmp-starter-template