Moe
03/26/2025, 1:35 AMCompositionLocal
and Compose idioms.
🔧 What it does:
• Lets you use t("key")
anywhere in your composables
• Switch languages at runtime with LocalizationProvider
• Designed specifically for Compose Web (WASM)
• Minimal setup, no magic, no boilerplate
Available on Maven Central
Github: https://github.com/MohammadNasrallahBlank/kmp-localize
It’s already powering my own WASM apps — feel free to try it out, break it, and share any feedback!
Would love to hear if it helps or if you spot ways it can improve ✌️Rok Oblak
03/26/2025, 5:08 AMCTAStrings(val submit: String)
Strings(val one: String, val two: String, val three: (Int) -> String, cta: CTAStrings)
val LangAStrings = Strings(...)
val LangBStrings = Strings(...)
and using a composition local to provide it via LocalStrings.current.two
or LocalStrings.current.cta.submit
especially since you use string literals to refer to entries in your map.
which means once you have hundreds/thousands of strings, it will not scale, because you will have to keep track of names using a separate bunch of constants.
Another issue is that they are all on the same level. You're going to have hundreds of things on the same level which means it's going to be harder and harder to find names which don't conflict and which refer to that specific feature; as opposed to having them grouped.
For simple strings (i.e. just strings, not multiline markup, not functions) I ended up with:
1. creating a Google Sheet document with multiple sheets, i.e. general
, cta
, errors
2. creating a script which fetches the sheet and uses Kotlin Poet to parse the data and generate the individual translations
So I can (or anyone else with access) just edit the sheet and my script will automatically translate and generate these:
val EN_Translations: Translations = Translations(
general = General(
one = "one_EN",
two = "two_EN"
),
errors = Errors(
test1 = "test1EN",
test2 = "test2EN"
),
cta = Cta(
submit = "submit_EN",
test = "test_EN"
)
)
Konstantin Tskhovrebov
03/26/2025, 10:00 AMian.shaun.thomas
03/26/2025, 3:37 PMMoe
03/26/2025, 5:17 PMdata class
+ CompositionLocal
+ codegen approach scales really well, especially when you have a well-structured system with nesting, type safety, and maybe some KotlinPoet automation behind it.
The motivation behind Compose Localizer was actually quite different:
Primary Goal was to lower the barrier to entry
This library is mostly aimed at:
• People building simple to moderately complex Compose Web apps (especially WASM)
• Those who don’t want to deal with sealed interfaces
, nesting, codegen, or Google Sheets from day one
• Use cases where just dropping a simple t("key")
is enough, and devs want something that “just works”
It’s meant to be a:
✅ No-setup-needed
✅ Works out-of-the-box
✅ Easy to drop into any KMP-WASM projectThe is definitely room for improvement here, which i do plan on doing in the near future, however I honestly made this so i can use it in my own projects, which was the least amount of work that could be done that suits what I needed in regards to scaling versus simplicity. So in short, you’re right, this won’t scale as cleanly for large apps today, but it’s a great “day-one” solution, and hopefully a nice starting point for teams who just want to localize a WASM app without wiring up anything complex.
Moe
03/26/2025, 5:19 PMDatePicker
, TimePicker
• Snackbar
accessibility labels
• or any Material3 components that rely on PlatformLocale
or androidx.compose.material3.LocalStrings
That said, you can still localize your own texts shown in Material3 components
So if you control the UI, you’re good, but anything handled internally by Material3’s localization system won’t be auto-patched yet.
If there's interest, I’d love to explore some form of compatibility layer or hook for plugging Compose Localizer
into Material3 string providers (for WASM/JS where Material3 is running on Compose HTML APIs).
Right now, it’s scoped to UI strings under your control, but I’m definitely open to expanding that.Moe
03/26/2025, 5:20 PM