Spec-Zone.ru › Kotlin 2

Работа с языками с письмом справа налево

Compose Multiplatform поддерживает языки с письмом справа налево (RTL), такие как арабский, иврит и персидский. Фреймворк автоматически обрабатывает большинство требований RTL и при использовании языков с письмом справа налево корректирует макеты, выравнивание и поведение ввода текста в соответствии с настройками локали системы.

Зеркальное отображение макета

Если в системе настроена локаль языка с письмом справа налево, Compose Multiplatform автоматически зеркально отображает большинство компонентов пользовательского интерфейса. Корректировки включают изменение внутренних отступов, выравнивания и положения компонентов:

  • Внутренние и внешние отступы, выравнивание
    Стандартные внутренние отступы и выравнивание меняются на противоположные. Например, в Modifier.padding(start: Dp, top: Dp, end: Dp, bottom: Dp) внутренний отступ start для LTR соответствует левой стороне, а отступ end — правой; в языках RTL start соответствует правой стороне, а end — левой.

  • Выравнивание компонентов
    Для таких элементов пользовательского интерфейса, как текст, элементы навигации и значки, стандартное выравнивание Start в режиме RTL меняется на End.

  • Горизонтально прокручиваемые списки
    В горизонтальных списках меняются на противоположные выравнивание элементов и направление прокрутки.

  • Расположение кнопок
    Типичные шаблоны пользовательского интерфейса, например расположение кнопок Отмена и Подтвердить, адаптируются к требованиям RTL.

Принудительное задание направления макета

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

Чтобы исключить элемент из автоматического зеркального отображения и задать для него определенную ориентацию, используйте LayoutDirection.Rtl или LayoutDirection.Ltr. Чтобы задать направление макета в рамках области видимости, используйте CompositionLocalProvider(): это гарантирует, что направление макета будет применяться ко всем дочерним компонентам композиции.

CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
    Column(modifier = Modifier.fillMaxWidth()) {
        // Components in this block will be laid out left-to-right
        Text("LTR Latin")
        TextField("Hello world\nHello world")
    }
}

Ввод текста в макетах RTL

Compose Multiplatform поддерживает различные сценарии ввода текста в макетах RTL, включая содержимое со смешанным направлением, специальные символы, числа и эмодзи.

При разработке приложения с поддержкой макета RTL учитывайте следующие аспекты. Их тестирование поможет выявить потенциальные проблемы локализации.

Поведение курсора

Курсор должен предсказуемо вести себя в макетах RTL и перемещаться в соответствии с логическим направлением символов. Например:

  • При вводе текста на арабском курсор перемещается справа налево, а при вставке текста LTR — слева направо.

  • Операции выделения, удаления и вставки текста учитывают естественное направление текста.

Двунаправленный текст

Compose Multiplatform использует алгоритм двунаправленного текста Unicode для обработки и отображения двунаправленного текста (BiDi), корректно выравнивая знаки препинания и числа.

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

В следующем тестовом примере содержится текст с латинскими и арабскими буквами, а также их двунаправленное сочетание:

import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import org.jetbrains.compose.ui.tooling.preview.Preview // Arabic text for "Hello World" private val helloWorldArabic = "مرحبا بالعالم" // Bidirectional text private val bidiText = "Hello $helloWorldArabic world" @Composable @Preview fun App() { MaterialTheme { LazyColumn( Modifier .fillMaxWidth() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { item { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { Column(modifier = Modifier.fillMaxWidth()) { Text("Latin and BiDi in LTR") TextField("Hello world") TextField(bidiText) } } } item { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { Column(modifier = Modifier.fillMaxWidth()) { Text("Arabic and BiDi in RTL") TextField(helloWorldArabic) TextField(bidiText) } } } } } } // Wrap function for BasicTextField() to reduce code duplication @Composable internal fun TextField( text: String = "" ) { val state = rememberSaveable { mutableStateOf(text) } BasicTextField( modifier = Modifier .border(1.dp, Color.LightGray, RoundedCornerShape(8.dp)) .padding(8.dp), value = state.value, singleLine = false, onValueChange = { state.value = it }, ) }
BiDi text

Compose Multiplatform также обеспечивает правильное выравнивание и интервалы в сложных случаях BiDi, в том числе при переносе текста на несколько строк и вложении двунаправленного текста.

Числа и эмодзи

Отображение чисел должно соответствовать направлению окружающего текста. Восточно-арабские цифры естественно выравниваются в тексте RTL, а западно-арабские цифры ведут себя как обычно в тексте LTR.

Эмодзи должны адаптироваться к контекстам RTL и LTR, сохраняя правильное выравнивание и интервалы в тексте.

В следующем тестовом примере используются эмодзи, восточно- и западно-арабские цифры, а также двунаправленный текст:

import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import org.jetbrains.compose.ui.tooling.preview.Preview // Arabic text for "Hello World" with emojis private val helloWorldArabic = "مرحبا بالعالم 🌎👋" // Bidirectional text with numbers and emojis private val bidiText = "67890 Hello $helloWorldArabic 🎉" @Composable @Preview fun App() { MaterialTheme { LazyColumn( Modifier .fillMaxWidth() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { item { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { Column(modifier = Modifier.fillMaxWidth()) { TextField("Hello world 👋🌎") TextField("Numbers: 🔢12345") TextField(bidiText) } } } item { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { Column(modifier = Modifier.fillMaxWidth()) { TextField(helloWorldArabic) TextField("الأرقام: 🔢١٢٣٤٥") TextField(bidiText) } } } } } } // Wrap function for BasicTextField() to reduce code duplication @Composable internal fun TextField( text: String = "" ) { val state = rememberSaveable { mutableStateOf(text) } BasicTextField( modifier = Modifier .border(1.dp, Color.LightGray, RoundedCornerShape(8.dp)) .padding(8.dp), value = state.value, singleLine = false, onValueChange = { state.value = it }, ) }
Numbers and emojis

Шрифты для веб-платформ

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

Чтобы предварительно загрузить резервные шрифты, используйте метод FontFamily.Resolver.preload(). Например:

val fontFamilyResolver = LocalFontFamilyResolver.current
val fontsLoaded = remember { mutableStateOf(false) }

if (fontsLoaded.value) {
   app.Content()
}

LaunchedEffect(Unit) {
   val notoEmojisBytes = loadEmojisFontAsBytes()
   val fontFamily = FontFamily(listOf(Font("NotoColorEmoji", notoEmojisBytes)))
   fontFamilyResolver.preload(fontFamily)
   fontsLoaded.value = true
}

Подробные сведения о предварительной загрузке ресурсов для веб-платформ см. в разделе о API предварительной загрузки.

Специальные возможности в макетах RTL

Compose Multiplatform поддерживает специальные возможности для макетов RTL, включая правильное направление и порядок текста для программ экранного доступа, а также обработку жестов.

Программы экранного доступа

Программы экранного доступа автоматически адаптируются к макетам RTL, сохраняя логический порядок чтения для пользователей:

  • Текст RTL читается справа налево, а текст со смешанным направлением — в соответствии со стандартными правилами BiDi.

  • Знаки препинания и числа озвучиваются в правильной последовательности.

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

Навигация с помощью фокуса

Навигация с помощью фокуса в макетах RTL следует зеркально отображенной структуре макета:

  • Фокус перемещается справа налево и сверху вниз, следуя естественному потоку содержимого RTL.

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

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

Подробные сведения о том, как задавать семантику обхода и устанавливать индексы обхода, см. в разделе «Специальные возможности».

Известные проблемы

Мы продолжаем улучшать поддержку языков RTL и планируем устранить следующие известные проблемы:

  • Исправить положение курсора при вводе символов не RTL в макете RTL (CMP-3096)

  • Исправить положение курсора для арабских цифр (CMP-2772)

  • Исправить TextDirection.Content (CMP-2446)

20 февраля 2026 г.
Управление региональными форматамиТесты локализации

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform/compose-rtl.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API