Статьи и новости

Контент на нескольких языках в Yii2. Часть 3. Интеграция словаря с API Yandex Translate

Часть 1
Часть 2
Часть 3

Настало время немного облегчить жизнь контент-менеджера, который будет заниматься заполнением слов в наш словарь. Для этого подключим API сервиса Yandex Translate к нашему сайту. Благо, расширение для этого уже написано.

Изначально планировалось подключение API Google Translate, но несколько отпугнуло то, что они требуют оплату сразу после небольшого тестового периода. У Яндекса есть достаточный лимит, который позволит на первых порах обойтись без дополнительных финансовых вливаний. Впрочем, замена одного провайдера данных на другого в примере, описанном ниже, потребует замены пары строк кода.

Подключим и настроим расширение Yii2 extension to Yandex Translate API

Ссылка на Github

Пройдемся по пунктам документации:

1. Устанавливаем расширение через Composer:

composer require wfstudioru/yii2-yandex-translate-api "dev-master"

Если расширение требует отличную от установленной версию PHP, пользуемся инструкцией.

2. Регистрируем ключ API для своего приложения и копируем его себе.

3. Переходим в файл конфига нашего проекта и включаем установленное расширение:

# /backend/config/main.php

'components' => [
    ...
    'translate' => [
        'class' => 'wfstudioru\translate\Translation',
        'key' => 'INSERT-YOUR-API-KEY', // не забудьте вставить сюда свой ключ!
    ],
    ...
],

У меня данное расширение будет использоваться как во фронтенд части, так и на бэкенде, поэтому я включаю данный блок кода в оба конфига — /backend/config/main.php и /frontend/config/main.php.

На этом общая установка расширения завершена. Самое время им воспользоваться!

Action для перевода

Создадим экшн контроллера, который будет возвращать нам переводы на заданные языки. Для начала напишем самую простую реализацию, которая будет возвращать перевод.

Для начала получим из Яндекса список всех поддерживаемых направлений для перевода:

$url = 'https://translate.yandex.net/api/v1.5/tr.json/getLangs';
$params = array(
    'key' => '<ключ>', // наш секретный ключ
    'ui' => 'en', // код языка
);
$result = file_get_contents($url, false, stream_context_create(array(
    'http' => array(
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => http_build_query($params)
    )
)));

echo $result;

Нас интересует перевод с греческого на русский и с греческого на английский. Составим метод контроллера и сначала распечатаем массив полученных результатов:

# /backend/controllers/DictionaryController.php

public function actionTranslateToNative($string){
    print_r(Yii::$app->translate->translate('el', 'ru', $string));
}

Переводит отлично.

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

# /backend/config/params.php

return [
    ...
    'nativeLanguages' => 'ru, en',
];

Теперь в любом месте нашего кода мы можем вызвать

\Yii::$app->params['nativeLanguages']

для получения списка языков. Аналогично добавим параметр targetLanguage, внутри которого будет код изучаемого языка (в нашем случае el).

Ну а дальше все просто:

# /backend/controllers/DictionaryController.php

public function actionTranslateToNative($string){
    $languages = explode ( ', ', \Yii::$app->params['nativeLanguages'] );
    $targetLanguage = \Yii::$app->params['targetLanguage'];
    $result = [];
    foreach ($languages as $lang):
        $info = Yii::$app->translate->translate($targetLanguage, $lang, $string);
        $result[$lang] = $info['text'][0];
    endforeach;

    return $result;
}

В коде выше мы перекладываем полученные переводы в ассоциативный массив, где ключами является код языка, а значениями — строки с переводом. Учитывая то, что мы будем передавать на вход методу всегда только одну строку, а не массив, мы можем уверенно брать из полученного по API результата первый индекс вложенного массива text.

AJAX-запрос в экшн Yii2

Теперь самое интересное. Добавим в форму кнопку «Перевести», которая никак не будет привязана к ActiveRecord. При клике по ней мы будем брать значение из заполненного input, переводить его, а полученные переводы раскладывать по инпутам для переводов.

Напишем основную функцию, которая будет отправлять AJAX-запрос в экшн для перевода.

# /js/common.js
# не забудьте зарегистрировать файл с кодом в ассетах!

$('#translateToNative').click(function() {
    if( $('#dictionary-word').length ){
        var $word = $('#dictionary-word').val();
        var $container = '#dictionary-translate';
    }

    $.ajax({
        type: 'POST',
        url: '/dictionary/ajax-translate-to-native',
        data: {
            'string': $word,
        },
        success: function(data) {
            insertResponsedData(data, $container);
        }
    });
});

Код получился более-менее универсальным: кнопку с id=»translateToNative» теперь можно добавлять и в другие блоки сайта, и она все так же будет работать. Единственное, что требуется — это написать, откуда забирать данные и куда их класть.

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

function insertResponsedData(data, container){
    $.each(data, function(index, value){
        if(index != 'ru'){
            var suffix = '_' + index;
        } else {
            var suffix = '';
        }

        $(container + suffix).val(value);
    });
}

Как вы могли заметить, несколько изменился и наш экшн:

# /backend/controllers/DictionaryController.php

public function actionAjaxTranslateToNative(){
    if(!\Yii::$app->request->isAjax){
        return false;
    }

    $string = \Yii::$app->request->post('string');

    $languages = explode ( ', ', \Yii::$app->params['nativeLanguages'] );
    $targetLanguage = \Yii::$app->params['targetLanguage'];
    $result = [];

    foreach ($languages as $lang):
        $info = Yii::$app->translate->translate($targetLanguage, $lang, $string);
        $result[$lang] = $info['text'][0];
    endforeach;

    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    return $result;
}

В нем мы стали проверять, что запрос действительно пришел через AJAX, а также изменили формат возвращаемых данных на JSON. Помимо этого, теперь мы получаем данные из массива POST, а не в качестве GET-параметра.

Теперь все действительно работает.

P.S. Вопросы безопасности мы сейчас не трогаем для простоты кода. Если по какому-то куску кода остались вопросы, оставляйте их в комментариях!

 

Обсуждение: 2 комментария
  1. Юрий:

    а добавление слов в пользовательские словари?

    Ответить
    1. coderiter:

      Это фронтовая часть, не админка. Там простейший CRUD с ajax`ом.

      Ответить

Ваш комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *