Rok Oblak
05/24/2025, 7:26 AMThis includes ${arg1}, ${arg2} and ${arg3}.
3. let Gemini translate into other languages
4. in the IDE, run a script which downloads the sheet and generates references such as LangStrings.errors.generic
and functions for formatted content, such as LangStrings.messages.someFormattedMsg(arg1: String, arg2: String, arg3: String)
5. composition locals and a few helper functions make it easy to reference the translations in Compose: Text( LangStrings.cta.someMessage())
Code samples in thread.
My goals:
• allow non-devs to modify the translations easily
• have an automatic step to sync the translations with the source of truth (spreadsheets)
• generate references of type StrKey
so that a translatable string can be referred to before we know the locale
• generate type-safe formatting functions for translations with arguments (so far it only accepts string args, but it could be extended to typed args)Rok Oblak
05/24/2025, 7:29 AMRok Oblak
05/24/2025, 7:30 AMRok Oblak
05/24/2025, 7:30 AMRok Oblak
05/24/2025, 7:31 AMpublic fun inviteCompanyFormatted(
locale: AppLocale,
USER_EMAIL: String,
USER_FIRST_AND_LAST_NAME: String,
COMPANY_NAME: String,
URL: String,
): String = _inviteCompany.resolve(locale).formattedWithNamed(listOf("USER_EMAIL" to USER_EMAIL, "USER_FIRST_AND_LAST_NAME" to USER_FIRST_AND_LAST_NAME, "COMPANY_NAME" to COMPANY_NAME, "URL" to URL))
Rok Oblak
05/24/2025, 7:32 AM@Composable
operator fun StrKey.invoke(vararg args: Any): String {
val locale = LocalLocale.current
val argsList = args.toList()
return TranslationUtil.resolve(this, locale).formattedWith(argsList)
}
@Composable
operator fun StrKey.invoke(): String {
val locale = LocalLocale.current
return TranslationUtil.resolve(this, locale)
}
Rok Oblak
05/24/2025, 7:33 AMRok Oblak
05/24/2025, 7:36 AMThomas Hormes
05/24/2025, 11:43 AMThomas Hormes
05/24/2025, 11:44 AMGuyaume Tremblay
05/26/2025, 7:45 PM