Используя API переводчика написал для себя простую программу для перевода слов и фраз, и чтобы из любого места работало. Хотел использовать curl, но непонятно почему получал ошибку что такого языка нет.

Теперь вместо скучного, а иногда медленного, а иногда такого ярко-белого нового таба с лишней информацией пишу в терминале trans hello и получаю перевод на русский, а если trans привет — на английский. Разумеется можно вводить и фразы, в кавычках. Работает быстренько.

import javax.net.ssl.HttpsURLConnection;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;

public class YandexTranslate {
	private static int i = 0;
	public static void main(String[] args) throws IOException {
		System.out.println(translate("ru", args[0]));
	}

	private static String translate(String lang, String input) throws IOException {
		String urlStr = "https://translate.yandex.net/api/v1.5/tr.json/translate?key=trnsl.1.1.20150627T071448Z.117dacaac1e63b79.6b1b4bb84635161fcd400dace9fb2220d6f344ef";
		URL urlObj = new URL(urlStr);
		HttpsURLConnection connection = (HttpsURLConnection)urlObj.openConnection();
		connection.setRequestMethod("POST");
		connection.setDoOutput(true);
		DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
		dataOutputStream.writeBytes("text=" + URLEncoder.encode(input, "UTF-8") + "&lang=" + lang);

		InputStream response = connection.getInputStream();
		String json = new java.util.Scanner(response).nextLine();
		int start = json.indexOf("[");
		int end = json.indexOf("]");
		String translated = json.substring(start + 2, end - 1);
		i++;
		if (translated.equals(input) && i < 2) {
			// if return equal of entered text - we need change direction of translation
			return translate("en", input);
		} else return translated;
	}
}


Чтобы перевод работал в любой директории, нужно в /usr/bin положить .class-файл и trans.sh для его вызова:
#!/bin/bash
if [ $# -eq 0 ]
  then
    echo "Enter text for translate"
    exit 1;
fi
java -classpath /usr/bin/ YandexTranslate "$1"

И сделать его исполняемым: sudo chmod +x trans.sh

Если вы вместо перевода начнете получать сообщение о том что ключ кончился, или мало-ли-что — тут можно получить новый кей — вставьте его куда надо в Java-коде, после чего откомпилируйте (javac YandexTranslate.java) и скопируйте с заменой на /usr/bin.

Также этот код доступен на Гитхабе.

Также пользователи Firefox могут воспользоваться моим экстеншеном-переводчиком — он интегрирован в контекстное меню, быстрый-минималистичный и не оказывает влияния на DOM, после установки сразу работает и не требует рестарта браузера. На данный момент единственный Яндекс-переводчик для текущих версий Firefox.

UPD: Такие штуки лучше делать сразу на баше, но сразу у меня не получилось, но после того как bockra показал свой скрипт, я его дописал — чтобы не надо было указывать направление перевода, и можно без ковычек писать сразу несколько слов. Так и не смог добиться перевода нескольких слов с амперсантом, но и халера с ним.
#!/bin/bash
#
# simple console util for translation text to any language using Yandex Translate API
# use: trans 'call me, baby
# will return translation of a phrase to ru or en language
# more example at http://api.yandex.ru/translate/
#

input=${@//[&]/%26}
link='https://translate.yandex.net/api/v1.5/tr.json/translate?key=trnsl.1.1.20150627T071448Z.117dacaac1e63b79.6b1b4bb84635161fcd400dace9fb2220d6f344ef&lang='
function translate() {
	translated=$(curl -s "$link$key&lang=$1&text=$input" | awk -F'"' {' print $10 '})
}

translate "ru"
if [ "$translated" == "$input" ]
	then
		translate "en"
fi
echo $translated

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


  1. tobilko
    26.06.2015 23:26

    что-то новенькое, спасибо

    а почему яндекс, а не гугл?


    1. 007 Автор
      26.06.2015 23:59
      +1

      Мне кажется en-ru/ru-en переводится лучше Яндексом, да и пинг наверное до сервера Яндекса меньше :)


      1. Pryada
        27.06.2015 12:24

        Если кому-то интересно, то с китайского на русский лучше всего (по моим тестам) переводит Бинг.
        Хотелось бы поставить Яндекс на второе место, но у него есть фатальные ошибки перевода (в моих кусках перевода), о которых я давно сообщил в тех поддержку, мне ответили, но до сих пор нет изменений. Наверное через какое-то время Яндекс будет на втором месте, а на третьем останется Гугл.


      1. kloppspb
        27.06.2015 13:14

        Основная проблема Яндеса в том, что что сервис перевода и сервис словаря — это два отдельных сервиса. Сравните, например, выдачу Яндекса и Гугла на «fox» или «Quick brown fox jumps over the lazy dog». У Гугла побогаче будет:

        ato.su/resizer/i/5/1/97a28d88.png
        ato.su/resizer/i/6/7/57cd1b6f.png

        У Яндекса нечто подобное можно получить только при обращении к словарям, да и то только в первом случае («fox»).


    1. drwatson32
      28.06.2015 17:52

      Я раньше пользовался api от Google, а вчера обнаружил, что Google деньги берет за Translate.
      А на месте автора я бы API Key бы убрал.
      И проще наверное было создать javascript bookmark в Хроме.


      1. kloppspb
        28.06.2015 18:55

        Не берут, просто другой URL нужен. Всё это уже пережёвывалось здесь: habrahabr.ru/post/256063


        1. drwatson32
          28.06.2015 19:30
          +1

          Берут, берут.
          https://cloud.google.com/translate/v2/pricing
          А то что вы привели, это не вызов API, а неправомерное использование чужого сервиса, на мой взгляд.
          Для дома поиграться может и сойдет, но в прод не вариант.


          1. kloppspb
            28.06.2015 20:00

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

            В любом случае пока у Яндекса не объединены словари и перевод, гугловский вариант куда полезней. Если б там можно было платить за фактическое количество знаков — почему бы и не? Но к миллиону даже близко не подберусь :)


  1. EuroElessar
    27.06.2015 05:21
    +13

    <зануда>

    • Составлять url слиянием строк, серьезно?
    • Разбирать json руками, серьезно?
    • Делать бесконечный рекурсивный вызов, серьезно?
    • Игнорировать все аргументы командной строки, кроме первого, серьезно?
    • Выкладывать это на Хабр, серьезно?
    </зануда>


    1. 007 Автор
      27.06.2015 08:41

      1) Ведь в таком маленьком коде проще слиять строки, разве нет? Каковы ваши аргументы против слияния?
      2) Разбирать json руками — опять же — зачем усложнять?
      3) Рекурсия не бесконечна, вызов самого себя происходит только если вернулось то же что ввел пользователь. Можно было конечно сразу определять язык, но это было бы чуть больше кода и все-равно два запроса к серверу.
      4) Какие еще нужны аргументы командной строки?
      5) Почему выложил на Хабр — сам искал такое решение, в том числе и на Хабре.


      1. EuroElessar
        27.06.2015 08:58
        +9

        1) Ведь в таком маленьком коде проще слиять строки, разве нет? Каковы ваши аргументы против слияния?

        trans "R&D"

        Ожидание — «НИОКР», реальность — «Р».
        2) Разбирать json руками — опять же — зачем усложнять?

        JSON экранирует ряд символов, например ", \n и т.д., поэтому нужен нормальный парсер.
        3) Рекурсия не бесконечна, вызов самого себя происходит только если вернулось то же что ввел пользователь. Можно было конечно сразу определять язык, но это было бы чуть больше кода и все-равно два запроса к серверу.

        trans "123"

        4) Какие еще нужны аргументы командной строки?

        Joiner.on(" ").join(args)

        5) Почему выложил на Хабр — сам искал такое решение, в том числе и на Хабре.

        Заранее извиняюсь, но на Хабр имеет смысл выкладывать нетривиальные решения, а не суповой набор из багов уровня средней школы.


        1. 007 Автор
          27.06.2015 10:53

          ок, спасибо за обратную связь, обновил:
          1) Теперь можно делать trans «R&D»
          2) Я не буду в консоли вводить что-то со слешем для перевода — не хочу превращать .class-файл в .jar-файл используя например gson для парсинга.
          3) Теперь вызов метода самого себя происходит лишь единожды.
          4) Joiner.on(" ").join(args) не понимаю, что это?
          5) Мне очень стыдно, но уже 13 человек добавили в избранное :)


          1. EuroElessar
            27.06.2015 11:43
            +1

            2) Я не буду в консоли вводить что-то со слешем для перевода — не хочу превращать .class-файл в .jar-файл используя например gson для парсинга.

            Замечательный подход, далеко пойдете :)
            3) Теперь вызов метода самого себя происходит лишь единожды.

            private static int i = 0;
            /* ... */
            i++;
            if (translated.equals(input) && i < 2) {
                // if return equal of entered text - we need change direction of translation
                return translate("en", input);
            } else return translated;
            

            А здесь, уважаемые зрители, яркий пример kostyl'-driven development.
            4) Joiner.on(" ").join(args) не понимаю, что это?

            А это возможность делать trans many words without escaping.
            Если быть еще точнее, то это, например, com.google.common.base.Joiner.


  1. bockra
    27.06.2015 11:12
    +4

    А зачем тут джава-то?
    Может не так экранировали ссылку?

    Вот мой помощник в переводе :)

    #!/bin/bash
    #
    # simple console util for translation text to any language using Yandex Translate API
    # use: Translate.sh ru 'call me, baby'
    # will return translation of a phrase to ru language
    # more example at http://api.yandex.ru/translate/
    #
    
    to=$1
    text=$2
    
    link='https://translate.yandex.net/api/v1.5/tr.json/translate?key='
    key='-- key from http://api.yandex.ru/key/keyslist.xml --'
    
    curl -s "$link$key&lang=$to&text=$text" | awk -F'"' {' print $10 '}
    


    1. 007 Автор
      27.06.2015 11:47
      -4

      Когда я пробовал делать 'curl $link' то получал {«code»:501,«message»:«The specified translation direction is not supported»}
      Да, надо было просто в кавычки поставить адрес… Тогда бы и не писал на Яве. Хотя я читал кто-то не любит ставить curl, а jre может быть установлен :)


      1. kloppspb
        27.06.2015 15:35

        >я читал кто-то не любит ставить curl, а jre может быть установлен

        А может и наоборот. Но wget должон быть :) В общем, всё тут, и в комментах особенно: habrahabr.ru/post/256063


        1. grossws
          30.06.2015 05:08

          Это зависит от системы. Иногда есть и curl, и wget, иногда что-то одно, иногда ни того, ни другого.


          1. kloppspb
            30.06.2015 09:42

            А поставить религия не позволяет, ага. Но на java качалки писать и велосипеды изобретать — это запросто :-)


            1. grossws
              30.06.2015 14:06

              Вы меня с автором этой «статьи» не путаете?


              1. kloppspb
                30.06.2015 14:41

                Ну не поставил тег irony, каюсь ;-)


    1. bockra
      27.06.2015 11:54
      +1

      Хотя тест Руслана на «R&D» тоже не прошел :)


      1. kloppspb
        27.06.2015 18:28

        sudo apt-get install gridsite-clients && man urlencode


    1. 007 Автор
      27.06.2015 16:31

      Дописал ваш скрипт и добавил в пост.


  1. ruslanys
    27.06.2015 12:37
    +8

    Во-первых — баян.
    Во-вторых — зачем здесь Ява?! Я, конечно, Java разработчик, обожаю этот язык, но для такой тривиальной задачи такой инструмент — крайне не подходящее решение на мой взгляд. Ребята решали подобную задачу средствами Bash. Ну максимум — Питон, как-никак скриптовый язык, не требующий никакой компиляции.
    В-третьих — крайне неуклюжая, «сырая» реализация. Как уже говорили, работа с JSON, например. Наверное, будет открытием, но в JSR 353 (https://jcp.org/en/jsr/detail?id=353) была введена поддержка JSON парсера. А это значит, что можно и без подключения сторонних библиотек реализовать гармоничное решение. (http://www.oracle.com/technetwork/articles/java/json-1973242.html)

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


  1. MaximChistov
    27.06.2015 22:25
    -1

     String json = new java.util.Scanner(response).nextLine();
            int start = json.indexOf("[");
            int end = json.indexOf("]");
            String translated = json.substring(start + 2, end - 1);
            i++;
            if (translated.equals(input) && i < 2) {
                // if return equal of entered text - we need change direction of translation
                return translate("en", input);
            } else return translated;
    

    Ужас какой )


  1. aNNiMON
    27.06.2015 23:02

    Назовите пост «Яндекс-Перевод в терминале через Java в 30 строк» и часть претензий отпадёт :)


  1. hell0w0rd
    28.06.2015 02:43

    Затронули больную, за последнее время, для меня тему, давно хотел подобное написать. Java нет у меня, зато везде есть node.js.
    github.com/nkt/yandex.translate — быстренько накидал реализацию.


    1. 007 Автор
      28.06.2015 14:15

      yandex-translate hello | say # It's talking!

      У вас она еще и говорит?


      1. hell0w0rd
        28.06.2015 14:32

        Сама программа нет. Но в osx есть программа say (думаю под linux есть аналоги), а оператор | перенаправляет stdout в stdin следующей программы. Таким образом можно воспроизводить переводы.


        1. kloppspb
          28.06.2015 15:27

          А аналогов xsel и notify-send в osx нет? Просто неудобно же вводить слова руками в консоли, и в консоли же получать результат (если не перенаправлять куда-то, конечно).


        1. 007 Автор
          28.06.2015 15:36

          Вы меня вдохновили сделать два скрипта для баша для TTS через Яндекс и Гугл :)

          Теперь пишу в консоли
          tts-y hello world
          или
          tts-g hello world
          И слушаю произношение :)


  1. grossws
    30.06.2015 05:03

    можно без ковычек писать сразу несколько слов. Так и не смог добиться перевода нескольких слов с амперсантом, но и халера с ним.
    Кроме переводчика стоит добавить в арсенал aspell/hunspell. Можно:
    — создавать дочерние процессы с помощью java.lang.Process, получить stdin и stdout и обернуть aspell/hunspell,
    — использовать только первый аргумент (проверять орфографию по одному слову же удобнее),
    — добавить в код константу, соответствующую epoch time через N часов и сравнивать System.currentTimeMillis()/1000 с этой константой и падать, если она оказалась меньше (чтоб периодически перекомпилировать эту обёртку.