Why Your Application Needs Internationalization Today
\n\nImagine: you've written a cool Kotlin application — convenient, fast, with a beautiful UI. But all the labels are in Russian. A user from Berlin or Tokyo opens your product and... closes it after 10 seconds. Why? Because they don't understand a word. Internationalization (i18n) is not just "translating buttons," but a bridge between your code and millions of users worldwide.
\n\nIn this article, we'll break down how to properly implement Kotlin internationalization in projects of any scale: from Android applications to server-side services on Ktor. You'll learn how to avoid common mistakes, how to use Kotlin Multiplatform for shared logic, and why "magic strings" are evil.
\n\ni18n Basics in Kotlin: From Simple to Complex
\n\nResource Files: The Foundation of Localization
\n\nThe most reliable way to organize Kotlin application localization is to extract all string literals into separate resource files. In Android Studio, these are standard strings.xml, but for pure Kotlin (backend, desktop), we can use .properties or JSON.
Example for Android:
\n\n// res/values/strings.xml (Russian — default)\n<resources>\n <string name="app_name">My Application</string>\n <string name="welcome_message">Welcome, %s!</string>\n <string name="points">You have %d points</string>\n</resources>\n\n// res/values-en/strings.xml (English)\n<resources>\n <string name="app_name">My App</string>\n <string name="welcome_message">Welcome, %s!</string>\n <string name="points">You have %d points</string>\n</resources>\n\nIn code, we access via context.getString():
val userName = "Alexey"\nval message = context.getString(R.string.welcome_message, userName)\n// Result: "Welcome, Alexey!" (or "Добро пожаловать, Алексей!" in Russian)\n\nNote: we use %s for strings and %d for numbers. Never concatenate strings manually — in Japanese or Arabic, word order may differ.
Working with Plural Forms
\n\nThe Russian language is famous for complex declension rules: 1 балл, 2 балла, 5 баллов. In English, it's simpler: 1 point, 2 points. Kotlin internationalization must account for this.
\n\nIn Android, there is <plurals> for this:
// strings.xml\n<plurals name="points_count">\n <item quantity="one">%d point</item>\n <item quantity="other">%d points</item>\n</plurals>\n\n// In code\nval points = 3\nval text = resources.getQuantityString(R.plurals.points_count, points, points)\n// "3 points"\n\nFor server-side Kotlin, you can use the icu4j library or write your own simple resolver. The main rule: never hardcode texts with numbers.
Internationalization in Kotlin Multiplatform (KMP)
\n\nIf you're writing a cross-platform application in Kotlin Multiplatform, the task becomes more complex. Shared code does not have access to Android resources. The solution is to use a common interface and platform-specific implementations.
\n\nArchitecture for KMP
\n\nCreate an expect class in the common module:
\n\n// commonMain\nexpect class StringProvider {\n fun getString(key: String, vararg args: Any): String\n}\n\n// Usage in shared code\nclass Greeting(private val strings: StringProvider) {\n fun greet(name: String): String {\n return strings.getString("welcome", name)\n }\n}\n\nImplementation for Android:
\n\n