Pull to refresh

Разделение кода и текста: прототип

Reading time6 min
Views4.9K

Этот пост является продолжением предыдущей публикации Разделение кода и текста: мысли вслух. На этот раз мы пойдем чуть-чуть дальше и представим возможный API, а также сравним рабочий процесс до и после. В качестве примера использованы язык PHP и фреймворк Laravel, но это почти не имеет значения.

Тезис

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

Текущий метод #1

Для начала рассмотрим самый примитивный способ работы с текстами. Этот способ вполне себе подходит для маленьких приложений и сайтов. Текст передается как параметр внутри контроллера:

Текст являются частью шаблона:

Плюсы данного метода:

  • Программисту не надо тратить дополнительное время

  • Очень легко вставлять в текст значения из переменных

Минусы:

  • Тексты разбросаны по репозиторию – что-то находится в классах, что-то в шаблонах. Иногда нужно время, чтобы найти конкретный текст и исправить в нем ошибку

  • Нет возможности перевода на другие языки

Текущий метод #2

Этот метод из документации Laravel, и большинство современных фреймворков, написанных на самых разных языках, имеют что-то подобное. Это примерная копия технологии 1970-1980 годов под названием i18n.

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

Плюсы метода:

  • Теперь можно переводить тексты при необходимости, достаточно перевести файлы, в которых хранятся тексты

  • Тексты вынесены в отдельную папку, что позволяет оптимизировать рабочий процесс (допустим, сделать их отдельным пакетом или репозиторием, чтобы копирайтеры и переводчики могли там делать изменения сами)

Минусы метода:

  • Дополнительная, замедляющая работа для разработчика, причем с ростом приложения она сильно увеличивается. Часто возникает дилемма - использовать существующий текст или создать новый? А вдруг в этом новом месте чуть-чуть другой контекст?

  • Вставлять переменные в текст не так удобно, как в варианте #1

  • Опечатка в идентификаторе текста "поломает" его

  • Работая с текстами копирайтеры и переводчики могут не до конца понимать, в каком месте конкретно он используется, "влезет" ли он в интерфейс и так далее

Текущий метод #3

Этот метод является модификацией предыдущего. Вместо использования идентификаторов, в целях ускорения работы сразу подставляется текст на языке по-умолчанию (например, на языке разработчика):

Плюсы метода:

  • Программист не тратит лишнего времени, как и в варианте #1

  • Можно комфортно переводить продукт на другие языки или локали

Минусы метода:

  • Переменные снова не так удобно вставлять внутрь текста

  • Если программист сделал опечатку или просто написал плоховато, то копирайтеру надо идти в код, чтобы исправить

  • Тексты теперь разнесены по 2 местам – переводы находятся в папке с текстовыми файлами, а тексты на основном языке находятся прямо в коде

  • Все еще не до конца понятно где находится в продукте конкретный текст. Копирайтер или переводчик может выбрать неудачный или неподходящий (по тону, по длине) текст

  • Невозможность иметь разные переводы для одного и того же исходного текста, так как сам текст является уникальным идентификатором

Предлагаемый метод

А теперь рассмотрим предлагаемый данной статьей метод, в котором мы попытаемся объединить плюсы каждого из вышеперечисленных. Предлагается использовать супер-короткую глобальную функцию (наподобие __()) в коде и директиву в файлах шаблонов (допустим, @p):

Или даже вот так:

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

Что же делает глобальная функция или директива p:

  • Подобно функции __() она проверяет в специальных файлах наличие альтернативного текста, которым может быть как перевод на другой язык, так и просто поправленная версия на этом же языке

  • Все отсутствующие тексты записываются в специальной лог, для дальнейшего экспорта

  • Функция использует трассировку языка и статический анализ, чтобы понять откуда был вызов – с какой страницы, какого шаблона и так далее

Таким образом, предполагается, что где-то в процессе CI/CD будет происходить синхронизация  – мы будем извещать внешний API о новых текстах, которые нуждаются в переводе или поправках, включая их точное местоположение, а также загружать в локальные файлы существующие тексты.

Это создает целый ряд плюсов. Рассмотрим их детально.

Преимущество #1

Как известно, многие программисты говорят даже на своих родных языках заметно слабее Шекспира или Пушкина. Тем не менее, с этим подходом разработчики могут не терять лишнее время, а просто писать черновые версии текста:

Вот соответствующее всплывающее сообщение на сайте:

Вроде бы и неплохо, но как-то слишком лаконично и сухо, кто-то даже может обидеться. Копирайтер (ну или какой-то product manager) вскоре увидит в своем интерфейсе, что появился новый текст на сайте и правит его на что-то более дружелюбное или соответствующее брэнду:

Что после следующей синхронизации попадает в интерфейс продукта:

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

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

Преимущество #2

Удобный общий контроль всех текстов в продукте – языка, на котором мы говорим с клиентами. Можно в любую секунду посмотреть как сейчас мы говорим на странице X или в письме Y, влазит ли тайский перевод в кнопку, достаточно ли эмпатии в письме про отмену транзакции:

Если раньше коллеги спрашивали: "а что мы сейчас говорим на такой-то странице?", а мы отвечали: "непомню, вроде вот это", то теперь любой сотрудник может посмотреть любой шаг и предложить поправки или улучшения в пару кликов. Тексты, разбросанные по сотням или тысячам файлов теперь собраны в одном месте и разложены аккуратно по полочкам, с полноценным предпросмотром:

Гипотетический предпросмотр (рендер)
Гипотетический предпросмотр (рендер)

Преимущество #3

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

То есть, имеем локаль ru_RU – русский язык в Российской его версии, и на его основе создаем ru_RU-молодежный .

Преимущество #4

Появляется сильно упрощенная возможность проведения тестов A/B. Как многим давно известно, текст напрямую влияет на уровень конверсий на странице – исправив одно слово, можно замотивировать большую группу пользователей что-то сделать, или наоборот перестать что-то делать. Сейчас на рынке нет прямо уж очень простых способов делать такие тесты. Как правило, разработчики делают что-то вроде:

Имеем два шаблона home.blade.php и home__treatment.blade.php, в первом у нас так называемая control-версия теста, его старый вид, а во втором файле treatment-версия – версия, эффективность которой мы тестируем. Пользователям при посещении страницы выставляется кука или флаг в сессии, которая будет определять какую версию в дальнейшем они будут видеть. Кроме того, аналитика (допустим, Google Analytics) будет также получать этот флаг, чтобы в дальнейшем можно было делать сравнительный анализ.

Представим, что в нашей гипотетический админке появилась еще кнопка "A/B-тест":

Нажали на кнопочку и предоставили вторую версию текста:

А наш сервис аналитики (скажем, Google Analytics) берет правильную метку (control или treatment) либо из нашего приложения, либо из этого сервиса по работе с текстами. Добавили вторую версию текста и через неделю посмотрели как изменился Bounce Rate или количество кликов на странице, оставили одну – ту, что эффективнее. Тривиально.

Преимущество #5

Подключать сервисы переводов (вроде Gengo) или сервисы исправления грамматических ошибок настолько тривиально, что даже не стоит подробно об этом писать ;)

Послесловие

Конечно, тут бы имела место быть какая-то цена миграции – время и силы, затраченные на то, чтобы обернуть все тексты в коде в эти функцию и директиву, но этот момент присутствует и в существующих в индустрии вариантах #2 и #3. Хочется добавить, чтобы преимуществ от подобного сервиса достаточно много даже для моно-языковых продуктов.

Контролировать практику обертки текстов можно через простой webhook, тогда все pull-реквесты будут автоматически проверятся:

Несмотря на то, что я немного поигрался с кодом и проверил, что все вышеизложенное возможно, эта статья обсуждает гипотетический продукт или утилиту. Цель статьи – собрать мнения, ваши мнения.

Пользовались бы Вы такой вещью?

Tags:
Hubs:
+4
Comments20

Articles