В данной статье весь код написан на JavaScript (с использованием JQuery).
Использование неофициальных API преследуется законом.
Сегодня хочу рассказать о реализации функции перевода текста на веб-страницах. Предстоит решить сразу несколько проблем:
Цена. API как Яндекс.Переводчика, так и Google Translate обходятся недешево, что совершенно не подходит стартап-проектам.
Скорость. Перевод должен осуществляться практически мгновенно, чтобы текст было читать максимально комфортно.
Возврат. Необходимо предоставить пользователю возможность моментально просматривать оригинальный текст.
Легкость. Под легкостью я подразумеваю как минимальную нагрузку на браузер, так и максимально быструю загрузку скрипта.
В первой части статьи описывается решение лишь двух проблем.
Цена
Итак, начнем с цены. Поискав в интернете, оказалось, что раньше практически все API переводчиков были бесплатными, сейчас же у всех есть бесплатный лимит, а далее вовсе не привлекательные цены:



Поискав еще немного, я наткнулся на статью о бесплатном 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). Если информация оказалось полезной, поделитесь ей с друзьями и коллегами!
Подпишитесь на мой телеграм-канал, чтобы не пропустить новый контент!