Почему вашему приложению нужна интернационализация уже сегодня
Представьте: вы написали крутое Kotlin-приложение — удобное, быстрое, с красивым UI. Но все надписи в нём на русском. Пользователь из Берлина или Токио открывает ваш продукт и... закрывает через 10 секунд. Почему? Потому что он не понимает ни слова. Интернационализация (i18n) — это не просто «перевод кнопок», а мост между вашим кодом и миллионами пользователей по всему миру.
В этой статье мы разберём, как грамотно внедрить интернационализацию Kotlin в проекты любого масштаба: от Android-приложений до серверных сервисов на Ktor. Вы узнаете, как не допустить типичных ошибок, как использовать Kotlin Multiplatform для общей логики и почему «волшебные строки» — зло.
Основы i18n в Kotlin: от простого к сложному
Ресурсные файлы: фундамент локализации
Самый надёжный способ организовать локализацию Kotlin-приложения — вынести все строковые литералы в отдельные ресурсные файлы. В Android Studio это стандартные strings.xml, но для чистого Kotlin (backend, desktop) мы можем использовать .properties или JSON.
Пример для Android:
// res/values/strings.xml (русский — по умолчанию)
<resources>
<string name="app_name">Моё приложение</string>
<string name="welcome_message">Добро пожаловать, %s!</string>
<string name="points">У вас %d баллов</string>
</resources>
// res/values-en/strings.xml (английский)
<resources>
<string name="app_name">My App</string>
<string name="welcome_message">Welcome, %s!</string>
<string name="points">You have %d points</string>
</resources>
В коде обращаемся через context.getString():
val userName = "Алексей"
val message = context.getString(R.string.welcome_message, userName)
// Результат: "Добро пожаловать, Алексей!" (или "Welcome, Alexey!" на английском)
Обратите внимание: мы используем %s для строк и %d для чисел. Никогда не склеивайте строки вручную — в японском или арабском порядок слов может отличаться.
Работа с плюральными формами (множественное число)
Русский язык славится сложными правилами склонения: 1 балл, 2 балла, 5 баллов. В английском всё проще: 1 point, 2 points. Интернационализация Kotlin обязана это учитывать.
В Android для этого есть <plurals>:
// strings.xml
<plurals name="points_count">
<item quantity="one">%d балл</item>
<item quantity="few">%d балла</item>
<item quantity="many">%d баллов</item>
<item quantity="other">%d баллов</item>
</plurals>
// В коде
val points = 3
val text = resources.getQuantityString(R.plurals.points_count, points, points)
// "3 балла"
Для серверного Kotlin можно использовать библиотеку icu4j или написать свой простой resolver. Главное правило: никогда не хардкодьте тексты с числами.
Интернационализация в Kotlin Multiplatform (KMP)
Если вы пишете кроссплатформенное приложение на Kotlin Multiplatform, задача усложняется. Общий код не имеет доступа к Android-ресурсам. Решение — использовать общий интерфейс и платформенные реализации.
Архитектура для KMP
Создаём expect-класс в common модуле:
// commonMain
expect class StringProvider {
fun getString(key: String, vararg args: Any): String
}
// Использование в общем коде
class Greeting(private val strings: StringProvider) {
fun greet(name: String): String {
return strings.getString("welcome", name)
}
}
Реализация для Android:
// androidMain
actual class StringProvider(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 (через NSLocalizedString):
// iosMain
actual class StringProvider {
actual fun getString(key: String, vararg args: Any): String {
val format = NSLocalizedString(key, comment = "")
return NSString.stringWithFormat(format, args)
}
}
Теперь ваш общий код работает с единым API, а платформенная часть отвечает за загрузку переведённых строк. Это идеальный пример локализации Kotlin-приложения без дублирования бизнес-логики.
Современные инструменты: библиотеки для i18n в Kotlin
Ручная работа с ресурсами — это база, но для больших проектов существуют специализированные библиотеки, которые упрощают интернационализацию Kotlin:
- Kotlin-i18n — лёгкая библиотека для серверных приложений, поддерживает .properties и JSON, автоматическое определение локали из заголовков HTTP.
- Gettext для Kotlin — порт GNU Gettext, удобен, если вы уже используете .po файлы в других проектах.
- PluralKit — специализированная библиотека для работы с плюральными формами в Kotlin, поддерживает 200+ языков.
Пример использования Kotlin-i18n:
// build.gradle.kts
implementation("io.github.xxlabaz:kotlin-i18n:1.2.0")
// Код
val i18n = I18n(Locale("ru"))
val message = i18n["welcome", "Мария"]
// "Добро пожаловать, Мария!"
Если вы работаете с Kotlin для backend (Ktor, Spring), обязательно настройте middleware для автоматического определения языка пользователя по заголовку Accept-Language.
Практические советы: как не провалить локализацию
1. Избегайте конкатенации строк
Плохо:
val text = "Привет, " + userName + "! У тебя " + points + " баллов."
Хорошо:
val text = getString(R.string.profile_info, userName, points)
2. Учитывайте направление текста (RTL)
Арабский, иврит и фарси пишутся справа налево. В Android используйте android:layoutDirection="locale" и тестируйте