Привет, Хабрахабр!
Я продолжительное время учу английский и хочется достичь идеала, но этот процесс не быстрый. На данный момент уровень моего английского позволяет мне довольно таки неплохо распознавать разговорную речь, но фильмы, пока, я смотрю всё так же с субтитрами. Даже без них, я уверен, в видео могут попадаться слова, которых я не знаю и хоть общий смысл будет понятен, мне всё равно захочется узнать, что это за слово.


Таким образом при просмотре фильма получается такой порядок действий:


  • смотрим
  • встречаем незнакомое слово
  • переключаемся на браузер, вкладку lingualeo
  • ищем слово, выбираем перевод, добавляем
  • смотрим фильм дальше

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


Начало


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


Первая мысль была проста: качаем весь словарь, регуляркой вытаскиваем весь текст из субтитров, сравниваем, выдаём пачку так называемых неизвестных слов. Но тут меня постигло фиаско. В английском языке есть такое понятие — lemma. Разумеется в моём словаре lingualeo не все слова были в такой форме, совершенно точно не все слова такие в субтитрах. Погуглив я нашёл такую библиотеку, как nltk. Вроде бы выход из положения, для получения lemma нужно было передать аргументом глагол это или существительное. Как разобрать где что? Или придётся написать здоровенный велосипед или...


Неожиданная новость


Просматривая ответы сервера lingualeo я заметил, что в ответе есть lemma. Таким образом мне оставалось лишь сравнить искомое слово с lemma и если они совпадали — это точно то, что мне нужно, иначе — сделать ещё один запрос. Выход найден, можно заняться делом, но есть одно НО — существует ещё такое понятие, как stop words. Это слова, которые обычно игнорируются (don't, a, the, etc.). Эти списки гуглятся, они разных размеров и какой выбрать — непонятно. В расширенных списках, теоретически, могут попадаться такие слова, которые тоже необходимо выучить. А если моей наработкой захочет воспользоваться кто-то другой?


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


Первые шаги


Первая реализация основывалась на пачке json файлов, в которых я хранил текущий словарь пользователя, слова, которые пришли из субтитров с вариантами переводов, stopwords. Для добавления/перебора/игнорирования слов я решил сделать веб-страничку, чтобы наглядно можно было видеть что к чему. Проблема оказалась очевидной, выбранный мною Flask может и можно было научить пагинировать список новых слов (которых может быть из одного фильма и тысяча), но это не стоило тех трудовых затрат и во всём остальном в таком решении были только минусы, нежели плюсы, поэтому я с чистой совестью решил использоваться sqlite с помощью SQLAlchemy.


Примеры кода я не привожу, со всем кодом можно ознакомиться на github (ссылка в конце статьи), я лишь приведу тут логику работы.


Как это работает?


Итак, при первом запуске нужно указать email и пароль, если они корректны, сохраним. Далее выкачиваем/обновляем словарь — он в lingualeo сортируется по дате, что крайне удобно, потому что с каждой новой страницей я сохраняю число добавленных слов в базу. Если оно равно 0, значит слова все сохранены, для уверенности качаем ещё пару страниц, если пусто — всё обновили.


Дальше, если указан текстовый файл, разбираем его. Сравнение со списком stopwords (слова, которые пользователь игнорирует) идёт 2 раза. В момент разбора текстового файла и потом, при получении lemma, если слова изменены. Сделано так, чтобы не насиловать лишний раз сервера :)


Кстати, выгруженный локально словарь можно сохранить в csv для импорта в Anki, если есть такое желание, нужно указать опцию --savecsv.


Для просмотра новых слов нужно запустить flask:


python3 server.py

Открыв localhost:5000 откроется страница со словами. Их можно тут же игнорировать (добавлять в stopwords) или добавлять в активный словарь на Lingualeo. Я добавил ссылку на сохранение csv, если кому-то это нужно, use case: игнорируем ненужные слова, а нужные выгружаем в файл для импорта в тот же Anki. Перевод будет выбран тот, в котором максимум голосов.


Заключение


Исходный код доступен по ссылке на github, если есть какие-то предложения, пожелания — добро пожаловать в комментарии или pullrequests/issues.
Спасибо за внимание :)

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


  1. little-brother
    03.10.2017 23:27
    +1

    Заодно: перевод слов по двойному клику для Firefox/GreaseMonkey, используя LingvoLeo
    // ==UserScript==
    // @name        MyScript
    // @namespace   Translate
    // @description Linvaleo
    // @version     1
    // @grant GM_xmlhttpRequest
    // ==/UserScript==
    (function (window, undefined) {
    	var w = (typeof unsafeWindow != undefined) ? unsafeWindow : window;
    
    	if (w.self != w.top)
    		return;
    	
    	var hint = document.createElement('div');
    	hint.id = 'lingualeo-hint';
    	hint.style.position = 'fixed';
    	hint.style.background = 'white';	
    	hint.style.padding = '20px';
    	hint.style.fontSize = '14pt';
    	hint.style.cursor = 'default';
    	hint.style.border = '1px solid #bbb';
    	hint.style.display = 'none';
    	hint.onmouseleave = () => hint.style.display = 'none';
    	document.body.appendChild(hint);
    	
    	var words = {};
    	
    	function translate (word, callback) {
    		var data = words[word];
    		if (data)
    			return callback(null, data);
    
    		GM_xmlhttpRequest({
    			method: 'GET',
    			url: 'http://lingualeo.com/userdict3/getTranslations?word_value=' + word + '&groupId=&_=' + new Date().getTime(),
    			onload: function(response) { 
    				try {
    					data = JSON.parse(response.responseText).userdict3;
    					data.audio = new Audio(data.sound_url);
    					words[word] = data;
    					callback(null, data);
    				} catch (err)  {
    					callback(err);
    				}
    			}
    		});
    	}	
    	
    	document.ondblclick = function (event) {
    		var selection = window.getSelection();		
    		var word = selection.toString().trim();
    		
    		if (!word)
    			return;		
    		
    		translate(word, function(err, data) {
    			if (err)			
    				return console.error(err);
    			
    			var html = [];
    			if (data.transcription) 
    				html.push('<i>' + data.transcription + '</i>');
    			if (data.translations instanceof Array) 
    				data.translations.forEach((t) => html.push(t.translate_value));
    			hint.innerHTML = html.join('<br>');
    			
    			hint.style.top = event.clientY - 5 + 'px';
    			hint.style.left = event.clientX - 5 + 'px';
    			hint.style.display = 'block';
    			
    			data.audio.play();
    			selection.removeAllRanges();			
    		});
    	  }
    })(window);


  1. pmcode
    04.10.2017 07:27

    Немного не по теме, но может кто-нибудь подскажет десктопную читалку (epub, fb2), в которой есть достойная интеграция со словарем. Пока пользую calibre, но там страница открывается в браузере, а хотелось бы модальности. Ну и при возможности тоже сохранять незнакомые слова, да хоть текстовый файл.

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


    1. kamagan
      04.10.2017 11:12

      FBReader для Android.


  1. bro-dev
    04.10.2017 12:20

    Какие то надуманные проблемы имхо, если вы знаете слово run это не значит что не нужно учить running, тоже самое стоп слова, их тоже нужно знать и не фильтровать. Проще все эти слова по фасту отметить как знаю, и дальше при фильтре других сабов уже не будут попадаются, я для себя так писал прогу.


    1. conformist Автор
      04.10.2017 14:00

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

      если вы знаете слово run это не значит что не нужно учить running

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


  1. Quasar_pro
    04.10.2017 13:55
    +1

    Если вы потратили столько усилий на реализацию такого функционала, я думаю вы зацените этот сервис :) www.hamatata.com
    Есть возможность просмотра практически любого фильма с практически любым языком субтитров. По наведению курсора на слово в субтитрах, видео ставится на паузу, а по клику можно посмотреть перевод с других сервисов и Лео в том числе)


    1. conformist Автор
      04.10.2017 14:03

      Я знаю про Ваш сервис, спасибо, что напомнили. Но разве он позволяет добавлять слова в словарь Лингволео или только просмотр перевода? Если только второе, то вся проблема заключается в том, что мне нужно будет как-то добавить слово в словарь, вручную, чего я и хотел избежать :)


      1. Quasar_pro
        04.10.2017 15:17
        +1

        В этом и вся прелесть, что есть кнопочка «добавить в словарь»)


  1. Goodkat
    04.10.2017 17:41

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


  1. angru
    05.10.2017 00:50

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


    https://bitbucket.org/angru/cutthesub


  1. questor
    06.10.2017 11:19

    Есть мнение, которое озвучивает тот же Лео (которым я активно пользуюсь), которое заключается в том, что для наиболее эффективного развития нужно смотреть видео, 80% слов в котором понятны.

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

    Я правда — не знаю, как правильнее поступать. Но пока я для себя очень чётко различаю, в каком контексте я нахожусь — «обучение языку» или «просмотр по работе» (это тексты, поэтому мне помогает плагин Лео по переводу слова и плагин яндекса по переводу слова) и не всегда в последнем режиме мне так важен точный перевод слова.

    В том же Лео у меня другая беда: после 10к слов в словаре очень сложно вспомнить, какие слова ты уже «изучил» (по терминологии сервиса, т.е. — попали в словарь или не попали) и приходится очень многие слова тыкать и смотреть «ага, тут уже есть галка, это слово я добавлял»). Я им даже писал по этому поводу, но мою проблему сперва не поняли, а потом задвинули в конец очереди. Быстрее самому плагин для браузера (подсвечивать в тексте Лео слова, НЕ добавленные в словарь) написать, чем дожидаться.