Respondo создавался в Дубае, и этот факт повлиял на продукт сильнее любого решения по дорожной карте. Одна очередь поддержки здесь может нести клиента, пишущего по-арабски, другого — по-английски, третьего — на хинди, а четвёртого — на урду, и часто в пределах одного часа. Никогда не существовало версии этого продукта, которая относилась бы к одному языку как к языку по умолчанию, а к остальным — как к переводам. Тридцать с лишним языков, включая языки с письмом справа налево, должны были стать фундаментом, а не слоем, добавленным позже.

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

Перевод — это не понимание

Соблазнительная архитектура — это конвейер: взять входящее сообщение, прогнать его через API перевода на английский, обработать английскими моделями, сгенерировать английский ответ, перевести обратно. Это дёшево, это быстро собрать — и это проваливается ровно в тех ситуациях, из которых состоит клиентская поддержка.

Клиентские разговоры плотно насыщены контекстом, который общий перевод сглаживает. Сленг, идиомы, регистры вежливости и предметная терминология — всё это стачивается в оборот туда-обратно. Классический пример — одно слово с расхождением в значении: клиент, спрашивающий про «return» в контексте розницы, хочет узнать о возврате товара; то же слово в финансовом контексте — про доходность вложений. Схема «перевести — обработать — перевести» теряет нить, потому что к моменту, когда английская модель это видит, разрешающий неоднозначность контекст уже искорёжен.

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

Когда интерфейс переворачивается

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

Поддержка арабского и иврита — это не вопрос перевода строк. Переворачивается вся раскладка. Текст выравнивается по правому краю. Порядок чтения идёт справа налево, а значит, зеркалятся визуальный поток разговора, положение кнопки «назад», направление, куда должна указывать стрелка. Дизайн, построенный с зашитыми в фиксированные позиции допущениями «слева направо», не переносится на RTL — он ломается.

Тонкость в том, что переворачивается не всё. Это ловушка, в которую попадают команды, когда открывают для себя CSS-свойство direction и думают, что дело сделано.

  • Раскладка, выравнивание текста и порядок чтения зеркалятся. Боковая панель, что слева в английском, в арабском место справа.
  • Иконки с направлением наследуют переворот. Стрелка «ответить» или шеврон «далее» должны указывать в другую сторону, потому что их смысл — направленный.
  • Контент, по природе своей идущий слева направо, не переворачивается. Номера телефонов, названия брендов латиницей, фрагменты кода и URL читаются слева направо независимо от окружающего языка. Зеркальте их — и вы создали бессмыслицу.

Сделать это правильно вручную, компонент за компонентом, по всему продукту — ровно та задача, которую невозможно удержать согласованной по мере роста продукта. Поэтому мы не делали это вручную.

На ограничениях, а не на позициях

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

Компонент на позициях говорит: «эта подпись стоит в 16 пикселях от левого края». Эта инструкция неверна в тот же миг, как раскладка переворачивается. Компонент на ограничениях говорит: «эта подпись стоит в начале строки, 16 пикселей отступа перед началом контента». Теперь «начало» автоматически разрешается в левый край в английском и в правый — в арабском, и одно и то же определение компонента рендерится корректно в обоих направлениях без единого условия.

Мы опёрлись на собственные логические свойства браузера, чтобы это выразить, — на современный CSS, который мыслит в терминах *start* и *end*, а не *left* и *right*, и в терминах *inline* и *block*, а не горизонтали и вертикали. Компонент, написанный так, не знает и знать не хочет, в каком направлении он рендерится. Направление задаётся однажды, в корне, и каждый компонент под ним адаптируется.

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

Место, чтобы текст дышал

Последний урок — наименее эффектный и чаще всего игнорируемый: длина текста колоссально варьируется между языками, и раскладка, видевшая только английский, треснет под теми, что в неё не влезают.

Одна и та же фраза может оказаться на 30% длиннее в немецком, прийти в совершенно другом наборе символов в китайском, где несколько глифов несут то, на что английскому нужно предложение, или потребовать больше вертикального места под диакритику, что стоит над и под арабским письмом. Кнопка, размеченная под английское слово «Send», обрежет или переполнит содержимое в тот же миг, как в неё попадёт более длинный перевод.

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

Сквозная линия

Каждое из этих решений рифмуется с одной и той же мыслью: многоязычность не может быть функцией, которую добавляешь, потому что допущения одноязычного продукта дотягиваются до модели, до раскладки и до отдельного компонента. Постройте «сначала английский» — и остаток жизни продукта уйдёт на латание мест, где эти допущения протекают. Постройте под тридцать языков с самого начала — и тридцать первый почти бесплатен. То, что мы базируемся там, где наши клиенты говорят на дюжине языков в день, не сделало это сложнее — оно сделало невозможным незаметно сделать это неправильно, а это лучший вид ограничения, под которым можно проектировать.