Pull to refresh

Переводчик сайтов на JS

Reading time4 min
Views9.9K

В данной статье весь код написан на JavaScript (с использованием JQuery).

Использование неофициальных API преследуется законом.

Сегодня хочу рассказать о реализации функции перевода текста на веб-страницах. Предстоит решить сразу несколько проблем:

  • Цена. API как Яндекс.Переводчика, так и Google Translate обходятся недешево, что совершенно не подходит стартап-проектам.

  • Скорость. Перевод должен осуществляться практически мгновенно, чтобы текст было читать максимально комфортно.

  • Возврат. Необходимо предоставить пользователю возможность моментально просматривать оригинальный текст.

  • Легкость. Под легкостью я подразумеваю как минимальную нагрузку на браузер, так и максимально быструю загрузку скрипта.

В первой части статьи описывается решение лишь двух проблем.

Цена

Итак, начнем с цены. Поискав в интернете, оказалось, что раньше практически все API переводчиков были бесплатными, сейчас же у всех есть бесплатный лимит, а далее вовсе не привлекательные цены:

Google Translate
Google Translate
Яндекс.Переводчик
Яндекс.Переводчик
Bing Translator
Bing Translator

Поискав еще немного, я наткнулся на статью о бесплатном API Google Translate, который используется во встроенном в браузер Chrome переводчике, а также на сайте Google Translate. У этого API лишь два ограничения:

  • Скорость. Если беспрерывно посылать запросы, скорость отклика незначительно снизится.

  • Количество символов. Это ограничение обусловлено браузером, который может отправлять в GET запросе максимум 2048 символов (в некоторых источниках 1756).

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

string.match(/.{1,2000}(?=\.)/gi)
// string – исходная строка
// (?=\.) обозначает, что после строки должна быть точка (в примере я разбиваю текст на предложения)
// стоит отметить, что перед отправкой запроса разбиваемую строку стоит обернуть в функцию encodeURI(), которая гарантирует, что вся строка дойдет до сервера

Скорость

Скорость ответа Google API увеличить вряд ли получится, а вот уменьшить задержку между получением ответа и отображением результата можно.

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

Суть такова:

  • при скролле запустить событие;

  • проверить, clientRect каких элементов ниже верхней границы видимой области, но выше нижней;

  • перевести данные элементы.

Запускаем событие перевода при скролле с помощью  document.addEventListener('scroll', startTranslating). Затем определяем, какие элементы находятся в поле видимости пользователя:

function isScrolledIntoView(element) {  
  let pageTop = $(window).scrollTop(); // верхняя граница видимой области
  let pageBottom = pageTop + $(window).height(); // нижняя граница видимой области
  let elementTop = $(element).offset().top; // верхняя граница элемента
  let elementBottom = elementTop + $(element).height(); // нижнаяя граница элемента
  return ((elementTop <= pageBottom) && (elementBottom >= pageTop)); // возвращает true, если хоть один край элемента в поле видимости пользователя, в противном случае – false
}

После отправляем запрос на сервер Google Translate и обрабатываем его:

let translateUrl = "https://translate.googleapis.com/translate_a/single?format=text&client=gtx&sl=" + sl + "&tl=" + tl + "&dt=t&q=" + originalText;
// sl – язык оригинала, tl – язык для перевода, originalText – текст запроса (можно использовать результат string.match(/.{1,2000}(?=\.)/gi))
let translatedText = httpGet(translateUrl);
function httpGet(url) {
  var xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", url, false);
  xmlHttp.send(null);
  return xmlHttp.responseText;
}

Осталось только обработать полученный текст... или нет?

Осталось решить лишь две проблемы:

  • Возврат. Необходимо предоставить пользователю возможность моментально просматривать оригинальный текст.

  • Легкость. Под легкостью я подразумеваю как минимальную нагрузку на браузер, так и максимально быструю загрузку скрипта.

Возврат

Здесь решение очевидно: достаточно загрузить исходный код в переменную, а при клике на кнопку "Показать оригинал" (или что-то в таком роде) отобразить его. Хорошей идеей также будет загружать в переменную уже переведенный текст, ведь если пользователь снова захочет перевести сайт, придется заново посылать запросы.

Что же касается повторного перевода одних и тех же элементов, то это фиксится добавлением и последующей проверкой наличия класса, например, translated.

Легкость

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

Решить проблему со скоростью загрузки скрипта можно двумя способами (они не исключают друг друга):

  • Минифицировать код. С помощью инструмента от 10015.io у меня получилось сократить финальную версию кода почти на 40%:

  • Использовать CDN. Как указано в статье на Хабре:

    Ускоряем фронтенд. Когда много запросов к серверу — это хорошо.Вместо подключения к центральному серверу пользователь может подключиться к серверу CDN, который находится ближе. Таким образом, обмен пакетами пройдёт гораздо быстрее. Это особенно хорошо подходит для статических ресурсов, таких как CSS, JavaScript и изображения, поскольку их легко распространять через CDN.

На этом, пожалуй, и закончу. Надеюсь, прояснил решение основных проблем (иногда даже с примерами кода =D). Если информация оказалось полезной, поделитесь ей с друзьями и коллегами!

Подпишитесь на мой телеграм-канал, чтобы не пропустить новый контент!

Tags:
Hubs:
Total votes 6: ↑2 and ↓4-1
Comments6

Articles