Google Chrome Extensions: быстрый переводчик своими руками

в 8:47, , рубрики: css, development, Google Chrome, Google Extensions, html, java, translate

image

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

Но такие уже есть!

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

А саму статью я решил написать, потому что многую информацию приходилось собирать по частям из дальних уголков интернета и я решил все немного объединить.

Итак, подсаживаемся поближе к камину открываем Notepad++, VS Code или любой другой удобный редактор и начинаем.

1. Подготовка необходимых файлов

Нам понадобятся:

  1. Manifest.json — здесь будет храниться версия нашего расширения, название, список используемых файлов, разрешения.
  2. Popup.html — это лицо нашего расширения, тут мы напишем popup-станичку, которая будет отображаться при клике на иконку нашего расширения
  3. Background.html — это все фоновые процессы нашего расширения.
  4. 4 иконки: 16х16, 36х36, 48х48, 128х128 — это иконка вашего приложения, хром и сам может подгонять иконку под нужный размер, но вы можете выставить разные иконки и в зависимости от этого они будут разными в контекстном меню, возле адресной строки, в меню расширений и т.д.

Сразу небольшая сноска о том, как загружать расширения в gogle chrome:

  1. Сохраняем все файлы расширения в отдельную папку
  2. Открываем Google Chrome -> Опции -> Настройки -> Расширения
  3. Ставим галочку режим разработчика, нажимаем загрузить распакованное расширение.
    image
  4. Указываем путь до папки с расширением, нажимаем ОК

2. Притча о манифесте и popup

И создал программист манифест и увидел программист, что это хорошо.

Наш manifest.json должен выглядеть

примерно так:

{
    "manifest_version": 2,

    "name": "Translator",
    "version": "1.0",

    "icons": {
        "16": "16x16.png",
        "32": "32x32.png",
        "48": "48x48.png",
        "128": "128x128.png"
    },

    "permissions": [
        "http://translate.yandex.net/*",
        "contextMenus"
    ],

    "browser_action": {
        "default_title": "Open translator",
        "default_icon": "48x48.png",
        "default_popup": "popup.html"
    },

    "background": {
    "page": "background.html"
    }
}

Теперь по-порядку:

  • manifest_version — версия нашего манифеста, сейчас актуальна 2 версия.
  • name — название расширения
  • version — версия расширения, тут должны быть только цифры, но в любом формате: 1.0 или 1.0.0.1 или 1.1.2, можно писать как больше нравится.
  • icons — список иконок нашего расширения
  • permissions — разрешения нашего расширения, ссылка даёт доступ к определенному ресурсу, contextMenus даёт доступ к контекстному меню.
  • browser_action: default_title — текст, который будет появляться при наведении мышки на иконку расширения, default_icon — иконка приложения по умолчанию, default_popup — popup-окошко по-умолчанию.
  • background — тут можно подключить фоновую страницу, если она есть или фоновые скрипты.

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

Я решил особенно не заморачиваться с внешним видом и быстренько сверстал более-менее симпатичное окошечко прилично выглядящего переводчика.

popup.html

<!DOCTYPE html>
<html>
<head>
    <script src="jquery.js"></script>
    <script src="popup.js"></script>
    <script src="bootstrap.js"></script>
    <link rel="stylesheet" href="bootstrap.css">
    <link rel="stylesheet" href="bootstrap-theme.css">
    <link rel="stylesheet" href="popup.css">
</head>
<body>
<header>
  <img id="logo" src="mixx.png">
</header>

<div id="wrapper">
    <div class="li">
        <input id="input" class="form-control">
    </div>
    <div class="li" style="margin-bottom: 10px;">
        <button id="btn_submit" type="submit" class="btn btn-default" style="margin-top: 10px;">Перевести</button>
    </div>
</div>

<footer id="options" role="button">
    <label id="result"></label>
</footer>

</body>
</html>

Не знаю, насколько лично ты, читатель, подкован в html, js и css, но на данном уровне я не ставлю целью объяснить тебе принципы этих языков, все что я использую и не поясняю довольно примитивно и легко гуглится.

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

Создадим файл popup.css и добавим немного стилей:

popup.css

body
{
  min-width: 250px;
  margin: 0px;
  font-family: Segoe UI, Arial, sans-serif;
  font-size: 13px;
  background-color: #f8f6f2;
}

header
{
  height: 45px;
  margin-bottom: 40px;
  border-bottom: 1px solid #e1ddd8;
}

#logo
{
  display: block;
  position: relative;
  top: 15px;
  margin: 0px auto;
}

#wrapper
{
  padding: 0px 20px;
}

footer
{
  cursor: pointer;
  padding: 10px 35px;
  border-top: 1px solid #e1ddd8;
}

footer:hover
{
  background: linear-gradient(to bottom, rgba(70, 50, 0, 0.1), rgba(70, 50, 0, 0.1));
}

.li
{
  list-style-type: none;
  border-top: 1px dashed #a5a4a1;
}

label
{
  vertical-align: middle;
}

Теперь наше расширение должно выглядеть примерно так:

image

Теперь можно переходить к самой логике переводчика, создаем файл

popup.js

$(document).ready(function(){

    $('#btn_submit').click(function(e){ /* Функция начнет свою работу, как только пользователь клинет по кнопке с id = "btn_submit" */

        translate($('#input').val());
    });
});


function translate(input) {
    
        var url = "https://translate.yandex.net/api/v1.5/tr.json/translate"; /* Обратите внимание, что ссылка по новому апи яндекса, начиная с версии 1.5 строится иначе, чем раньше */

        var key = "trnsl.1.1.20170124T214153Z.11b2724899c0a9fc.6d5c7e3a02107ce1349d21bbc6dc9dd4a86dc62a"; /* это ключ вашего приложения, который можно получить на официальном сайте яндекса, без него апи работать <b>не будет!</b>  https://tech.yandex.ru/keys/get/?service=trnsl (получение ключа)*/

        var parent = /[а-яёЁ]/i;

        var language = (parent.test(input))? 'ru-en':'en-ru';

        $.getJSON(url, {lang: language, key: key, text: input}, function(res){ /* Ответом мы получаем массив */
            $('#result').text("");
            for (var i in res.text) {
               $('#result').text($('#result').text() + res.text[i] + " ");
            }
        });
}

Сохраним и загрузим наше расширение в хром. Иногда кнопка обновить расширения не помогает и тогда нужно удалить расширение и загрузить заново.

Проверяем работу, у нас должно получится что-то подобное:

image

Вроде уже неплохо постарались, но чего-то не хватает. Добавим реакцию на клавишу Enter.

Добавляем код в popup.js

$("#input").keyup(function(event){
    if(event.keyCode == 13){ /* 13 - виртуальный код клавиши Enter
        $("#btn_submit").click();
    }
});

Проверяем и видим, что теперь можно нажимать enter, а не кликать по кнопке. Но нужно добавить еще минимум одну функцию, которая присутствует в большинстве переводчиков — это копирование переведенного текста в буфер.

Добавляем код в popup.js

var options = document.getElementById("options");
if(options) {
    options.addEventListener("click", function() /* Начинаем ждать клика по панели footer */
  {
    var range = document.createRange(); */ Возвращает новый объект типа Range. */
    var value = document.querySelector("#result");  /* Селектор выбирает элемент с id = "result" */
    range.selectNode(value); /* Выбор элемента */
    window.getSelection().addRange(range);  

    try {  
    var successful = document.execCommand('copy');  
    var msg = successful ? 'successful' : 'unsuccessful';  
    console.log('Copy email command was ' + msg);

  } catch(err) {
    console.log('Oops, unable to copy');  
  }
  window.getSelection().removeAllRanges();
 });

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

Сага о background.js

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

Background.html — фоновая страница и одна из ее возможностей — добавлять пункт в контекстное меню. В сам background.html мы лишь подключаем скрипты, они то нам и нужны.

background.js

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script src="jquery.js"></script>
    <script src="background.js"></script>
</head>

А вот с background.js нам предстоит уже больше повеселиться. Создаем пункт нашего приложения в меню:

Добавляем в background.js

chrome.contextMenus.create({
            'title': 'Перевести с Translator', /* Текст пунтка меню */
            'contexts':['selection'], /* Тип пункта меню */
            'onclick': function() {} /* Запомните это место, вместо этой функции мы будем вставлять код перевода */
}
});

Теперь когда мы перезагрузим расширение и выделив какой-нибудь текст щёлкнем правой кнопкой мыши — мы увидим, что в контекстном меню появился новый пункт:

image

Теперь нужно придумать как переводить этот текст. Сначала я пытался сделать так, чтобы при таком способе перевода открывалось наше popup-окошко и перевод был там, но столкнулся с тем, что Google ограничило возможность открытия окошка только когда пользователь нажмет на иконку. Тогда я взял в руки меч решил сделать перевод в контекстном меню, как это сделано в Яндекс браузере:

image

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

В background.js на место старой пустой функции вставьте эту строчку:

Вставьте код в background.js

translate(info.selectionText);

И отдельно добавьте функцию translate:

Вставьте код в background.js

function translate(input) {
    
        var url = "https://translate.yandex.net/api/v1.5/tr.json/translate";

        var key = "trnsl.1.1.20170124T214153Z.11b2724899c0a9fc.6d5c7e3a02107ce1349d21bbc6dc9dd4a86dc62a";

        var parent = /[а-яёЁ]/i;

        var language = (parent.test(input))? 'ru-en':'en-ru';

        $.getJSON(url, {lang: language, key: key, text: input}, function(res){
                alert(res.text);
        });
}

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

image

Ну вот и все, друзья! Если кто-то подскажет лучший способ реализации перевода с помощью контекстного меню — буду рад услышать.


За информацию о реализации подобных вещей выражаю свою благодарность статьям на Habrahabr и ответам на StackOverflow.

Автор: Noxormy

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js