Что нужно знать о поддержке RTL-языков в мобильном приложении
Представьте: вы выходите на рынок ОАЭ, запускаете арабскую версию приложения — и получаете шквал негативных отзывов. Меню съехало, кнопки не нажимаются, текст обрезается. Запустив приложение на арабском языке, вы можете столкнуться с тем, что кнопка «Назад» указывает вправо, а слайды приезжают слева. Пользователи привыкли к обратному порядку — и это вызывает когнитивный диссонанс. Без корректной RTL-поддержки даже функционально одинаковое приложение воспринимается как сломанное, что приводит к снижению удержания на 30% (данные наших проектов). Мы адаптировали более 20 проектов под арабский и иврит и знаем все подводные камни. Наша команда готова взять на себя полный аудит и реализацию RTL-поддержки под ключ.
Простая смена локали и установка layoutDirection = rtl — это лишь 20% работы. Остальное — ручная адаптация каждого компонента: иконок, анимаций, навигации, текста и даже жестов (например, свайпы). Вот что на самом деле ломается:
| Компонент | iOS | Android | Flutter | React Native |
|---|---|---|---|---|
| Иконки | SF Symbols с RTL-вариантом работают, но кастомные PNG — нет | autoMirrored="true" для VectorDrawable, BitmapDrawable не зеркалится |
Directionality не влияет на CustomPainter |
I18nManager.isRTL для условного рендеринга |
| Анимации | UIView.animate с абсолютными координатами |
Animator с translationX требует проверки layoutDirection |
SlideTransition с initialOffsetX — ручная логика |
Animated.timing с useNativeDriver не зеркалится |
| Текст | NSTextAlignment.natural зеркалится, .left — нет |
textAlignment="viewStart" для TextView |
textDirection: TextDirection.rtl для Text |
textAlign: 'auto' вместо 'left' |
| Навигация | UINavigationController зеркалит кнопку «назад» автоматически |
ActionBar требует android:supportsRtl="true" |
Navigator автоматически, но кастомные переходы — нет |
ReactNavigation требует ручной настройки |
Наш подход с кастомными флиппинг-трансформами в 2 раза быстрее традиционного переписывания всех экранов под RTL с нуля и сокращает время доработки на 40%. Это позволяет сэкономить 30–50% бюджета по сравнению с полной переработкой. Мы используем автоматизированные тесты для проверки зеркальности, что позволяет выявлять ошибки на ранних этапах и снижать затраты на QA.
Почему стандартное RTL-решение не покрывает все кейсы?
Подробная таблица выше показывает типичные проблемы. Добавим, что на iOS кастомные draw() и Core Graphics требуют conditional flipping, чтобы зеркалировать содержимое. На Android autoMirrored работает только для VectorDrawable, но не для BitmapDrawable. В Flutter Directionality не влияет на CustomPainter, поэтому приходится вручную применять canvas.scale(-1, 1). В React Native важно проверять версию: на Android I18nManager.isRTL работает только в RN >=0.63, иначе нужен forceRTL с перезагрузкой.
Как мы реализуем RTL-поддержку?
-
Аудит. Запускаем приложение на арабской локали через
adb shell setprop persist.sys.locale ar-AE(Android) иSettings → General → Language & Region(iOS Simulator). Это выявляет 80% проблем. Фиксируем артефакты на каждом экране — в среднем 10–15 на приложение из 50 экранов. -
Классификация. Делим проблемы на 4 типа: layout, иконки, текст, анимации. Для каждого типа — свой рецепт исправления. Например, для иконок применяем conditional flipping, для анимаций — замену абсолютных координат на относительные.
-
Правки. На iOS переписываем кастомные
draw()под conditional flipping, используемUIView.appearance(whenContainedInInstancesOf:)для системного наследованияsemanticContentAttribute. На Android заменяемleft/rightнаstart/endв XML и программно черезMarginLayoutParamsCompat. Для Flutter зеркалируемCustomPainterчерезcanvas.scale(-1, 1). Для React Native — проверяемI18nManager.isRTLв каждом компоненте. -
Тестирование. Обязательно на реальных устройствах: Samsung с One UI меняет поведение
VectorDrawable, а на старых версиях iOSUIView.appearanceможет не сработать. Добавляем скриншотные тесты с RTL-локалями в CI. Запускаем на 3–4 физических девайсах, чтобы покрыть 95% кейсов.
Подробнее о тестировании
Используем XCTest с XCUIRemote для симуляции жестов и проверки зеркальности. На Android — Espresso с DeviceLocale для переключения локали. Интегрируем Firebase Test Lab для тестирования на реальных устройствах в облаке.
Какие услуги входят в RTL-адаптацию?
- Полный аудит кода и артефактов на всех экранах
- Исправление layout, иконок, текста, анимаций
- Адаптация кастомных компонентов (Canvas, Core Graphics, CustomPainter)
- Настройка бэкенд-интеграции для передачи RTL-контекста
- Ручное тестирование на 4+ реальных устройствах
- Интеграция RTL-скриншот-тестов в CI/CD
- Документация по поддержке RTL для команды
Сколько времени занимает RTL-доработка на каждой платформе?
| Платформа | Аудит (дни) | Правки (дни) | Тестирование (дни) | Итого |
|---|---|---|---|---|
| iOS | 1–2 | 2–3 | 1 | 4–6 |
| Android | 1–2 | 2–4 | 1 | 4–7 |
| Flutter | 1 | 1–2 | 0.5 | 2–3.5 |
| React Native | 1 | 2–3 | 0.5 | 3–4.5 |
Какие типичные ошибки допускают при RTL-разработке?
- Жёстко заданный
textAlign: 'left'в кастомных компонентах вместо'auto'или'start' -
transform: [{scaleX: -1}]применён к иконке без проверкиI18nManager.isRTL— иконка зеркалируется всегда - Локализация чисел:
١٢٣(eastern arabic numerals) vs123— зависит от контекста отображения, нужно явно задаватьNSLocale/Locale - Бидирекциональный текст (арабский + английское название):
NSAttributedStringс явнымNSWritingDirectionAttributeName, иначе порядок слов ломается
Как закладывать RTL на этапе проектирования?
Лучший способ — использовать start/end вместо left/right с самого начала, избегать абсолютных координат в анимациях и проверять кастомные Drawable на autoMirrored. Если проект уже готов — мы проведём аудит и устраним все несоответствия. Наши инженеры гарантируют корректную работу на арабском и иврите на всех поддерживаемых устройствах с чистым сопровождаемым кодом.
Не дайте вашим пользователям потеряться в зеркальном лабиринте — свяжитесь с нами для консультации по RTL-аудиту. Закажите консультацию — мы рассчитаем сроки и стоимость. Инвестиции окупятся в течение 2-3 месяцев после выхода на рынок.
Apple рекомендует использовать UIView.appearance() для наследования семантических атрибутов; подробнее см. RTL (Right-to-Left) на Wikipedia.







