Кастомный виджет Яндекс.Переводчик для сайтов

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Когда-то я предложил свое решение по кастомизации виджета googleTranslate, тема оказалась действительно полезной и актуальна по сей день. Репозиторий с проектом на gitHub набрал немного звезд, а я рад тому, что мои труды не напрасны. И вот недавно мне понадобилось сделать пользовательский выпадающий список с выбором языков, но уже с виджетом яндекс переводчика. Вообще сам по себе виджет вполне устраивал заказчика, но проблема заключается в том что в нем по умолчанию находится более 90 языков и этот список нельзя никак ограничить. Нельзя выставить 2-3 или 5 необходимых вам языков, будут показаны все 90+, но проблема еще и в том, что виджет не адаптивен, он занимает 1221 пиксель в ширину и никак не подстраивается под размер экрана:

В отличии от виджета гугл переводчика, в котором вся разметка находилась в iframe, в яндекс переводчике можно переопределить стили, но это все не то чего хотелось бы...

На сайте, где генерируется виджет есть ссылка на документацию, и конечно же я её начал изучить, но документация на самом деле об API и никакой информации по работе с виджетом не имеет. Я решил написать в тех. поддержку яндекса:

Текст обращения

Здравствуйте. Виджет переводчика, ведет на документацию в которой вообще о виджете не слова. В частности, как для виджета выбрать для перевода не весь список из 80 языков, а например 5, которые необходимы. И как используя виджет запретить переводить определенные слова в html разметке. Например гугл виджет для этого использует класс notranslate и все что в нем не будет переведено.

И довольно быстро получил ответ:

Текст ответа

Здравствуйте, Виталий!

Такой возможности в нашем виджете сейчас нет.

Спасибо за желание сделать Яндекс.Переводчик удобнее! Я передал ваше предложение команде разработки.

И теперь окончательно убедившись, что готового решения нет, я принялся за дело.

Как будет выглядеть пример:

Разметка демо-страницы
<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <title>Пользовательский виджет yatranslate для сайта на чистом js</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <!-- yatranslate -->
        <script src="./js/yatranslate.js"></script>
        <link rel="stylesheet" href="./css/yatranslate.css">
        <!-- END yatranslate -->

    </head>

    <body class="body">

        <div class="lang lang_fixed">
            <div id="ytWidget" style="display: none;"></div>
            <div class="lang__link lang__link_select" data-lang-active>
                <img class="lang__img lang__img_select" src="./images/lang/lang__ru.png" alt="Ru">
            </div>
            <div class="lang__list" data-lang-list>
                <a class="lang__link lang__link_sub" data-ya-lang="ru">
                    <img class="lang__img" src="./images/lang/lang__ru.png" alt="ru">
                </a>
                <a class="lang__link lang__link_sub" data-ya-lang="en">
                    <img class="lang__img" src="./images/lang/lang__en.png" alt="en">
                </a>
                <a class="lang__link lang__link_sub" data-ya-lang="de">
                    <img class="lang__img" src="./images/lang/lang__de.png" alt="de">
                </a>
                <a class="lang__link lang__link_sub" data-ya-lang="zh">
                    <img class="lang__img" src="./images/lang/lang__zh.png" alt="zh">
                </a>
                <a class="lang__link lang__link_sub" data-ya-lang="fr">
                    <img class="lang__img" src="./images/lang/lang__fr.png" alt="fr">
                </a>
            </div>
        </div>

        <section class="content">
            <h1 class="content__title">Автоматический перевод сайта</h1>
            <div class="content__desc">
                <p>Перевод сайта на другие языки при помощи виджета "Яндекс.Переводчик для сайтов"</p>
                <p>Пример настраиваемого виджета</p>
                <p>Hello World!!!</p>
            </div>
        </section>

        <style>
            /* Стили для демонстрации */
            /* Styles for demonstration */
            body {
                display: flex;
                justify-content: center;
                align-items: center;
                min-height: 100vh;
                margin: 0;
                padding: 0;
                font-family: tahoma;
            }

            .content {
                text-align: center;
                margin: auto;
            }

        </style>
    </body>

</html>

Для корректной работы виджета необходимо подключить файлы:

<script src="./js/yatranslate.js"></script>
<link rel="stylesheet" href="./css/yatranslate.css">
Содержимое yatranslate.css
/* lang */

.lang {
    position: relative;
    z-index: 10;
    text-align: center;
    background: rgba(157, 157, 157, 0.3);
    perspective: 700px;
}

.lang_fixed {
    position: fixed;
    right: 20px;
    top: 20px;
}

.lang__link {
    cursor: pointer;
    transition: .3s all;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    flex-shrink: 0;
    box-sizing: border-box;
    text-decoration: none;
    border-radius: 2px;
    padding: 4px;
}

.lang__img {
    width: 30px;
    height: 18px;
    flex-shrink: 0;
    font-size: 10px;
    display: block;
    transition: .3s all;
}

.lang__link_sub:hover {
    filter: drop-shadow(0 0 3px rgb(136, 136, 136)) brightness(130%);
}


.lang__name {
    color: #737b84;
    font-size: 12px;
    line-height: 12px;
    flex-shrink: 0;
    text-transform: uppercase;
}

.lang__link_sub {
    width: 100%;
    height: auto;
    position: relative;
    padding: 0;
    margin-bottom: 2px;
}

.lang__list {
    background: rgba(157, 157, 157, 0.3);
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    width: 100%;
    opacity: 0;
    visibility: hidden;
    transition: .3s all;
    transform: rotateX(-90deg);
    position: absolute;
    left: 0;
    top: 100%;
    z-index: 10;
    line-height: 13px;
    padding: 4px;
    transform-origin: center top;
    box-sizing: border-box;
}

.lang:hover .lang__list {
    opacity: 1;
    visibility: visible;
    transform: rotateX(0);
}

.lang__link_select {
    align-items: flex-start;
    text-align: center;
    font-size: 0;
}
Содержимое yatranslate.js
/*!***************************************************
 * yatranslate.js v1.0.0
 * author: Vitalii P.
 *****************************************************/

const yatranslate = {
    /* Original language */
    lang: "ru",
    /* The language we translate into on the first visit */
    /* Язык, на который переводим при первом посещении */
    // langFirstVisit: 'en',
};

document.addEventListener('DOMContentLoaded', function () {
    // Start
    yaTranslateInit();
})

function yaTranslateInit() {

    if (yatranslate.langFirstVisit && !localStorage.getItem('yt-widget')) {
        /* Если установлен язык перевода для первого посещения и в localStorage нет yt-widget */
        /* If the translation language is installed for the first visit and in localStorage no yt-widget */
        yaTranslateSetLang(yatranslate.langFirstVisit);
    }

    // Подключаем виджет yandex translate
    // Connecting the yandex translate widget
    let script = document.createElement('script');
    script.src = `https://translate.yandex.net/website-widget/v1/widget.js?widgetId=ytWidget&pageLang=${yatranslate.lang}&widgetTheme=light&autoMode=false`;
    document.getElementsByTagName('head')[0].appendChild(script);

    // Получаем и записываем язык на который переводим
    // We get and write down the language into which we translate
    let code = yaTranslateGetCode();

    // Показываем текущий язык в меню
    // Show the current language in the menu
    yaTranslateHtmlHandler(code);

    // Вешаем событие клик на флаги
    // We hang the event click on the flags
    yaTranslateEventHandler('click', '[data-ya-lang]', function (el) {
        yaTranslateSetLang(el.getAttribute('data-ya-lang'));
        // Перезагружаем страницу
        // Reloading the page
        window.location.reload();
    })
}

function yaTranslateSetLang(lang) {
    // Записываем выбранный язык в localStorage объект yt-widget 
    // Writing the selected language to localStorage 
    localStorage.setItem('yt-widget', JSON.stringify({
        "lang": lang,
        "active": true
    }));
}

function yaTranslateGetCode() {
    // Возвращаем язык на который переводим
    // Returning the language to which we are translating
    return (localStorage["yt-widget"] != undefined && JSON.parse(localStorage["yt-widget"]).lang != undefined) ? JSON.parse(localStorage["yt-widget"]).lang : yatranslate.lang;
}

function yaTranslateHtmlHandler(code) {
    // Получаем язык на который переводим и производим необходимые манипуляции с DOM
    // We get the language to which we translate and produce the necessary manipulations with DOM 
    document.querySelector('[data-lang-active]').innerHTML = `<img class="lang__img lang__img_select" src="./images/lang/lang__${code}.png" alt="${code}">`;
    document.querySelector(`[data-ya-lang="${code}"]`).remove();
}

function yaTranslateEventHandler(event, selector, handler) {
    document.addEventListener(event, function (e) {
        let el = e.target.closest(selector);
        if (el) handler(el);
    });
}
Используемые флаги

Логика виджета довольно простая. При выборе языка в локальное хранилище записывается объект с ключем yt-widget. В объекте хранится язык на который будет переведен сайт:

{
	"lang":"en",
	"active":true
}

К локальному хранилищу без проблем можно получить доступ и я применил ту же технику что и с гугл переводчиком. Виджет яндекса прячем, а кликая на свой кастоный флажок с атрибутом data-ya-lang назначаем записаный в нем язык свойству lang и перезагружаем страницу. После перезагрузки страницы язык, который мы сами установили, будет подхвачен виджетом и сайт будет на него переведен. В функции yaTranslateHtmlHandler проводим необходимые манипуляции с разметкой, в моем случае я показываю флаг текущего языка перевода и удаляю его из общего списка. В js каждый этап я разбил на функции и добавил описание, чтобы было легче доработать код под себя.

Репозиторий с проектом на GitHub

Демонстрация

Источник: https://habr.com/ru/post/554982/


Интересные статьи

Интересные статьи

Устраивать конкурсы в инстаграме сейчас модно. И удобно. Инстаграм предоставляет достаточно обширный API, который позволяет делать практически всё, что может сделать обычный пользователь ручками.
Существует традиция, долго и дорого разрабатывать интернет-магазин. :-) Лакировать все детали, придумывать, внедрять и полировать «фишечки» и делать это все до открытия магазина.
Создать аккордеон, faq, спойлер и подобное, можно при помощи Div и JavaScript. Но лучше: Details и Summary Поддерживается всеми современными браузерами и это семантически правильно оформ...
Если вы последние лет десять следите за обновлениями «коробочной версии» Битрикса (не 24), то давно уже заметили, что обновляется только модуль магазина и его окружение. Все остальные модули как ...
Тема статьи навеяна результатами наблюдений за методикой создания шаблонов различными разработчиками, чьи проекты попадали мне на поддержку. Порой разобраться в, казалось бы, такой простой сущности ка...