Альтернативний спосіб локалізації веб-сайтів: мутилюючий контент CDN

Вступ
Більшість веб-розробників стикалося з завданням перекладу веб-сайту на кілька мов. Місія це досить проста, і рішення, як правило, відноситься до рутини. Упевнений, що багато хто погодиться з твердженням, що локалізація – це нудна, некреативна частина проекту.

У цій статті я хотів би винести на обговорення альтернативну модель перекладу веб-сайтів. Якщо спробувати описати принцип в одному реченні, то це: CDN, який переводить контент між користувачем і оригінальним джерелом.

Потреба в перекладах
Сумніваюся, що користь від багатомовності ресурсу варто доводити, але, тим не менш, присвячую цьому один маленький параграф.

Будь-який Інтернет-сайт доступний трьом мільярдам користувачів на планеті за замовчуванням – просто тому, що ваш сайт в Інтернеті. Якщо ви щось продаєте на сайті, то простим додаванням мови фактично ви виходите на новий ринок. Як мінімум, ви захочете мати версію на місцевому мовою (мовою території, де ви ведете бізнес) та англійську версію, адже англійська мова – це половина Інтернет-контенту за даними W3Techs.

Існуючі способи
Файли з перекладами
Варіанти є різні – від спеціальних форматів начебто GNU gettext, до простих текстових файлів, які ваш поточний framework може використовувати. Результат приблизно однаковий: в момент виведення тексту викликається функція, яка перевірить наявність перекладу у словнику.

Приклад на PHP:

// gettext:
echo _("Привіт, світ!");

// Фреймворк Laravel 5
echo trans('common.hello_world');

Плюси способи:

  • Перевірений десятиліттями метод (читай звичний);
  • Можливість досить просто віддавати окремі файли стороннім перекладачам;
  • Маленьке вплив на код.
Мінуси способу:

  • Як правило відсутня можливість внесення негайних змін;
  • gettext-словники потрібно компілювати, а кінцеві файли коммиттить в репозиторій;
  • Щодо незручне і повільне управління текстами, чим більше проект, тим більше файлів і заплутаніше ієрархія;
  • Немає стандартних механізмів для роботи над перекладами командою перекладачів;
  • Як правило, використовується дві схеми паралельно – переклади для backend і переклади для frontend (JavaScript);
  • Час від часу в текстах для переказів з'являються HTML-теги, тому що програмістам було незручно їх висмикувати.
Переклади в базі даних
На відміну від першого способу, переклади зберігаються в базі даних проекту, що дозволяє вносити коригування на ходу. Як правило, розробники проекту роблять для адміністраторів панель керування перекладами, на що йде додатковий час.

Плюси способи:

  • Легше організувати роботу команд;
  • Можливість внесення негайних змін.
Мінуси способу:

  • Складніше віддавати розділи на переклад стороннім перекладачам;
  • Frontend тексти переводяться все ще окремо від backend текстів;
  • Час від часу в текстах для переказів з'являються HTML-теги, тому що програмістам було незручно їх висмикувати.
Переклад на стороні користувача через JavaScript
Порівняно новий спосіб, пропонується кількома західними стартапами. Від вас потрібно тільки додати посилання на зовнішній JavaScript-файл, який почне підміняти тексти в DOM на основі наданих (або затверджених) заздалегідь переказів.

Плюси способи:

  • Проста установка практично без необхідності програмування;
  • Frontend і backend одночасно переводяться з одного сховища перекладів;
  • В репозиторії текстів не буде HTML-тегів, тому що всі тексти оброблялися post factum з DOM.
Мінуси способу:

  • Пошукові системи не побачать додаткові мови;
  • Поділитися посиланням в соціальних мережах також буде неможливо;
  • Додаткова мережева навантаження (читай ризики затримок) при відкритті сайту.
CDN-перекладач
Власне, те, що виноситься на обговорення в даній статті. А що якщо між користувачем і сайтів вставити «прошарок» – прикордонний сервер, здатний переводити web-контент? Сервіси начебто CloudFlare вже вміють мінімально мутувати клієнтські сторінки — додавати код Google Analytics, наприклад. Якщо зробити крок далі і дозволити користувачеві підміняти тексти і посилання?

Поведінка традиційного CDN:

  1. Клієнт запитує адресу X;
  2. Якщо адреса X є в кеші, то він негайно повертається з кешу;
  3. Якщо адреси X ні в кеші, то прикордонний сервер робить запит на оригінальний сайт, а потім повертає відповідь клієнту. Залежно від заголовків у відповіді оригінального сайту і правил, встановлених на сайті, ресурс X тепер може бути поміщений в кеш.


Поведінка CDN-перекладача:

  1. Клієнт запитує адресу X;
  2. Якщо адреса X є в кеші, то він негайно повертається з кешу як є;
  3. Якщо адреси X ні в кеші, то прикордонний сервер робить запит на оригінальний сайт, а потім застосовує правила мутації – підміняє посилання, замінює перекладені тексти. Залежно від заголовків у відповіді оригінального сайту і правил, встановлених на сайті, ресурс X може бути поміщений в кеш.

Крок 2b в деталях

Отримавши відповідь від оригінального сайту, у прикордонного сервера стоїть завдання, як його перекласти. Запропонована тактика:

  1. Звернути увагу на заголовок Content-type. Якщо значення не входить у список підтримуваних, то не намагатися трансформувати контент;
  2. Звернути увагу на розмір відповіді. Якщо розмір вище встановленої межі – не намагатися трансформувати контент;
  3. Почати парсинг і редагування контенту. Приклад HTML-сторінки: пройтися по всіх вузлів DOM, у яких є текстовий вузол-нащадок. Запросити в репозиторії перекладений текст, передавши параметри вихідний текст і контекст.
  4. Замінивши необхідні шматки контенту, повертаємо результат користувачу. Якщо заголовки і правила дозволяють, то кешуємо результат.
Репозиторій було б логічно реалізувати як окремий RESTful API, а контекст було б зручно задавати начебто URL:selector. Наприклад, хочемо переводити слово «Main page» як «Головна» в будь-якому блоці будь-сторінки починається на /news отримуємо контекст "/news*:head". Світ настільки звик до селекторам в стилі CSS/jQuery, що почати працювати з таким синтаксисом зможе практично будь-розробник з ходу.

Так як межовий сервер звертається за переказом API репозиторію, то цілком логічним стає реалізація SDK і пакетів під популярні мови і фреймворки. Власникам веб-сайтів дається вибір – можна переводити контент через CDN, можна через наш клас в існуючому коді.

Припустимо, що у нас програма на PHP і використовується фреймворк Laravel. Реалізувати legacy-підтримку тривіально – пере-оголошуємо функцію-помічник trans(), замінюємо її своєю реалізацією, де йде пошук не в локальних текстових файлах, а у віддаленому API. Щоб уникнути затримок при кожному запиті, використовуємо кеш або окремий процес-proxy.

Подібним чином, можемо змінювати вміст об'єктів JavaScript, графічні зображення і так далі.

Плюси способи:

  • Повна абстракція програми та перекладів – додаток взагалі не знає про наявність інших мовних версій. Програмісти спокійно працюють над основним продуктом;
  • Backend та frontend-контент перекладається одночасно, використовуючи один репозиторій перекладів;
  • Можна досить просто переводити графічні зображення;
  • Дуже просто запускати перекладені версії сайту на інших (окремих) доменах;
  • Сумісність з будь-яким існуючим сервісом CDN. Можна вибудовувати в ланцюжок;
  • Сумісність з пошуковими системами та соціальними мережами;
  • В репозиторії текстів не буде HTML-тегів, тому що всі тексти оброблялися post factum з DOM;
  • Легко організувати роботу команд.
Мінуси способу:

  • Мені не вдалося знайти, але буду дуже радий допомоги в цьому!
Відео YouTube
Щоб дохідливо пояснити концепцію, я зняв дуже короткий відео-ролик, який показує мій прототип такої системи переказів. Наратив англійською, але я додав російські субтитри.



Реалізація
Я вже перевірив реалізованість і практичність запропонованого методу – написав примітивний варіант прикордонного програми на PHP і Lumen.

Мій метод, отримує від користувача запит і повертає перекладений відповідь:

/**
* @param Request $request
* @param WebClientInterface $crawler
* @param MutatorInterface $mutator
* @param TranslatorInterface $translator
* @return Response
*/
public function show(Request $request, WebClientInterface $crawler, MutatorInterface $mutator, TranslatorInterface $translator)
{
$url = $request->client [origin'] . parse_url($request->url(), PHP_URL_PATH);

$response = $crawler->makeRequest($request->getMethod(), $url);
if ($response === false) abort(502);

$mutator->initWithWebRequest($response);

if ($response->isTranslatable()) $mutator->translateText($translator);
if ($response->isCacheable()) $mutator->cache(60);
$mutator->replaceLinks($request->client [origin'], $request->getSchemeAndHttpHost());

return (new Response($mutator->getBody(), $mutator->getStatusCode()))
->withHeaders($mutator->getHeaders());
}

Упевнений, що багато почнуть сумніватися в парадигмі через навантаження на процесор – адже той же nginx тому і не хоче ніяк мутувати вміст відповідей, що це дуже негативно позначилося на продуктивності. Взагалі, переводити ось так, post factum – це, безумовно, дорожче з точки зору ресурсів.

Мої аргументи тут наступні. Ми спостерігаємо постійне здешевлення IT-ресурсів протягом останніх 5-10 років, настала епоха серверів за 5 доларів – для багатьох сайтів не так вже і страшно трохи підвищити навантаження. По-друге, якщо я все-таки займуся цим проектом, то оптимізація продуктивності буде одним з пріоритетних напрямів. Напевно, можна знайти багато місць для поліпшень!

Висновок
Індустрія завжди рухається в бік оптимізації, підвищення комфорту і економії коштів. Вважаю, що запропонований спосіб локалізації веб-додатків цілком ймовірно може стати основним через 5-10 років.

Більш того, у CDN, як у структури, можуть з'являтися все нові й нові застосування. CloudFlare запропонував світові захист від DDoS, Imgix робить адаптивні картинки на льоту.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.