вырезаем из 17го спринта описание локализации на примере emoji mixer

This commit is contained in:
andrew mayer
2025-06-21 16:29:05 +04:00
parent d9a2f25252
commit 2bcb40e7c7
4 changed files with 79 additions and 92 deletions
@@ -1,10 +1,10 @@
Прежде чем переводить приложение на новые языки, его нужно подготовить в коде. Откройте проект `EmojiMixer` — в этом уроке он понадобится вам для практики!
# Интернационализация
# Интернационализация
Текст, который вы используете для заголовков экранов, лейблов, кнопок и алертов – это *статические строки*.
Статические строки — фиксированный текст, который не меняется в процессе работы приложения. Чтобы пользователь смог прочитать текст на понятном для себя языке, нам надо найти эти строки и разместить их в специальных файлах локализации.
Статические строки — фиксированный текст, который не меняется в процессе работы приложения. Чтобы пользователь смог прочитать текст на понятном для себя языке, нам надо найти эти строки и разместить их в специальных файлах локализации.
> Относитесь к тексту, который видит пользователь, как к ресурсу — такому же, как картинки, цвета или шрифты. Если для них есть специальные папки и каталоги, то и для текста должны существовать такие хранилища. Так вы сможете подключить любой новый язык с наименьшими трудозатратами.
@@ -14,16 +14,16 @@
Их несколько:
- внутри кода — статические строки, конкатенация (сложение) строк и интерполированные
- Info.plist — настройки приложения
- в файлах Interface Builder (.xib, .storybord)
- Info.plist — настройки приложения
- в файлах Interface Builder (.xib, .storyboard)
А ещё есть текст, написанный на картинках, но про его локализацию поговорим отдельно.
Кнопка
Понятно!
Прежде чем приступать к интернационализации приложения, надо отделить все статические строки от вёрстки и разместить их в специальном файле для локализации.
Внимательно просмотрите на [макеты `EmojiMixer`](https://www.figma.com/design/tfuJs9k2StXOzn1pf5BY8c/Emoji-Mixer?node-id=0-1&p=f&t=5G18lvTAXczS90D5-0), экраны и вью, найдите использованные строки.
Прежде чем приступать к интернационализации приложения, надо отделить все статические строки от вёрстки и разместить их в специальном файле для локализации.
Внимательно просмотрите на `EmojiMixer`, экраны и вью, найдите использованные строки (у нас всего одна строка "Delete All" для кнопки в NavigationBar).
Кнопка
Далее
@@ -44,21 +44,18 @@
`"ключ" = "локализованное значение";`
В качестве ключа обычно используют английское словосочетание, описывающее назначение строки. Давайте составим такой файл для проекта `EmojiMixer`:
В качестве ключа обычно используют английское словосочетание, описывающее назначение строки. Давайте составим такой файл для проекта `EmojiMixer`:
```
"emptyState.title" = "Что будем отслеживать?";
"delete" = "Удалить";
"delete.confirmation" = "Уверены что хотите удалить трекер?";
"cancel" = "Отменить";
```swift
"delete_all" = "Удалить всё";
```
> Обратите внимание: кавычки нужны, только если вы используете символ пробела в ключе. В остальных случаях их можно опускать.
> Обратите внимание: кавычки нужны, только если вы используете символ пробела в ключе. В остальных случаях их можно опускать.
Итак, мы подготовили базовый файл: строки, полученные из него, будут видны всем пользователям — при условии, что для этих строк не добавлен соответствующий язык. Поэтому очень важно, чтобы в строках оказались фразы на самых популярных языках (например, на английском и на французском).
**Кнопка**
А что произойдёт, если пользователю нужно выбрать язык, который не поддерживается приложением?
А что произойдёт, если пользователю нужно выбрать язык, который не поддерживается приложением?
В таком случае iOS по умолчанию использует базовый язык. Но даже если ваше приложение поддерживает язык, для которого локализована не каждая строка, у Apple будет решение!
@@ -109,7 +106,7 @@
- `key`, ключ перевода `Localizable.strings` — используется для поиска строки в файле;
- `comment`, комментарий — используется, чтобы предоставлять дополнительную информацию переводчикам – например, местоположение строки в элементе, контекст строки в приложении и так далее;
- `tableName` — нужен для указания файла с локализованными данными, если тот отличается от файла `Localizable.strings`;
- `bundle` — позволяет выбирать пакеты ресурсов, из которых надо извлечь строку; если этот параметр не указан, по умолчанию используется главный пакет приложения;
@@ -123,27 +120,27 @@
Кнопка
Понятно!
Давайте теперь попробуем получить такую функцию для ключа "emptyState.title":
Давайте теперь попробуем получить такую функцию для ключа "delete_all":
```swift
let emptyStateText = NSLocalizedString("emptyState.title", comment: "Text displayed on empty state")
```swift
let deleteAllText = NSLocalizedString("delete_all", comment: "Text displayed on delete all button")
```
Полученную строку можно установить в свойство `text` у UILabel, например:
```swift
let emptyStateText = NSLocalizedString("emptyState.title", comment: "Text displayed on empty state")
emptyStateLabel.text = emptyStateText
```swift
let deleteAllText = NSLocalizedString("delete_all", comment: "Text displayed on delete all button")
deleteAllLabel.text = deleteAllText
```
> Обновите текстовые элементы в приложении `EmojiMixer` самостоятельно.
> Обновите текстовые элементы в приложении `EmojiMixer` самостоятельно.
Отлично! А теперь давайте научимся запускать приложение для разных локалей, чтобы проверить работу локализации!
Отлично! А теперь давайте научимся запускать приложение для разных локалей, чтобы проверить работу локализации!
Кнопка
Давайте!
![Иллюстрация](./img/3-change-locale.png)
![Иллюстрация](./img/3-change-locale.png)
1. В верхней панели управления проектом нажмите на имя таргета вашего приложения (`EmojiMixer`).
@@ -153,27 +150,25 @@ emptyStateLabel.text = emptyStateText
4. В верхней части окна перейдите на вкладку "Options".
5. В пункте "App Language" выберите язык, на котором хотите тестировать локализацию приложения из списка.
5. В пункте "App Language" выберите язык, на котором хотите тестировать локализацию приложения из списка.
Заметим, что выбранная настройка изменит язык *только* для приложения и не повлияет на язык операционной системы симулятора. Закройте окно редактирования схемы и запустите проект на симуляторе, используя `Cmd + R`.
Вот так можно поменять настройки локали устройства, чтобы переключаться не только между языками, но и регионами (для этого нужно изменить соседнее поле `Region`).
Вот так можно поменять настройки локали устройства, чтобы переключаться не только между языками, но и регионами (для этого нужно изменить соседнее поле `Region`).
> Обратите внимание: изменения в этом файле меняют файл проекта `<AppName>.xcscheme`. Но любые изменения для тестирования НЕ нужно добавлять в git-репозиторий!
![Иллюстрация](./img/4-localized-app.png)
# Процесс локализации
# Процесс локализации
Мы рассмотрели, как локализуются строки на небольшом приложении, где текстовых ресурсов немного. Но в международных приложениях текстовых элементов и их состояний могут быть тысячи, а языковых локалей — десятки! Сейчас мы вынесли строки для локализации, перевели их в онлайн-переводчике и руками добавили новые языки в приложение. В больших продуктах разработчики сами не переводят строки и ничего не добавляют руками — для этого в каждой команде выделен отдельный человек, или даже целая команда локализации, которая управляет этим процессом.
Xcode позволяет разделить разработку и перевод приложения, чтобы эти процессы могли развиваться параллельно.
Сначала идёт интернационализация, то есть вы пишите код так, чтобы можно было делегировать работу над переводами другой команде. На этом шаге мы определяем текстовые элементы для локализации и верстаем экраны по определённым правилам.
Сначала идёт интернационализация, то есть вы пишите код так, чтобы можно было делегировать работу над переводами другой команде. На этом шаге мы определяем текстовые элементы для локализации и верстаем экраны по определённым правилам.
> С этого момента вы можете заниматься тестированием, даже если переводов ещё нет. Для тестирования в Xcode существуют *псевдолокализации*, которые помогают тестировать приложения в различных локале-зависимых условиях. Когда будете готовы локализовать приложение, попробуйте экспортировать локализируемый текст с использованием стандартных форматов файлов и отправить его команде локализации для перевода на несколько языков. Этот процесс мы рассмотрим в следующих уроках.
Пока вы ждёте переводов текста, можно продолжить разработку приложения и дополнительно выполнить самостоятельные шаги по локализации — например, добавить аудио- и графические файлы в свой проект. Когда переводы будут готовы, импортируйте локализацию в проект и тщательно протестируйте своё приложение, на *каждом* поддерживаемом языке и регионе.
Пока вы ждёте переводов текста, можно продолжить разработку приложения и дополнительно выполнить самостоятельные шаги по локализации — например, добавить аудио- и графические файлы в свой проект. Когда переводы будут готовы, импортируйте локализацию в проект и тщательно протестируйте своё приложение, на *каждом* поддерживаемом языке и регионе.
Xcode поддерживает инкрементальную локализацию (ГЛОССАРИЙ: В разработке программного обеспечения термин «инкремент» часто относится к небольшому, но существенному улучшению или изменению, которое применяется к проекту или продукту.) вашего проекта. То есть вы можете добавлять новые переводы частями, поэтапно:
@@ -200,7 +195,7 @@ Xcode поддерживает инкрементальную локализа
В идеале нужно было бы протестировать переводы всех языков с вышеуказанными характеристиками, но это потребует очень много усилий. К счастью, Xcode предлагает инструмент для решения и этой задачи.
# Псевдолокализация
# Псевдолокализация
Как упоминалось выше, в Xcode добавлены специальные псевдоязыки, которые можно использовать для тестирования. Псевдоязык можно выбрать в том же меню "App Language" при редактировании схемы приложения.
@@ -5,20 +5,20 @@
Для начала давайте посмотрим, как настройки устройства влияют на то, как приложение будет обходиться с датами и измерениями.
Откройте в iPhone или на симуляторе `Настройки -> Основные -> Язык и регион`. В самом низу экрана вы увидите стандарты форматов для выбранной локали. По умолчанию iPhone сам выбирает настройки для языка и региона, чтобы пользователям не пришлось об этом думать. Здесь вы можете увидеть настройки календаря, температуры, системы измерений, форматы дат, чисел и даже какой день недели должен быть первым в календаре.
Откройте в iPhone или на симуляторе `Настройки -> Основные -> Язык и регион`. В самом низу экрана вы увидите стандарты форматов для выбранной локали. По умолчанию iPhone сам выбирает настройки для языка и региона, чтобы пользователям не пришлось об этом думать. Здесь вы можете увидеть настройки календаря, температуры, системы измерений, форматы дат, чисел и даже какой день недели должен быть первым в календаре.
> Когда мы говорим про настройки какой-либо локали, то имеем в виду общий случай – базовые настройки. Никто не запрещает вашим пользователям изменять их по-своему, даже если это будет нестандартно для региона. Просто помните, что если человек переедет в другую страну, ему будет удобнее использовать соответствующую комбинацию этих настроек.
Вы можете поменять настройки на этом экране, чтобы посмотреть, как другие приложения учитывают их в своём интерфейсе или чтобы протестировать своё приложение.
![Иллюстрация](./img/17-region-language-settings.png)
![Иллюстрация](./img/17-region-language-settings.png)
Итак, мы узнали, что форматы дат, чисел и валют могут отличаться в зависимости от настроек локали пользователя. Важно, чтобы наше приложение было понятным для пользователя, поэтому такие данные нужно корректно сконвертировать для каждой локали.
Кнопка
А как предусмотреть всё-вообще-всё?
К счастью, перебирать все варианты и изучать особенности каждого региона не нужно — у Apple для этого есть специальные *форматеры*.
К счастью, перебирать все варианты и изучать особенности каждого региона не нужно — у Apple для этого есть специальные *форматеры*.
Пользователь (как и вы сейчас) может поменять настройки языка во время работы приложения. Форматеры, которые мы рассмотрим далее, помогут вам корректно манипулировать данными в коде и не загружать голову лишними сценариями: данные будут показываться пользователю так, будто это сам выбрал их как в настройках телефона. Это удобно: когда мы переключаемся между приложениями, они выглядят привычно и предсказуемо. Так формируется бесшовный опыт взаимодействия с платформой. Для правильного форматирования данных мы будем использовать свойство `Locale`.
@@ -52,10 +52,10 @@ let customFormattedDate = customDateFormatter.string(from: Date())
--- КОНЕЦ СКРЫВАШКИ
Этот способ позволит получить для любого языка переведённую дату в строго заданном порядке:
Этот способ позволит получить для любого языка переведённую дату в строго заданном порядке:
- `Пятница, Апрель 19, 2023`
- `Friday, April 19, 2023`
- `Пятница, Апрель 19, 2023`
- `Friday, April 19, 2023`
Приятный бонус от Swift: дата сразу переводится на язык пользователя! Вам не нужно просить кого-то или самим переводить дни недели и месяцы. Так произошло, потому что мы указали форматеру свойство `locale`.
@@ -64,7 +64,7 @@ let customFormattedDate = customDateFormatter.string(from: Date())
Кнопка
Далее
Некоторые форматы записи даты и времени могут неоднозначно прочитываться в разных регионах. Например, по записи `06/09/23` невозможно однозначно определить, использован ли шаблон `dd/mm/yy` или `mm/dd/yy`. Так и пользователям может быть непонятно (или попросту непривычно), что приложение пытается им сказать. Кроме дат, надо помнить о том, что в одних странах привыкли к 12-часовому формату времени, а в других — к 24-часовому. Где-то принято использовать обозначения времени суток AM (ГЛОССАРИЙ: AM — лат. "ante meridiem", «до полудня») и PM (ГЛОССАРИЙ: PM – лат. "post meridiem", «после полудня»). Apple рекомендует избегать всего этого разнообразия и пользоваться заготовленными *пресетами* стилей (ГЛОССАРИЙ: Пресет – набор правил и предустановленных параметров: например, стили для времени и даты у `DateFormatter`). Они учтут все эти сложности за вас:
Некоторые форматы записи даты и времени могут неоднозначно прочитываться в разных регионах. Например, по записи `06/09/23` невозможно однозначно определить, использован ли шаблон `dd/mm/yy` или `mm/dd/yy`. Так и пользователям может быть непонятно (или попросту непривычно), что приложение пытается им сказать. Кроме дат, надо помнить о том, что в одних странах привыкли к 12-часовому формату времени, а в других — к 24-часовому. Где-то принято использовать обозначения времени суток AM (ГЛОССАРИЙ: AM — лат. "ante meridiem", «до полудня») и PM (ГЛОССАРИЙ: PM – лат. "post meridiem", «после полудня»). Apple рекомендует избегать всего этого разнообразия и пользоваться заготовленными *пресетами* стилей (ГЛОССАРИЙ: Пресет – набор правил и предустановленных параметров: например, стили для времени и даты у `DateFormatter`). Они учтут все эти сложности за вас:
```swift
let dateFormatter = DateFormatter()
@@ -72,40 +72,35 @@ dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
dateFormatter.locale = Locale.current
let formattedDate = dateFormatter.string(from: Date())
```
```
В результате получится строка, содержание которой будет отличаться в зависимости от региона и календаря:
`Apr 19, 2023 at 11:03 PM` или `19 апр. 2023 г., 23:03`.
`Apr 19, 2023 at 11:03 PM` или `19 апр. 2023 г., 23:03`.
> Обратите внимание: календари тоже различаются! В разных странах могут по-своему исчислять эры, месяцы и даже количество дней. Например, в Японии новая эра начинается с каждым новым императором. Длина месяца может варьироваться от года к году, а дней может быть от 5 до 31! Всегда проверяйте такие факты и ни в коем случае не пытайтесь полагаться на собственное представление о времени! Это никого ещё к успеху не приводило!
Кнопка
Далее
Теперь давайте доработаем динамические строки в `EmojiMixer`! В нашем макете даты указываются в двух местах:
Продолжим изучать работу со строками.
1. `UILabel` — в заголовке у секций с карточками.
Чтобы дата `07.12.22` не вводила в заблуждение, 12 июля это или 7 декабря, адаптируем её для наших иностранных пользователей.
2. `UIDatePicker` — для выбора даты создания карточки.
![Иллюстрация](./img/18-localize-dates-emoji-mixer.png)
Чтобы дата `07.12.22` не вводила в заблуждение, 12 июля это или 7 декабря, адаптируем её для наших иностранных пользователей.
Создайте форматер в приложении, как показано в примере. Присвойте свойству `text` заголовка отформатированное значение:
Создайте форматер, как показано в примере и распечатайте отформатированное значение:
```swift
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
dateFormatter.locale = .current
dateLabel.text = dateFormatter.string(from: Date())
```
let formattedDate = dateFormatter.string(from: Date())
print(formattedDate)
```
Запустите и сравните полученное отображение с макетом.
Запустите и изучите полученный вывод.
Здесь вы заметите неточность — дата выводится слишком подробно: указано время, а месяц указан не в числовом виде. Чтобы это исправить, откройте документацию Apple [DateFormatter.Style](https://developer.apple.com/documentation/foundation/dateformatter/style) и подберите пресет, похожий на дату в макете.
Здесь вы заметите что дата выводится слишком подробно: указано время, а месяц указан не в числовом виде. Чтобы это исправить, откройте документацию Apple [DateFormatter.Style](https://developer.apple.com/documentation/foundation/dateformatter/style) и подберите пресет, похожий на дату `07.12.22`.
ТАБЛИЧКА: DateFormatter.Style // Дата // Время
@@ -115,18 +110,16 @@ dateLabel.text = dateFormatter.string(from: Date())
`short` // `11/23/37` // `3:30 PM`
`none` // будет пропущено // будет пропущено
В нашем макете дата должна состоять полностью из цифр. Значит, нам подойдёт пресет `short`. Время нам не нужно выводить — возьмём для него пресет `none`:
Дата должна состоять полностью из цифр. Значит, нам подойдёт пресет `short`. Время нам не нужно выводить — возьмём для него пресет `none`:
```
```swift
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .none
```
Запустите проект в разных локалях. Форматер будет выводить числа в привычном для локали порядке, а для арабского даже заменит цифры на восточно-арабские.
![Иллюстрация](./img/19-localized-dates.png)
> При тестировании проекта обратите внимание, что `UIDatePicker` будет самостоятельно менять отображение в зависимости от установленной локали. Специально настраивать `UIDatePicker` не не нужно: Apple уже позаботилась о разработчиках, предоставив нам значение по умолчанию в свойстве [`locale`](https://developer.apple.com/documentation/uikit/uidatepicker/1615995-locale).
> При тестировании проекта Tracker обратите внимание, что `UIDatePicker` будет самостоятельно менять отображение в зависимости от установленной локали. Специально настраивать `UIDatePicker` не не нужно: Apple уже позаботилась о разработчиках, предоставив нам значение по умолчанию в свойстве [`locale`](https://developer.apple.com/documentation/uikit/uidatepicker/1615995-locale).
Для работы с датами Apple также придумали дополнительные форматеры. Предлагаем вам самостоятельно посмотреть в документации примеры с ними:
@@ -136,7 +129,7 @@ dateFormatter.timeStyle = .none
- [RelativeDateTimeFormatter](https://developer.apple.com/documentation/foundation/relativedatetimeformatter) – предлагает локализацию времени относительно момента времени. Например, можно получить такие значения как «завтра», «вчера», или «4 минуты назад», причём полностью переведённые на правильный язык.
- [ISO8601DateFormatter](https://developer.apple.com/documentation/foundation/iso8601dateformatter) — форматер, поддерживающий конвертацию дат в формат стандарта ISO 8601. Его удобно использовать при передаче данных между приложением и сервером.
- [ISO8601DateFormatter](https://developer.apple.com/documentation/foundation/iso8601dateformatter) — форматер, поддерживающий конвертацию дат в формат стандарта ISO 8601. Его удобно использовать при передаче данных между приложением и сервером.
> Обратите внимание: с iOS 15 доступен упрощённый [способ форматирования дат](https://developer.apple.com/documentation/foundation/date/3796312-formatted). Можно обратиться на объекте с датой к методу `formatted()` и использовать те же самые стили, чтобы получить необходимый формат. В этом уроке мы рассматриваем общеупотребимые варианты, которые подойдут как для новых, так и для более старых версий iOS. Познакомиться с новым API мы также предлагаем вам самостоятельно.
@@ -1,32 +1,33 @@
# Локализация изображений
В этом уроке мы поговорим о том, какие ситуации требуют от нас локализации изображений в iOS-приложении и как это реализовать в проекте.
# Адаптация изображений для Right-to-Left-языков
## Адаптация изображений для Right-to-Left-языков
Вы уже видели, как меняется приложение, если поменять направление чтения с LTR на RTL в зависимости от региона. Это также наиболее частая причина для адаптации изображения в зависимости от той или иной локали.
Вы уже видели, как меняется приложение, если поменять направление чтения с LTR на RTL в зависимости от региона. Это также наиболее частая причина для адаптации изображения в зависимости от той или иной локали.
Давайте рассмотрим это на примере иконки в `EmojiMixer`, расположенной внутри карточки с эмоджи. Добавьте в Asset-каталог иконку c закладкой (в нашем примере она выглядит как красный треугольник):
> Для экспериментов, описанных в этом уроке, вы можете создать новый пустой проект в Xcode. Добавьте в него любое изображение, чтобы применять на практике рассматриваемые инструменты.
![Иллюстрация](./img/7-localize-images-add-bookmark.png)
Давайте рассмотрим это на примере изображения, которое вы добавили в ваш проект.
Добавим в ячейку `UIImageView` элемент и зафиксируем положение «верхний правый угол»:
Добавим на экран `UIImageView` и зафиксируем положение в верхнем правом углу. Для этого в коде вашего ViewController'а можно использовать следующий код:
```swift
contentView.addSubview(markImageView)
markImageView.translatesAutoresizingMaskIntoConstraints = false
// Предполагается, что imageView уже создан, например, на сториборде или программно
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
markImageView.topAnchor.constraint(equalTo: contentView.topAnchor),
markImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
markImageView.heightAnchor.constraint(equalToConstant: 44),
markImageView.widthAnchor.constraint(equalTo: markImageView.heightAnchor),
imageView.topAnchor.constraint(equalTo: view.topAnchor),
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
imageView.heightAnchor.constraint(equalToConstant: 100),
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor),
])
```
Протестируем приложение для RTL языка (можно выбрать ранее добавленный арабский либо псевдо-RTL, как мы упоминали в предыдущем уроке).
Протестируем приложение для RTL языка (можно выбрать ранее добавленный арабский либо псевдо-RTL, как мы упоминали в предыдущем уроке).
Теперь приложение зеркально отобразило интерфейс (как и положение иконки), но саму иконку оставило в том виде, в каком мы её добавляли в каталог.
![Иллюстрация](./img/8-localize-images.png)
Теперь приложение зеркально отобразило интерфейс (как и положение иконки), но саму картинку оставило в том виде, в каком мы её добавляли в каталог.
Конечно, можно было бы добавить отзеркаленную версию картинки и программно перебрать поддерживаемые RTL-языки, чтобы выставить картинку. Но Xcode позволяет это сделать без единой строчки кода!
@@ -37,7 +38,7 @@ NSLayoutConstraint.activate([
![Иллюстрация](./img/9-asset-catalog.png)
Давайте посмотрим, какие значения предлагает Xcode:
Давайте посмотрим, какие значения предлагает Xcode:
- `Fixed` — стандартное значение, которое указывает, что изображение будет использовано «как есть» для любого направления чтения. Используйте это свойство для иллюстраций или изображений, которые хорошо смотрятся без отзеркаливания — аватарки, фотографии, иконки социальных сетей или логотипы компаний.
@@ -47,9 +48,9 @@ NSLayoutConstraint.activate([
- `Both` — Xcode предложит вам добавить две версии изображения для одного asset'а и будет использовать соответствующее изображение для LTR- и RTL-языков. Такое может пригодиться, если вам надо не просто отобразить картинку зеркально, а полностью её заменить.
> Выберите нашу иконку в Asset Catalog. В окне инспектора атрибутов установите значение "Direction" на "Left to Right, Mirrors". Запустите приложение, чтобы убедиться, что закладка отзеркалилась.
> Выберите ваше изображение в Asset Catalog. В окне инспектора атрибутов установите значение "Direction" на "Left to Right, Mirrors". Запустите приложение, чтобы убедиться, что изображение отзеркалилось.
# Поддержка локализованных изображений
## Поддержка локализованных изображений
Кроме настройки отражений изображения, Xcode также позволяет выбирать разные изображения для каждого языка (точно так же, как это делается со строками). Давайте рассмотрим примеры, когда это необходимо делать:
@@ -73,25 +74,25 @@ NSLayoutConstraint.activate([
3. Перетащите локализованное изображение или изображения в соответствующие поля для выбранных языков.
В качестве примера для арабского языка мы заменили цвет иконки для закладки:
В качестве примера для арабского языка мы можем заменить цвет изображения:
![Иллюстрация](./img/10-localize-images.png)
![Иллюстрация](./img/10-localize-images.png)
> Точно так же, как для изображений, вы можете сделать локализованные цвета в ассет-каталоге: алогоритм добавления локализации очень похож.
> Точно так же, как для изображений, вы можете сделать локализованные цвета в ассет-каталоге: алгоритм добавления локализации очень похож.
Кнопка
Далее
Вместо того, чтобы добавлять новую картинку, перекрашенную в другой цвет, мы могли бы завести отдельные цвета для иконки закладки: красный и фиолетовый. Для этого понадобится:
Вместо того, чтобы добавлять новую картинку, перекрашенную в другой цвет, мы могли бы завести отдельные цвета для нашего изображения: например, красный и фиолетовый. Для этого понадобится:
1. Настроить изображение в Asset-каталоге, выбрать свойство `Render As "Template Image"`.
2. Воспользоваться свойством `tintColor` у `UIImageView`.
3. Установить цвет из ассета с помощью инициализатора с названием ассета `UIColor(named: "markColor")`.
3. Установить цвет из ассета с помощью инициализатора с названием ассета `UIColor(named: "iconColor")`.
Этот способ сэкономит вашему приложению память: вам не придётся добавлять ещё одно изображение, ведь дополнительный цвет сохранится в текстовом формате. Однако для изображений более сложных по цвету рекомендуем воспользоваться предыдущим способом.
Этот способ сэкономит вашему приложению память: вам не придётся добавлять ещё одно изображение, ведь дополнительный цвет сохранится в текстовом формате. Однако для изображений более сложных по цвету рекомендуем воспользоваться предыдущим способом.
# Подведём итоги
## Подведём итоги
В этом уроке мы рассмотрели, как в Xcode добавляются локализованные ассеты, а также разобрали ситуации, когда нам это может пригодиться. В следующем уроке разберём нюансы вёрстки.
В этом уроке мы рассмотрели, как в Xcode добавляются локализованные ассеты, а также разобрали ситуации, когда нам это может пригодиться. В следующем уроке разберём нюансы вёрстки.
@@ -6,7 +6,7 @@
![Иллюстрация](./imge/../img/bad-localized-app.png)
# Правила вёрстки
# Правила вёрстки
При добавлении локализации в первую очередь нужно учитывать то, что размер текста перестанет быть фиксированным. Теперь он будет зависеть от длины слов в предложениях, а также от того, насколько точным будет перевод для интерфейса. Переведённый текст может оказаться гораздо длиннее, чем тот, который вы использовали в макетах на языке оригинала.
@@ -24,13 +24,13 @@
# Semantic Content Attribute
Кроме anchor'ов Auto Layout, нам также доступно свойство [`Semantic Content Attribute`](https://developer.apple.com/documentation/uikit/uiview/1622461-semanticcontentattribute). Аналогично свойству `Direction`, это свойство помогает зафиксировать отображение для LTR и RTL-языков.
Кроме anchor'ов Auto Layout, нам также доступно свойство [`Semantic Content Attribute`](https://developer.apple.com/documentation/uikit/uiview/1622461-semanticcontentattribute). Аналогично свойству `Direction`, это свойство помогает зафиксировать отображение для LTR и RTL-языков.
Чтобы найти `Semantic Content Attribute` для элемента интерфейса в Interface Builder, откройте в правой боковой панели Xcode раздел "Attributes Inspector" и найдите поле "Semantic". В коде для наследников UIView будет доступно свойство `semanticContentAttribute`.
По умолчанию там задано значение `Unspecified` — это значит, что элемент может иметь зеркальное отображение для RTL-языка. Но иногда нам нужно зафиксировать, что в этом случае пригодится именно `Force Left-to-Right` (или `Force Right-to-Left`) — тогда элемент всегда будет иметь LTR-ориентацию (или RTL), даже если язык системы по умолчанию имеет RTL-направление чтения.
Также вы можете запретить переворачивать изображения или тексты, содержащие брендинговое название: Apple и на арабском будет Apple.
Также вы можете запретить переворачивать изображения или тексты, содержащие брендинговое название: Apple и на арабском будет Apple.
> Давайте разберём это на примере с тестовым полем. В RTL-языках символы при печати будут появляться справа от каретки. Для ввода данных в общепринятых стандартах такое поведение следует переопределить на LTR. Так, независимо от языка, номер телефона во всех странах принято вводить слева направо.
@@ -45,8 +45,6 @@
Если ваш дизайн-макет предусматривает горизонтальное выравнивание элементов, вы можете ориентироваться на значение `userInterfaceLayoutDirection`, чтобы изменить отображение вручную (например, коллекцию с уменьшением при скролле элементов). Чтобы определить точку для анимированного уменьшения элемента, ориентируйтесь на вид отображения в приложении.
![Иллюстрация](./img/12-layout.png)
Если ваше приложение содержит анимации, которые зависят от направления языка (например, анимация перехода между экранами или анимация перемещения элементов), вам также может понадобиться определить направление языка и в соответствии с этим скорректировать направление анимации.
# Подведём итоги
@@ -55,7 +53,7 @@
Чтобы поддерживать RTL-вёрстку с разных сторон:
1. Чаще используйте `leading-trailing` констрейнты в своей вёрстке для учёта RTL-языков.
1. Чаще используйте `leading-trailing` констрейнты в своей вёрстке для учёта RTL-языков.
2. Явно задавайте свойство `Semantic Content Attribute` для более тонкой настройки отзеркаливания элементов.
3. Чтобы определить актуальное направление интерфейса, используйте значение `UIUserInterfaceLayoutDirection`.