Internationalization (i18n) in Kotlin: A Complete Guide with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Internationalization (i18n) in Kotlin: A Complete Guide with Examples



Internationalization (i18n) is the process of designing and developing software so that it can be adapted to various languages and regions without requiring changes to the source code. In the Kotlin ecosystem, whether it's Android applications, server-side projects on Ktor, or multiplatform solutions with Kotlin Multiplatform, proper implementation of i18n is critically important for the global success of a product. In this article, we will explore the main approaches, tools, and best practices for internationalizing Kotlin applications.



Why is i18n important in Kotlin?

Kotlin, being a modern language fully compatible with Java, inherits all of Java's localization capabilities but also offers its own unique solutions. Proper internationalization allows you to:

  • Significantly expand your application's audience
  • Improve the user experience for speakers of different languages
  • Comply with the legal requirements of different countries (e.g., regarding currencies or date formats)
  • Simplify the process of adding new languages in the future


Main approaches to i18n in Kotlin

1. Using Resource Bundle (Java-compatible approach)

The most common and simple way is to use standard ResourceBundle and property files (.properties). This method is ideal for console applications and server-side projects in Kotlin.



// messages_en.propertiesgreeting=Hello, {0}!farewell=Goodbye

// messages_ru.propertiesgreeting=Привет, {0}!farewell=До свидания


import java.util.ResourceBundleimport java.text.MessageFormat

fun main() { val bundle = ResourceBundle.getBundle("messages", Locale("ru")) val greeting = MessageFormat.format(bundle.getString("greeting"), "Мир") println(greeting) // Выведет: Привет, Мир! println(bundle.getString("farewell")) // Выведет: До свидания}


2. Kotlin-specific approach with extension functions

Kotlin allows you to create a more concise and type-safe API for working with localization using extension functions and delegated properties.



import java.util.*import kotlin.properties.ReadOnlyPropertyimport kotlin.reflect.KProperty

class I18n(private val baseName: String) { private val bundle: ResourceBundle get() = ResourceBundle.getBundle(baseName) operator fun provideDelegate( thisRef: Any?, prop: KProperty<*> ): ReadOnlyProperty { return ReadOnlyProperty { _, _ -> bundle.getString(prop.name) } }}

object Strings { val i18n = I18n("messages") val greeting by i18n val farewell by i18n}

fun main() { // Автоматически использует локаль системы println(Strings.greeting) // Выведет соответствующее значение из файла свойств println(Strings.farewell)}


Tools for localization in Kotlin

1. Kotlin Multiplatform (KMP) and expect/actual

For multiplatform projects, Kotlin offers a powerful expect/actual mechanism, allowing you to declare a common API for i18n and implement it separately for each platform.



// В общем коде (commonMain)expect class PlatformStringResources {    fun getString(key: String, vararg args: Any?): String}

// В Android (androidMain)actual class PlatformStringResources { private val context: Context = // получаем контекст actual fun getString(key: String, vararg args: Any?): String { val resId = context.resources.getIdentifier(key, "string", context.packageName) return context.getString(resId, *args) }}

// В iOS (iosMain)actual class PlatformStringResources { actual fun getString(key: String, vararg args: Any?): Str

Recommendations