見出し画像

「英語学習にプログラミングを活用!」パート❶ - TOEIC単語帳アプリをJavaScriptで自作する! - 「英単語1000本ノック」のデザインから始めよう

TOEICスコアアップとプログラミング習得を同時に!

以前、Webスクレイピングの解説シリーズを紹介しました。そこでは、英語辞書系サイトから、TOEICSAT(米国大学入学選考で利用される試験)などに頻出の単語をもとに、そのサンプル文章を抽出するというアプリ、「英単語1000本ノック」をVisual StudioとC#を使って作成しました。

ここでどのような機能を作ったかというと、

❶ 単語リストをTOEIC、SAT、そして自分のリストから選択
❷ リストから学習する単語をランダムに選ぶ
❸ 選ばれた単語が入った例文を複数の辞書系サイトから自動抽出する
❹ 例文を一つひとつ表示して単語の意味を掴む

作ったコンソールアプリはこんな感じでした。

画像1

【C#コンソール版 英単語1000本ノックアプリのサンプル画面】

上のサンプル画面では、単語帳としてTOEICを選び、cupboardという単語がセレクトされています。それに対して例文を英語から表示し、意味を考えたらEnterキーを押して日本語の訳文を表示するという流れで単語の意味を理解していきます。

辞書禁止!英単語を例文で覚えるのが効果的な理由

ちょっとプログラミングから話がそれますが、この「例文から単語を覚える」という学習アプローチについてちょっと解説したいと思います。

英単語の勉強といえば、まずは辞書を見て意味を理解するのが普通のやり方です。それで頭に入るなら苦労はないのですが、ただ単に意味を見ただけではなかなか頭に入りません。辞書を閉じたとたんに意味を忘れることもよくあることですよね。

そこで、辞書は一切使わず、とにかくサンプル文章を見続け、あくまで文脈の中で意味を理解してみるというのが実は大変効果的な単語の覚え方です。

例えば、fluctuateという単語。もし意味が分からない場合、この”1000本ノックアプリ”でどう学習するか説明します。

アプリではとにかく、fluctuateが入った例文がどんどんと表示されます。単語によっては100以上もの例文を見ることができます。これはすべてWebサイトからスクレイプ(自動抽出)されたものです。それを英文だけを見ていって意味を考えてみるのです。

画像9

意味がピンとくる”ゴールデンサンプル”を待つ

まず最初に出てくるのはこの文章です。

The stocks fluctuate in price.

stockは株式のこと。priceは値段。つまり「株は値段でfluctuateする」ということ。株と値段と言えばどんな動詞なのでしょう。「株は値段が上がる」?あるいは「下がる」?まあとにかく株と値段に使える動詞だということはわかります。大きなヒントですよね。

各例文でこうしたヒントを頭に蓄積していきます。ヒントがわかればそれで充分です。なるべく時間をかけずに次に行きます。

fluctuate between hopes and fears

「希望と恐れの間をfluctuate」する?よく「希望と絶望のはざまで・・・」とか言いますが、そんなことなんでしょうか。まあよくわからなくても「良いことと悪いことの間で何かするのがfluctuate」ということがわかればOKです。では次。

fluctuate markedly from one year to the next.

markedlyは「すごく、著しく」という意味です。例文にはほかにもわからない単語が出てきます。スキップしてもよいのですが、ターゲットの単語以外なら辞書で調べてもよいでしょう。

そこで、「ある年から次の年にかけてものすごくfluctuateした」ということです。まだ決定的なヒントはないですね。例文中にピンとくるものがなければ即パスします。では次。

not liable to fluctuate or especially to fall

liableは「~しやすい」ということで、「fluctuateしやすく、特に落ちやすい」という意味。また株の話なんでしょうね。どうやら株価というものと親和性の高い動詞だという感じです。まあ次に行きましょう。

cause to fluctuate or move in a wavelike pattern

例文を読み進めていくと、「ゴールデンサンプル」、つまりその文章を読むとかなり意味が見えてくるというものにぶちあたります。例えばここの文章がそれです。「波のようなパターンでfluctuateしたり動いたりする結果となる」。”波の動き”というのは上下動ですよね。音波の波形などを想像してみてください。このパターンというのだから、これはもう「上下する」という意味の線が濃くなってきます。そういえば株価も上下します。希望と絶望の間の動きも上と下ですよね。だんだんとイメージが固まってきますよね。

その人の英語力にもよりますが、こうやっていくつもサンプルの英文と格闘していくと、ある段階でぼんやりと意味が見えてきます。はっきりと訳語を言えないにしても、文脈の中で意味をとらえることに意味があります。これが1000本ノックの真価です。

今回作るウェブサイトはこんな感じです。

画像2

まず単語帳の中からランダムに一つ選んでくれます。ここではfluctuateが選択され、Webスクレイピングで取得したサンプル文章が表示されます。「次を表示」をクリックしていくと、次々に出てきますので、一つひとつ読み解きながら意味を考えていきます。

意味がだいたいわかってきたら、今度は「訳文も表示する」をチェックして「最初から」をクリックすると、最初から文章の表示をスタートし、今度は翻訳文がついてきます(ないものもありますが、この対処は後程やっていきます)。

画像3

意味を確認しながら例文を見ていくと、確信をもって意味を文脈のなかで理解できるので、これが頭に入りやすくなる秘訣です。

その上で最終確認として辞書を見たい時、各サンプルにある辞書サイトのリンク(上の例ではweblioやyourdictionaryなど)をクリックすると辞書の定義を見ることができます。

画像4

1000本ノックのポイントは理解できましたか?

では開発の準備をしよう!

英単語の学習方法に話がそれましたが、ではプログラミングをスタートさせましょう。まず今回の目的はHTMLやCSS、JavaScriptを使って上記の通りの英単語学習サイトを開発していきます。もちろんサイトはPCでもスマホでも見ることができます。これまで他のnoteシリーズをお読みいただいた方はすぐにスタートできますが、今回初めての方に、作業の前提条件を説明します。

準備❶ ウェブページとJafvaScriptのコーディング環境を用意する

これは「子供とプログラミング」シリーズでやった「おしゃべりWebサイト」のマガジンを読めばすべて準備が整います。

Visual Studio CodeでHTML、CSS、JavaScriptを少しでも書いたことがある方はスキップしても構いません。ただ、Web APIの呼び出し方、そして自作したウェブサイトをFTPで公開する(ここではAzureのApp Serviceとして展開する)方法も詳しく解説していますので、サイトコンテンツをサーバーにアップロードした経験がない方は是非お読みください。

【このシリーズ記事でできるようになること】

● Visual Studio Code(PCとMac対応)が使えるようになる
● 簡単なHTML、CSS、JavaScriptが書ける
● 作成したウェブサイトをサーバーに展開して公開できる
● Web APIの基礎が理解できる

プログラミング未経験の方は是非このシリーズを読んでプログラミングに挑戦してみてください。

準備❷ Webスクレイピングの方法

1000本ノックアプリそのものはWeb Scrapingは行いません。単語帳やサンプルの収集はすべてMagicWandAPIというWeb APIで行い、皆さんが書くJavaScriptはAPIの呼び出しだけを行います。ただ、どうしてTOEICの頻出単語が利用できて、多くの例文が取得できるのか、その仕組みについては、Webスクレイピングについて特集したマガジン記事をご覧ください。

ここでは1000本ノックアプリのC#バージョンを作っています。

ではコーディング作業に入りましょう!

画像10

ステップ❶:プロジェクトフォルダを用意する

いつもの通り、まずはプロジェクトファイルを入れるフォルダをどこかに作ってください。ここではWebSiteEitangoとしています。

そして、次のHTMLとCSSファイル、そして前回プロジェクトで使った音声処理(音声認識と音声合成)のJavaScriptを用意します。ここはコアのコーディングとはあまり関係がないので深くは解説しません。とりあえずファイル作成の作業を進めてください。

画像11

index.html

まずはHTMLファイル、index.htmlを作り、中身は次のものをコピペしてくっださい。

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <link rel="stylesheet" href="style.css">
   <title>英単語 1000本ノック</title>
</head>
<body>
   <section class="wholesecion">
       <div class="content">
           <h1>英単語1000本ノック</h1>
           <div class="source-selection">
               <span class="sources">単語帳:</span> 
               <label><input type="radio" class="nes-radio" name="source" value="TOEIC" checked="true" /><span>TOEIC</span></label>
               <label><input type="radio" class="nes-radio" name="source" value="SAT" /><span>SAT</span></label>
               <label><input type="radio" class="nes-radio" name="source" value="MYLIST" /><span>マイリスト</span></label>
               <br/>
               <label><input class="nes-checkbox" type="checkbox" id="show-trans" /><span>訳文も表示する</span></label>
               <br/><br/>
          </div>

           <div id="term-box" class="selected-term"></div>
           <div id="sample-box" class="display-samples"></div>
           <button id="run-train" class="rounded-corner" onclick="RunTraining();">スタート</button>
           <button id="run-train" class="rounded-corner" onclick="RestartTraining();">最初から</button>
           <button id="re-start" class="rounded-corner" onclick="RerunTraining();">次の単語</button>
       </div>
   </section>

   <script src="./speech.js"></script>
   <script src="./training.js"></script>
</body>
</html>

style.css

次にスタイルシートです。これもファイルを作ったら中身をコピペしてください。

:root {
	--primary-color: #3a4052 ;
}
* {
	box-sizing: border-box;
	margin: 0;
   padding: 0;
}
body {
	font-family: 'Open Sans', sans-serif;
   line-height: 1.5;
   background: url("background.jpg");
}
h1 {
	font-weight: bold;
	font-size: 35px;
	line-height: 1.2;
	margin-bottom: 30px;
	margin-top: 15px;
}
.wholesecion {
	display: flex;
   justify-content: center;
	text-align: center;
   align-items: center;
	color: rgb(39, 51, 17);
	padding: 10px 20px;
}

.rounded-corner {
	margin: 10pt;
	padding: 5pt;
	background-color: #0a458a ;
	width: 120px;
	height: 50px;
	color: #FFFFFF ;
	font-size: 20px;
	outline:none;
}

.content {
	align-items: center;
}

.display-samples {
	align-items: center;
	align-content: center;;
	word-wrap: break-word;
	width: 100%; 
	text-align: left;
	margin: 5px;
	font-size: 15pt;
}

.display-samples .eng-sentence{
   text-align: left;
   color: black;
   border-radius: 5px;
   background: url("engback.jpg");
   background-size: cover;
   width:100%;
   padding:10px 10px 10px 10px;
   box-shadow: inset 8px 8px 10px #9aa1a3 ,
               inset -4px -4px 8px #ffffff ;         
 }

.selected-term {
   width:100%;
	font-weight: bold;
	background-color: darkslategrey;
	color: #FFFFFF ;
}

この中で二つのJPEGファイルが参照されています。ウェブページ全体の背景と、英文ボックスの背景で、白っぽい背景画像なら何でもよいのですが、サンプルに使われているものを下に表示しておきました。それぞれの画像の上で右クリックし、「画像を保存する」を選択して自分のプロジェクトフォルダに指定されたファイル名で保存してください。ファイル名は同じものでないといけませんのでご注意を。

background.jpg (右クリックして保存)

画像5

engback.jpg (右クリックして保存)

画像6

speech.js

これは「おしゃべりウェブサイト」で使った音声JavaScriptと全く同じですので、そこでプロジェクトをやった方はそのまま使えます。初めての方は同じ名前でJSファイルを作って、中身をコピペしてください。

//====================================================
// Web Speech APIを利用した音声認識と音声合成の関数
//====================================================
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
//音声合成
function Speak (text, locale) {
 let voice = new SpeechSynthesisUtterance();
 voice.text = text;
 voice.volume = 1;
 voice.rate = 1;
 voice.pitch = 1;
 voice.lang = locale;
 window.speechSynthesis.speak(voice);
}

//音声認識
function Recognize(locale, callback) {                 
 var recognition = new SpeechRecognition();
 recognition.continuous = false;
 recognition.lang = locale;
 recognition.interimResults = false;
 recognition.maxAlternatives = 1;
 recognition.start();
 recognition.onresult = function(event) {
   var recoText = event.results[0][0].transcript;
   //コールバック関数を呼び出す
   callback(recoText);
 }
}

ステップ❷ 中心となるロジックをJavaScriptでコーディング

最後にコアとなるJavaScriptです。ここではtraining.jsという名前で作成して、まずはコピペしてください。

training.js


//サンプル文章データのJSONオブジェクト
var SamplesJSON;
//現在のサンプル文章のインデックス
var SampleIndex = 0;

//スタートボタンを押した際のトレーニング開始メソッド
function RunTraining() {
   var tangocho = document.querySelector('input[name="source"]:checked').value;
   GetSamples(tangocho);
}

//サンプル文章の表示を最初から表示しなおすメソッド
function RestartTraining() {
   SampleIndex = 0;
   document.getElementById("sample-box").innerHTML = "";
   DisplaySample();
}

//新しい単語を選択してトレーニングをスタートさせるメソッド
function RerunTraining() {
   SampleIndex = 0;
   document.getElementById("run-train").innerHTML = "スタート";
   document.getElementById("term-box").innerHTML = "";
   document.getElementById("sample-box").innerHTML = "";
   var tangocho = document.querySelector('input[name="source"]:checked').value;
   GetSamples(tangocho);
}

//単語をもとにサンプル文章のJSONデータを取得するメソッド
const GetSamples = function (listtype) {
   //最初の時だけサンプル文章データの取得を行う
   if (SampleIndex == 0) {
       document.getElementById("term-box").innerHTML = "サンプル文章をロードしています・・・";
       //ここからWeb APIの呼び出し
       var oRequest = new XMLHttpRequest();
       oRequest.responseType = "text";
       oRequest.open("GET", "https://magicwandapi.azurewebsites.net/api/eitango/"  + listtype);

       oRequest.onload = function () {
           if (oRequest.status >= 200 && oRequest.status < 400) {
               SamplesJSON = JSON.parse(this.response);
               document.getElementById("term-box").innerHTML = SamplesJSON.term;
               DisplaySample();
               document.getElementById("run-train").innerHTML = "次を表示";
           }
       };
       oRequest.send();
   } 
   //一度表示が始まったらあとはJSONオブジェクトからデータ表示
   else {
       DisplaySample();
   }   
}

//サンプル文章をDIVに表示させるメソッド
function DisplaySample () {
   //サンプル英文
   var engsentence = SamplesJSON.samples[SampleIndex].sentence;       
   //サンプル翻訳:翻訳データがない場合はnullになる
   var translation;
   if (document.getElementById("show-trans").checked == true)
       translation = SamplesJSON.samples[SampleIndex].locsentence;
   else 
       translation = "";
   //表示テキストの作成:英文をクリックすると音声で読み上げる
   document.getElementById("sample-box").innerHTML 
       += "<div class=eng-sentence onclick='Speak(\"" + engsentence + "\", \"en-US\");'>" + engsentence + "</div>" 
       + "<div class=jpn-sentence>" + translation + "</div>"
       + "<a href=" + SamplesJSON.samples[SampleIndex].url + " target=_blank>" 
       + SamplesJSON.samples[SampleIndex].siteName + "</a><br/>";     
   //音声で読み上げる
   Speak(SamplesJSON.samples[SampleIndex].sentence, "en-US");

   SampleIndex++;
}

まずは基本的な操作をカバーするスクリプトです。このファイルを作成して保存したら、まずはウェブページを動かしてみましょう。前回プロジェクト(「子供と一分間プログラミング」)をやったら、Preview on Web Server(VSCodeで使える簡易Webサーバーなら何でも構いません)がVSCodeにインストールされていると思いますので、Cntl + Shift + L でサイトをローカルホストで立ち上げてみて下さい。

画像7

使い方は簡単で、TOEICがデフォルトで選択されていますので、まずは「スタート」ボタンをクリックしてください。

最初から」ボタンをクリックすると同じ単語で最初からサンプル表示を始めます。その際に「訳文も表示する」をチェックすると翻訳文も表示されます。

画像8

別の単語をやりたい場合は「次の単語」ボタンをクリックしてください。

まずはアプリがどんな動作をするのか、実際に使ってみて理解してください。

次回は

今回はアプリ作成前の解説が長くなりましたので、training.jsの解説は次回にたっぷりやります。まずはアプリを使って操作に慣れてください。

今後のコーディング作業ですが、まずは次回に今回使用したWeb APIの解説およびWeb APIの呼び出しについて詳しく解説します。単語帳とサンプル文章をどのように用意したかについても深く掘り下げます。

さらに、今後はアプリを拡張していきます。現段階でいくつか軽いバグがある(訳文がないとnull表示されるなど)のでその対処と、次の機能を追加していきます。

● 訳文がないサンプルは機械翻訳で訳文を生成する
● 自分でサンプル文章を発音して聞き取ってもらう(音声認識)。発音することでさらに単語が使えるようになる。
● 自分の単語リストをもとにトレーニングができるようにする
● すでに覚えた単語は選択されないようにする

こうした機能を4回程度にわたって実装していきます。

乞うご期待!


この記事が気に入ったらサポートをしてみませんか?