Почему вашему приложению нужна интернационализация?
Представьте: вы написали крутое iOS-приложение. Оно идеально работает, интерфейс — загляденье, а пользователи из России ставят пять звёзд. Но что если ваш код заговорит по-английски? Или по-китайски? Или по-арабски, где текст читается справа налево?
Интернационализация в Swift — это не просто перевод кнопок. Это архитектурный подход, который позволяет вашему приложению говорить на языке пользователя, уважать его культурные особенности (форматы дат, валюты, единицы измерения) и не ломаться при смене локали.
В этой статье мы разберём, как правильно внедрить i18n (internationalization) в Swift-проект, используя современные инструменты Xcode и лучшие практики. Готовы сделать ваш код гражданином мира? Поехали!
Основы локализации в Swift: от NSLocalizedString до String Catalog
Классический подход: NSLocalizedString
Самый базовый инструмент — макрос NSLocalizedString. Он ищет перевод в файлах .strings и, если не находит, показывает ключ (или дефолтное значение).
let hello = NSLocalizedString("hello_world", comment: "Приветствие на главном экране")
print(hello) // Выведет перевод в зависимости от языка устройства
Комментарий — не просто формальность. Он помогает переводчикам понять контекст: "hello_world" может быть как приветствием, так и названием раздела. Всегда пишите осмысленный comment.
String Catalog — новый стандарт (Xcode 15+)
Забудьте про десятки файлов Localizable.strings. В Xcode 15 появились String Catalogs (.xcstrings). Это единый файл с поддержкой множества языков, плюрализации и контекстных заметок.
Чтобы создать каталог: File → New → File → String Catalog. Добавили ключ — и готово:
// Код остается тем же!
let welcome = NSLocalizedString("welcome_message", comment: "Приветствие для нового пользователя")
// В String Catalog вы просто добавляете переводы для en, ru, ar и т.д.
Плюсы: не нужно синхронизировать файлы, меньше шансов ошибиться с кодировкой, встроенная поддержка плюрализации.
Форматирование чисел и дат: культурный код
Ошибка: жёстко задавать формат даты как "dd.MM.yyyy". В США пишут "MM/dd/yyyy", в Японии — "yyyy年MM月dd日". Swift спасает DateFormatter и NumberFormatter.
Даты, которые не стыдно показать
let date = Date()
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
formatter.locale = Locale.current // Автоматически подстраивается под язык устройства
let localizedDate = formatter.string(from: date)
// Для en: "January 15, 2025"
// Для ru: "15 января 2025 г."
// Для de: "15. Januar 2025"
print(localizedDate)
Никаких dateFormat строк! Используйте .short, .medium, .long — они уже учитывают культурные правила.
Числа и валюты: уважайте запятые и точки
В России число 1234.56 пишется как "1 234,56", а в США — "1,234.56". NumberFormatter знает об этом:
let price = 1234.56
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.locale = Locale.current
let localizedPrice = numberFormatter.string(from: NSNumber(value: price))!
// Для en_US: "$1,234.56"
// Для ru_RU: "1 234,56 ₽"
// Для de_DE: "1.234,56 €"
print(localizedPrice)
Плюрализация: один, два, много — не гадайте
Правило "один — много" работает только в английском. В русском есть "1 минута", "2 минуты", "5 минут". В арабском — шесть форм! String Catalog и NSStringPluralRule решают это элегантно.
В String Catalog вы добавляете ключ, указываете тип "Plural" и заполняете формы:
// В коде:
let minutes = 3
let format = NSLocalizedString("minutes_ago", comment: "Сколько минут назад")
let result = String.localizedStringWithFormat(format, minutes)
// Для minutes=1: "1 минуту назад"
// Для minutes=3: "3 минуты назад"
// Для minutes=10: "10 минут назад"
Важно: в каталоге для русского языка нужно указать one (1, 21, 31...), few (2-4, 22-24...) и many (5-20, 25-30...).
SwiftUI и локализация: красота без боли
В SwiftUI локализация ещё проще. Текстовые метки автоматически ищут переводы, если вы используете инициализатор с LocalizedStringKey:
struct ContentView: View {
var body: some View {
VStack {
Text("hello_world") // Автоматически ищет в String Catalog
Text("Вы вошли как \(userName)") // Поддерживает интерполяцию
}
}
}
Для изображений с альтернативным текстом:
Image("flag")
.accessibilityLabel(Text("flag_description")) // Локализованная подпись
Не забудьте локализовать и accessibilityHint — это улучшит UX для людей с ограничениями.
Практический чек-лист: как не провалить интернационализацию
- Не хардкодьте строки. Каждая строка, которую видит пользователь, должна проходить через
NSLocalizedString. - Используйте String Catalog. Он упрощает плюрализацию и контекстные комментарии.
- Проверяйте RTL-языки. Арабский, иврит — текст идёт справа налево. Используйте
.leadingи.trailingвместо.leftи.right. - Форматируйте данные динамически. Даты, числа, валюты — только через
FormatterсLocale.current. - Не забывайте про Accessibility. Локализуйте подписи для VoiceOver и динамический тип текста.
- Тестируйте на реальных локалях. Смените язык в симуляторе и проверьте, не вылезает ли текст за границы кнопок.
Заключение: ваш код — дипломат
Интернационализация Swift-приложений — это не про "добавить перевод". Это про уважение к пользователю. Когда вы правильно форматируете дату