Упрощаем локализацию iOS-приложения со String Catalogs

Выход продукта на новые рынки сбыта — это деньги. Чем лучше ты знаешь своего клиента, тем вероятнее ты их сможешь заработать. Это правило справедливо и в обратную сторону: клиент будет более охотно пользоваться твоим продуктом, если он может разговаривать с ним на одном языке.

Сегодня я расскажу о том, как можно в значительной мере облегчить и усовершенствовать процесс перевода iOS-приложения на другие языки. Языки, разумеется,  человеческие: от Swift мы отказываться не будем.

Для локализации iOS-приложения мы привыкли использовать файлы двух разных форматов:

Плюрализация? Не, не слышал

Такой вариант рекомендуется избегатьСм. «Автоплюрализация» для более элегантного решения

Такой вариант рекомендуется избегать
См. «Автоплюрализация» для более элегантного решения

Плюрализация — это перевод слова во множественное число в сочетании со значением этого числа:

Например,  в английском языке имеет значение лишь то,  единица перед нами или любое другое значение:  1 document,  но 2 documents, 3 documents и 11 documents;

А в русском будет аж 3 возможных варианта: 1 документ,  3 документа,  11 документов.

К сожалению, человеческий фактор — штука беспощадная. При локализации iOS-приложения разработчики нередко попадают в неприятные ситуации. Например:

  • Сохраняются «мертвые» ключи для тех строк, что вышли из употребления и не встречаются в коде;

  • Иногда строки во время разработки могут добавляться в код без ключей, поэтому часть контента в приложении остается без перевода на другие языки. В результате и консистентность теряется, и пользовательский опыт страдает;

  • Ключи были добавлены, но при разработке были временно взяты значения с другого языка и далее остались без замены на корректные. Работа переводчика часто следует после того,  как был написан код, поэтому упустить такую деталь легко.

Многие годы приходилось с этими сложностями мириться. К счастью, в 2023 году Apple представила String Catalogs.

Strings Catalogs (*.xcstrings) — это единый формат файла локализации iOS-приложения, более продвинутый и удобный, чем прежние  *.strings и .stringsdict. Когда-нибудь он вытеснит их полностью, а пока все форматы при желании могут уживаться в одном проекте. Впрочем, отказаться от старых сущностей можно сразу, препятствий никаких нет.

Под капотом

Собственно каталог строк — файл *.xcstrings — это JSON:

{
  "sourceLanguage": "en",
  "strings": {
    "common.yes": {
      "extractionState": "stale",
      "localizations": {
        "ru": {
          "stringUnit": {
            "state": "translated",
            "value": "Да"
          }
        },
        "en": {
          "stringUnit": {
            "state": "translated",
            "value": "Yes"
          }
        }
      }
    }
  },
  "version": "1.0"
}

Преимущества

На этапе сборки все строки будут автоматически отслеживаться и синхронизироваться. Больше не потребуется вручную добавлять новые ключи локализации, обновлять изменившиеся или удалять неиспользуемые.

Процесс локализации станет более комфортным и приятным, а разработчик будет избавлен от нудных рутинных операций.

Строки собираются отовсюду:

  • в представлениях SwiftUI;

  • в сторибордах и файлах .xib;

  • в файлах кода Swift, C и Objective-C;

  • во фразах App Shortcut;

  • в файлах Info.plist и Localizable.strings.

Какие бывают статусы

В каталогах содержатся не только сами автоматически синхронизируемые строки,  но и статусы для них, что позволяет уменьшить рутину, связанную с ручным ревью локализации и поддержкой. Статусы STALE и NEEDS REVIEW будут особенно полезными для ранее добавленных в проект строк.

Статус

Цвет

Значение

STALE

Желтый

Строка не используется в коде. Возможно,  строка подлежит удалению

NEW

Красный

Строка не имеет перевода для языка в каталоге. Необходимо добавить перевод

NEEDS REVIEW

Оранжевый

Изменился контекст использования строки. Возможно,  потребуется ревью со стороны переводчика

TRANSLATED

Зеленый

Со строкой не было обнаружено проблем

Немного практики

Добавляем новый каталог

  1. В окне добавления нового файла в проект выбираем тип String Catalog;

  2. Далее нажимаем Next и Create.

Xcode отобразит пустой каталог без содержимого. Чтобы в каталоге появились строки,  просто соберите проект.

Мигрируем на каталоги

Готовы перенести ключи на новый формат?  Все очень просто:

  1. Щелкаем правой кнопкой мыши по файлу Localizable.strings;

  2. Выбираем «Migrate to String Catalog…»;

  3. В новом окне выбираем файлы локализации;

  4. Жмем на Migrate.

Остальное Xcode выполнит самостоятельно. В конце работы Вы увидите каталог всех строк с перемещенным содержимым.

Разные строки для различных устройств

Ранее для адаптации iOS-приложения под watchOS приходилось заводить отдельные ключи для сокращенных надписей, чтобы умещать текст на маленьком экране. 

Теперь появилась возможность выставлять семью устройств для одной и той же строки. Принцип аналогичен передаче форм множественного числа в локализации,  когда используется единый ключ для разных форм.

Другой пример:  в локализациях на iOS встречается слово «коснитесь» (tap),  которое совершенно не подходит,  к примеру,  для macOS без сенсорного экрана. В ней коснуться чего-либо невозможно, зато можно «щелкнуть» (click) мышью. Вместо того,  чтобы заводить на каждую систему свой ключ,  мы просто делаем чуть разные формы для iOS и macOS:

Конкретизируем локализацию под Mac

Конкретизируем локализацию под Mac

Радуемся результату. Строка будет отображаться по-разному на разных устройствах

Радуемся результату. Строка будет отображаться по-разному на разных устройствах

Автоплюрализация

String Catalogs умеют автоматически распознавать плюральные строки — строки, где одно или несколько слов склоняются в зависимости от значения числа.

Сразу попробуем на практике:

  1. Добавим пару строчек кода в ContentView с использованием строки с интерполяцией:

Text("I'm \(happyNumber) years old")

Строка со счастливым числом внутри

Строка со счастливым числом внутри

  1. Собираем проект;

  2. Правой кнопкой мыши щелкаем по новой строке в каталоге;

  3. Выбираем опцию Vary by Plural:

Vary by Plural

Vary by Plural

  1. Задаем единственное и множественное число для английского варианта:

1 year, но 2, 3, 5, 11, 21 years

1 year, но 2, 3, 5, 11, 21 years

  1. Задаем единственное и множественное число для русского варианта:

1 год, но 2 или 3 года и 5 либо 11 лет

1 год, но 2 или 3 года и 5 либо 11 лет

Случаи с десятками вида »21 год»,  »32 года» String Catalogs обрабатывают самостоятельно — по аналогии со *.stringsdict-файлами.

Для каждого выбранного языка каталоги самостоятельно определяют количество и типы вариантов плюрализации. От разработчика требуется самая малость: вписать перевод со строки-оригинала на каждый язык.

Теперь убедимся, что все работает корректно:

Preview — отличный способ проверить что-то на лету

Preview — отличный способ проверить что-то на лету

Необходимо отметить, что возможно плюрализовывать строки более чем с одним аргументом. Процесс локализации будет практически идентичен приведенному выше за исключением одного — на каждый аргумент добавляются переменные:

Переменные подсвечиваются розовым, а аргументы — синим. Меняются динамически и одновременно. Глаза довольны

Переменные подсвечиваются розовым, а аргументы — синим. Меняются динамически и одновременно. Глаза довольны

Результат

Результат

Ручное управление строками

Для некоторых проектов может потребоваться хранение ключей в каталоге независимо от состояния строк в проекте и только с ручным обновлением. Для этой цели предназначена настройка Managed:

Отвязываем строку от сборок и состояния проекта

Отвязываем строку от сборок и состояния проекта

Она отключает автоматические обновления соответствующих строк, но разрешает их редактировать вручную.

Сколько каталогов можно создавать

Для крупных проектов целесообразно разбить все множество строк на несколько каталогов в зависимости от контекста.

Такая возможность имеется. Можно создавать сколько угодно String Catalogs. Достаточно убедиться в наличии tableName для строк с их названиями. Например:

Text("My feed", tableName: "Menu")

Заключение

Переход на новые технологии обычно дается нелегко. Часто нам приходится убеждать команду в повышении минимальной версии iOS, правках архитектуры или же необходимости серьезного рефакторинга кодовой базы ради чего-то свежего и новенького. Тот же SwiftUI для многих команд и проектов все еще остается terra incognita именно по этим причинам.

К счастью, у меня здесь есть для Вас ну очень, прям очень хорошая новость! Прям под конец прочтения статьи оставил.

Для существующих проектов String Catalogs привлекательны тем, что не имеют ограничений:

  • ни по фреймворку (SwiftUI,  UIKit);

  • ни по языку программирования (поддерживается даже Objective-C);

  • ни по минимальной версии iOS.

Так что… если Вы уже хотели завести техническую задачу под данное дело в бэклог, то смело делайте это прямо сейчас. Всего лишь достаточно обновиться на Xcode 15 — самое время,  если Вы еще этого не сделали.

Для внедрения на новый проект String Catalogs полезны тем, что Вам не понадобится мучительно собирать все строки по проекту руками, ведь Xcode «запылесосит» их в каталог за Вас. Также они позволят легко поддерживать их и далее в актуальном состоянии, ну и самое главное — избегать неточностей и ошибок локализации.

Желаю успехов!

© Habrahabr.ru