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

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

Комментарии (6)


  1. yarkov
    01.09.2022 16:06

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

    А можно узнать зачем это делать в 2022 году?


    1. 12rbah
      01.09.2022 16:13
      +2

      Наверное еще за XMLHttpRequest() попросят пояснить


    1. povProgramming Автор
      01.09.2022 16:14

      Я лишь начинающий программист, в статье описал решение заинтересовавшей меня проблемы. В 2022 году достаточно много людей имеют старое устройство/ПО, которое не имеет встроенный переводчик, из-за чего у меня и возникла идея реализации переводчика на сайте. Во всяком случае спасибо за комментарий, буду исправляться :)


      1. 12rbah
        01.09.2022 16:25
        +2

        Я лишь начинающий программист, в статье описал решение заинтересовавшей меня проблемы.

        Честно говоря, в статье больше рекламы, чем полезной информации.

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

        Если честно то вы почти ничего не пояснили, вы просто показали как сделать запрос к апи через XHR. Если вы пишите про полезный софт, то хотя бы стоит дать ссылку на гитхаб или хотя бы возможность попробовать софт.

        Не подумайте, что я сильно критикую, просто смысла в такой статье нет, т.к. она недоработана.

        P.S. Если вы не пишите +/- хорошие статьи, то за ссылку на тг могут накидать минусов в карму.


  1. AlexanderMarginal
    01.09.2022 20:08
    +1

    1. А зачем через api google с фронта, если можно отдавать на фронт уже переведенный контент?

    2. Зачем в 2022 вам понадобился jQuery и XMLHttpRequest ?

    3. Зачем минифицировать js на каком-то левом сайте который неизвестно что вам по факту отдаст на выходе (в том числе возможно и какого-то зловреда), когда можно использовать для этих целей например webpack?

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


  1. Bigata
    03.09.2022 13:01

    Всё равно автора следует похвалить автора за попытку. Ну велосипед, ну старые решения, но работает. Может за исключением минимизации кода.