diff --git a/app/templates/index.html b/app/templates/index.html
index 5d7f0d246dbb39970daf18352cd8060cd9b11c88..404ea64d907de992011e6cb8a9f5874fc3b23a78 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -14,34 +14,12 @@
     <meta property="og:image" content="https://user-images.githubusercontent.com/1951843/102724116-32a6df00-42db-11eb-8cc0-129ab39cdfb5.png" />
     <meta property="og:description" name="description" class="swiftype" content="Free and Open Source Machine Translation API. 100% self-hosted, no limits, no ties to proprietary services. Run your own API server in just a few minutes."/>
 
-
 	<script src="{{ url_for('static', filename='js/vue@2.js') }}"></script>
 	<!-- Compiled and minified CSS -->
 	<link rel="stylesheet" href="{{ url_for('static', filename='css/materialize.min.css') }}">
-	<link href="{{ url_for('static', filename='css/material-icons.css') }}" rel="stylesheet">
-	<link href="{{ url_for('static', filename='css/prism.min.css') }}" rel="stylesheet" />
-
-	<style type="text/css">
-	textarea.materialize-textarea{height: 120px;}
-	.code{
-		font-size: 90%;
-        border-radius: 4px;
-	    padding: 4px;
-	    border: 1px solid #9e9e9e;
-	    background: #fbfbfb;
-	    overflow: auto;
-	    font-family: monospace;
-	    min-height: 280px;
-	    width: 100%;
-	    overflow: auto;
-	}
-	.progress.translate{
-		position: absolute;
-	}
-	.card.horizontal .card-stacked{
-		overflow: auto;
-	}
-	</style>
+	<link rel="stylesheet" href="{{ url_for('static', filename='css/material-icons.css') }}" />
+	<link rel="stylesheet" href="{{ url_for('static', filename='css/prism.min.css') }}" />
+	<link rel="stylesheet" href="{{ url_for('static', filename='css/main.min.css') }}" />
 
 	{% if gaId %}
 	<!-- Global site tag (gtag.js) - Google Analytics -->
@@ -50,449 +28,440 @@
 	  window.dataLayer = window.dataLayer || [];
 	  function gtag(){dataLayer.push(arguments);}
 	  gtag('js', new Date());
-
 	  gtag('config', '{{ gaId }}');
 	</script>
-   {% endif %}
+	{% endif %}
 </head>
+
 <body>
-  <nav class="blue lighten-1" role="navigation">
-	<div class="nav-wrapper container"><a id="logo-container" href="/" class="brand-logo"><i class="material-icons">translate</i> LibreTranslate</a>
-	  <ul class="right hide-on-med-and-down">
-		<li><a href="/docs">API Docs</a></li>
-        <li><a href="https://github.com/uav4geo/LibreTranslate">GitHub</a></li>
-        {% if api_keys %}
-        <li><a href="javascript:setApiKey()" title="Set API Key"><i class="material-icons">vpn_key</i></a></li>
-        {% endif %}
-	  </ul>
-
-	  <ul id="nav-mobile" class="sidenav">
-		<li><a href="/docs">API Docs</a></li>
-        <li><a href="https://github.com/uav4geo/LibreTranslate">GitHub</a></li>
-        {% if api_keys %}
-        <li><a href="javascript:setApiKey()" title="Set API Key"><i class="material-icons">vpn_key</i></a></li>
-        {% endif %}
-      </ul>
-	  <a href="#" data-target="nav-mobile" class="sidenav-trigger"><i class="material-icons">menu</i></a>
-	</div>
-  </nav>
-  <div id="app">
-   <div class="section no-pad-bot center" v-if="loading">
-	<div class="container">
-		<div class="row">
-		  <div class="preloader-wrapper active">
-			<div class="spinner-layer spinner-blue-only">
-			  <div class="circle-clipper left">
-				<div class="circle"></div>
-			  </div><div class="gap-patch">
-				<div class="circle"></div>
-			  </div><div class="circle-clipper right">
-				<div class="circle"></div>
-			  </div>
+	<header>
+		<nav class="blue lighten-1" role="navigation">
+			<div class="nav-wrapper container">
+				<a id="logo-container" href="/" class="brand-logo">
+					<i class="material-icons">translate</i> LibreTranslate
+				</a>
+				<ul class="right hide-on-med-and-down">
+				<li><a href="/docs">API Docs</a></li>
+				<li><a href="https://github.com/uav4geo/LibreTranslate">GitHub</a></li>
+				{% if api_keys %}
+				<li><a href="javascript:setApiKey()" title="Set API Key"><i class="material-icons">vpn_key</i></a></li>
+				{% endif %}
+				</ul>
+
+				<ul id="nav-mobile" class="sidenav">
+				<li><a href="/docs">API Docs</a></li>
+				<li><a href="https://github.com/uav4geo/LibreTranslate">GitHub</a></li>
+				{% if api_keys %}
+				<li><a href="javascript:setApiKey()" title="Set API Key"><i class="material-icons">vpn_key</i></a></li>
+				{% endif %}
+				</ul>
+				<a href="#" data-target="nav-mobile" class="sidenav-trigger"><i class="material-icons">menu</i></a>
+			</div>
+		</nav>
+	</header>
+
+	<main id="app">
+	<div class="section no-pad-bot center" v-if="loading">
+		<div class="container">
+			<div class="row">
+				<div class="preloader-wrapper active">
+				<div class="spinner-layer spinner-blue-only">
+					<div class="circle-clipper left">
+					<div class="circle"></div>
+					</div><div class="gap-patch">
+					<div class="circle"></div>
+					</div><div class="circle-clipper right">
+					<div class="circle"></div>
+					</div>
+				</div>
+				</div>
 			</div>
-		  </div>
 		</div>
 	</div>
-  </div>
-  <div v-else-if="error">
-  <div class="section no-pad-bot">
-	<div class="container">
-		<div class="row">
-		  <div class="col s12 m7">
-		    <div class="card horizontal">
-		      <div class="card-stacked">
-		        <div class="card-content">
-		          <i class="material-icons">warning</i><p> [[ error ]]</p>
-		        </div>
-		        <div class="card-action">
-		          <a href="#" @click="dismissError">Dismiss</a>
-		        </div>
-		      </div>
-		    </div>
-		  </div>
-		 </div>
+
+	<div v-else-if="error">
+		<div class="section no-pad-bot">
+			<div class="container">
+				<div class="row">
+					<div class="col s12 m7">
+					<div class="card horizontal">
+						<div class="card-stacked">
+						<div class="card-content">
+							<i class="material-icons">warning</i><p> [[ error ]]</p>
+						</div>
+						<div class="card-action">
+							<a href="#" @click="dismissError">Dismiss</a>
+						</div>
+						</div>
+					</div>
+					</div>
+					</div>
+			</div>
 		</div>
 	</div>
-  </div>
-  <div v-else>
-  <div class="section no-pad-bot">
-	<div class="container">
-		<div class="row">
-		<h3 class="header center">Translation API</h3>
-		<div class="card horizontal">
-			<div class="card-stacked">
-				<div class="card-content">
+
+	<div v-else>
+		<div class="section no-pad-bot">
+			<div class="container">
+				<div class="row">
+					<h3 class="header center">Translation API</h3>
+
 					<form class="col s12">
-					  <div class="row">
-						<div class="input-field col s5">
-							<select  class="browser-default" v-model="sourceLang" ref="sourceLangDropdown"@change="handleInput">
-								 <template v-for="option in langs">
-									 <option :value="option.code">[[ option.name ]]</option>
-								</template>
-							</select>
-						 </div>
-						 <div class="col s2 center">
-						 	<a href="javascript:void(0)" @click="swapLangs" class="waves-effect waves-teal btn-flat btn-large" style="margin-top: 8px;"><i class="material-icons">swap_horiz</i></a>
-						 </div>
-						 <div class="input-field col s5">
-							<select  class="browser-default" v-model="targetLang" ref="targetLangDropdown" @change="handleInput">
-								<template v-for="option in langs">
-									 <option v-if="option.code !== 'auto'" :value="option.code">[[ option.name ]]</option>
-								</template>
-							</select>
-						 </div>
-					</div>
-					<div class="row">
-						<div class="input-field col s6">
-						  <textarea id="textarea1" class="materialize-textarea" v-model="inputText" @input="handleInput" ref="inputTextarea"></textarea>
-						  <label for="textarea1">Input Text</label>
-						  <div v-if="charactersLimit !== -1">
-							  <label>[[ inputText.length ]] / [[ charactersLimit ]]</label>
+						<div class="row mb-0">
+							<div class="col s6 language-select">
+								<span>Translate from</span>
+								<select class="browser-default" v-model="sourceLang" ref="sourceLangDropdown" @change="handleInput">
+									<template v-for="option in langs">
+										<option :value="option.code">[[ option.name ]]</option>
+									</template>
+								</select>
+							</div>
+
+							<div class="col s6 language-select">
+								<a href="javascript:void(0)" @click="swapLangs" class="btn-switch-language">
+									<i class="material-icons">swap_horiz</i>
+								</a>								
+								<span>Translate into</span>
+								<select  class="browser-default" v-model="targetLang" ref="targetLangDropdown" @change="handleInput">
+									<template v-for="option in langs">
+										<option v-if="option.code !== 'auto'" :value="option.code">[[ option.name ]]</option>
+									</template>
+								</select>								
 							</div>
 						</div>
-						<div class="input-field col s6">
-							<div>
-							  <textarea id="textarea2" class="materialize-textarea" v-model="translatedText" ref="translatedTextarea"></textarea>
-							  <label for="textarea2"><div class="progress translate" v-if="loadingTranslation">
-							  <div class="indeterminate"></div>
-						  </div></label>
-							 </div>
-						</div>
-					</div>
-					<div class="row">
-						<div class="col s6">
-							<button class="btn btn-small" style="display: inline-block;" title="Delete text" @click="deleteText"><i class="material-icons">delete</i></button>
-						</div>
-						<div class="col s6" style="text-align: right;">
-							<button class="btn btn-small" style="display: inline-block;" @click="copyText">[[ copyTextLabel ]]</button>
+
+						<div class="row">
+							<div class="input-field textarea-container col s6">
+								<textarea id="textarea1" v-model="inputText" @input="handleInput" ref="inputTextarea"></textarea>
+								<button class="btn-delete-text" title="Delete text" @click="deleteText">
+									<i class="material-icons">close</i>
+								</button>							
+								<div class="characters-limit-container" v-if="charactersLimit !== -1">
+									<label>[[ inputText.length ]] / [[ charactersLimit ]]</label>
+								</div>
+							</div>
+
+							<div class="input-field textarea-container col s6">
+								<div class="position-relative">
+									<textarea id="textarea2" v-model="translatedText" ref="translatedTextarea"></textarea>
+									<button class="btn-copy-translated" @click="copyText">
+										<span>[[ copyTextLabel ]]</span> <i class="material-icons">content_copy</i>
+									</button>										
+									<label for="textarea2">
+										<div class="progress translate" v-if="loadingTranslation">
+											<div class="indeterminate"></div>
+										</div>
+									</label>
+								</div>
+							</div>
 						</div>
-					</div>
 					</form>
-			   </div>
-			  </div>
-		  </div>
-	  </div>
-	</div>
-  </div>
-
-  <div class="section no-pad-bot" id="index-banner">
-	<div class="container">
-	   <div class="row center">
-		  <div class="col s12 m12">
-			<div class="card horizontal">
-			  <div class="card-stacked">
-				<div class="card-content">
+
+				</div>
+			</div>
+		</div>
+
+		<div class="section no-pad-bot" id="index-banner">
+			<div class="container">
+				<div class="row center">
+					<div class="col s12 m12">
+
 					<div class="row center">
 						<div class="col s12 m12 l6 left-align">
 							<p>Request</p>
-							<p>
-<pre class="code"><code class="language-javascript" v-html="$options.filters.highlight(requestCode)">
-</code></pre></p>
+							<pre class="code"><code class="language-javascript" v-html="$options.filters.highlight(requestCode)">
+							</code></pre>
 						</div>
 						<div class="col s12 m12 l6 left-align">
 							<p>Response</p>
-<pre class="code"><code class="language-javascript" v-html="$options.filters.highlight(output)">
-</code></pre>
+							<pre class="code"><code class="language-javascript" v-html="$options.filters.highlight(output)">
+							</code></pre>
 						</div>
 					</div>
 
+					</div>
 				</div>
-			  </div>
 			</div>
-		  </div>
-	  </div>
-	</div>
-  </div>
- {% if web_version %}
-  <div class="section no-pad-bot" id="index-banner">
-	<div class="container">
-	   <div class="row center">
-		  <div class="col s12 m12">
-		  		<h3 class="header">Open Source Machine Translation</h3>
-  				<h4 class="header">100% Self-Hosted. No Limits. No Ties to Proprietary Services.</h4>
-  		  		<br/><a class="waves-effect waves-light btn btn-large" href="https://github.com/uav4geo/LibreTranslate"><i class="material-icons left">cloud_download</i> Download</a>
-  		  		<br/><br/><br/>
-  		  </div>
-  		</div>
-	  </div>
+		</div>
+		{% if web_version %}
+		<div class="section no-pad-bot" id="index-banner">
+			<div class="container">
+				<div class="row center">
+					<div class="col s12 m12">
+						<h3 class="header">Open Source Machine Translation</h3>
+						<h4 class="header">100% Self-Hosted. No Limits. No Ties to Proprietary Services.</h4>
+						<br/><a class="waves-effect waves-light btn btn-large" href="https://github.com/uav4geo/LibreTranslate"><i class="material-icons left">cloud_download</i> Download</a>
+						<br/><br/><br/>
+					</div>
+				</div>
+			</div>
+		</div>
+		{% endif %}
 	</div>
-{% endif %}
-</div>
-</div>
-
-<footer class="page-footer blue darken-3">
-  <div class="container">
-	<div class="row">
-	  <div class="col l12 s12">
-		<h5 class="white-text">LibreTranslate</h5>
-		<p class="grey-text text-lighten-4">Free and Open Source Machine Translation API</p>
-		<p class="grey-text text-lighten-4">
-			Made with ❤ by <a class="grey-text text-lighten-3" href="https://uav4geo.com">UAV4GEO</a> and powered by <a class="grey-text text-lighten-3" href="https://github.com/argosopentech/argos-translate/">Argos Translate</a>
-		</p>
-		<p><a class="grey-text text-lighten-4" href="https://www.gnu.org/licenses/agpl-3.0.en.html">License: AGPLv3</a></p>
-		<p><a class="grey-text text-lighten-4" href="/javascript-licenses" rel="jslicense">JavaScript license information</a></p>
-{% if web_version %}
-        <p>
-			The public API on libretranslate.com should be used for testing, personal or infrequent use. If you're going to run an application in production, please <a href="https://github.com/uav4geo/LibreTranslate" class="grey-text text-lighten-4" style="text-decoration: underline;">host your own server</a> or <a class="grey-text text-lighten-4" href="https://uav4geo.com/contact" style="text-decoration: underline;">get in touch</a> to obtain an API key.
-		</p>
-{% endif %}
-	  </div>
-	  <div class="col l4 offset-l2 s12">
-		<!-- <h5 class="white-text">Links</h5>
-		<ul>
-		  <li><a class="grey-text text-lighten-3" href="#!">Link 1</a></li>
-		  <li><a class="grey-text text-lighten-3" href="#!">Link 2</a></li>
-		  <li><a class="grey-text text-lighten-3" href="#!">Link 3</a></li>
-		  <li><a class="grey-text text-lighten-3" href="#!">Link 4</a></li>
-		</ul> -->
+	</main>
+
+	<footer class="page-footer blue darken-3">
 		<div class="container">
+			<div class="row">
+				<div class="col l12 s12">
+					<h5 class="white-text">LibreTranslate</h5>
+					<p class="grey-text text-lighten-4">Free and Open Source Machine Translation API</p>
+					<p><a class="grey-text text-lighten-4" href="https://www.gnu.org/licenses/agpl-3.0.en.html">License: AGPLv3</a></p>
+					<p><a class="grey-text text-lighten-4" href="/javascript-licenses" rel="jslicense">JavaScript license information</a></p>
+					{% if web_version %}
+					<p>
+						The public API on libretranslate.com should be used for testing, personal or infrequent use. If you're going to run an application in production, please <a href="https://github.com/uav4geo/LibreTranslate" class="grey-text text-lighten-4" style="text-decoration: underline;">host your own server</a> or <a class="grey-text text-lighten-4" href="https://uav4geo.com/contact" style="text-decoration: underline;">get in touch</a> to obtain an API key.
+					</p>
+					{% endif %}
+				</div>
+			</div>
 		</div>
-	  </div>
-	</div>
-  </div>
-  <div class="footer-copyright center">
-  </div>
-</footer>
-
-<script src="{{ url_for('static', filename='js/materialize.min.js') }}"></script>
-<script>
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-window.Prism = window.Prism || {};
-window.Prism.manual = true;
-// @license-end
-</script>
-
-<script src="{{ url_for('static', filename='js/prism.min.js') }}"></script>
-
-<script>
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-// API host/endpoint
-var BaseUrl = window.location.protocol + "//" + window.location.host;
-
-document.addEventListener('DOMContentLoaded', function(){
-    var elems = document.querySelectorAll('.sidenav');
-    var instances = M.Sidenav.init(elems);
-
-	var app = new Vue({
-	  el: '#app',
-	  delimiters: ['[[',']]'],
-	  data: {
-	  	BaseUrl: BaseUrl,
-		loading: true,
-		error: "",
-		langs: [],
-		settings: {},
-		sourceLang: "",
-		targetLang: "",
-
-		loadingTranslation: false,
-		inputText: "",
-		translatedText: "",
-		output: "",
-		charactersLimit: -1,
-
-		copyTextLabel: "Copy Text"
-	  },
-	  mounted: function(){
-		var self = this;
-		var requestSettings = new XMLHttpRequest();
-		requestSettings.open('GET', BaseUrl + '/frontend/settings', true);
-
-		requestSettings.onload = function() {
-		  if (this.status >= 200 && this.status < 400) {
-				// Success!
-				self.settings = JSON.parse(this.response);
-				self.sourceLang = self.settings.language.source.code;
-				self.targetLang = self.settings.language.target.code;
-				self.charactersLimit = self.settings.charLimit;
-			}else {
-				self.error = "Cannot load /frontend/settings";
-				self.loading = false;
-		  }
-		};
+		<div class="footer-copyright center">
+			<p>
+				Made with ❤ by <a class="grey-text text-lighten-3" href="https://uav4geo.com">UAV4GEO</a> and powered by <a class="grey-text text-lighten-3" href="https://github.com/argosopentech/argos-translate/">Argos Translate</a>
+			</p>
+		</div>
+	</footer>
 
-		requestSettings.onerror = function() {
-		  self.error = "Error while calling /frontend/settings";
-		  self.loading = false;
-		};
+	<script src="{{ url_for('static', filename='js/materialize.min.js') }}"></script>
+	<script>
+	// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
+	window.Prism = window.Prism || {};
+	window.Prism.manual = true;
+	// @license-end
+	</script>
 
-		requestSettings.send();
+	<script src="{{ url_for('static', filename='js/prism.min.js') }}"></script>
 
-		var requestLanguages = new XMLHttpRequest();
-		requestLanguages.open('GET', BaseUrl + '/languages', true);
+	<script>
+	// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
+	// API host/endpoint
+	var BaseUrl = window.location.protocol + "//" + window.location.host;
+
+	document.addEventListener('DOMContentLoaded', function(){
+		var sidenavElems = document.querySelectorAll('.sidenav');
+		var sidenavInstances = M.Sidenav.init(sidenavElems);
+
+		var app = new Vue({
+		el: '#app',
+		delimiters: ['[[',']]'],
+		data: {
+			BaseUrl: BaseUrl,
+			loading: true,
+			error: "",
+			langs: [],
+			settings: {},
+			sourceLang: "",
+			targetLang: "",
+
+			loadingTranslation: false,
+			inputText: "",
+			inputTextareaHeight: 250,
+			translatedText: "",
+			output: "",
+			charactersLimit: -1,
+
+			copyTextLabel: "Copy text"
+		},
+		mounted: function(){
+			var self = this;
+			var requestSettings = new XMLHttpRequest();
+			requestSettings.open('GET', BaseUrl + '/frontend/settings', true);
 
-		requestLanguages.onload = function() {
-		  if (this.status >= 200 && this.status < 400) {
-			// Success!
-			self.langs = JSON.parse(this.response);
-			self.langs.push({ name: 'Auto Detect (Experimental)', code: 'auto' })
-			if (self.langs.length === 0){
-				self.loading = false;
-				self.error = "No languages available. Did you install the models correctly?"
-				return;
+			requestSettings.onload = function() {
+			if (this.status >= 200 && this.status < 400) {
+					// Success!
+					self.settings = JSON.parse(this.response);
+					self.sourceLang = self.settings.language.source.code;
+					self.targetLang = self.settings.language.target.code;
+					self.charactersLimit = self.settings.charLimit;
+				}else {
+					self.error = "Cannot load /frontend/settings";
+					self.loading = false;
 			}
+			};
 
-		    self.loading = false;
-		  } else {
-			self.error = "Cannot load /languages";
+			requestSettings.onerror = function() {
+			self.error = "Error while calling /frontend/settings";
 			self.loading = false;
-		  }
-		};
-
-		requestLanguages.onerror = function() {
-		  self.error = "Error while calling /languages";
-		  self.loading = false;
-		};
-
-		requestLanguages.send();
-	  },
-	  updated: function(){
-			M.FormSelect.init(this.$refs.sourceLangDropdown);
-			M.FormSelect.init(this.$refs.targetLangDropdown);
-			if (this.inputText === ""){
-				this.$refs.inputTextarea.style.height = 150 + "px";
-				this.$refs.translatedTextarea.style.height = 150 + "px";
-			}else{
-				this.$refs.inputTextarea.style.height = this.$refs.translatedTextarea.style.height = "1px";
-				this.$refs.inputTextarea.style.height = Math.max(150, this.$refs.inputTextarea.scrollHeight) + "px";
-				this.$refs.translatedTextarea.style.height = Math.max(150, this.$refs.translatedTextarea.scrollHeight) + "px";
-			}
+			};
+
+			requestSettings.send();
+
+			var requestLanguages = new XMLHttpRequest();
+			requestLanguages.open('GET', BaseUrl + '/languages', true);
 
-			if (this.charactersLimit !== -1 && this.inputText.length >= this.charactersLimit){
-				this.inputText = this.inputText.substring(0, this.charactersLimit);
+			requestLanguages.onload = function() {
+			if (this.status >= 200 && this.status < 400) {
+				// Success!
+				self.langs = JSON.parse(this.response);
+				self.langs.push({ name: 'Auto Detect (Experimental)', code: 'auto' })
+				if (self.langs.length === 0){
+					self.loading = false;
+					self.error = "No languages available. Did you install the models correctly?"
+					return;
+				}
+
+				self.loading = false;
+			} else {
+				self.error = "Cannot load /languages";
+				self.loading = false;
 			}
+			};
 
+			requestLanguages.onerror = function() {
+			self.error = "Error while calling /languages";
+			self.loading = false;
+			};
 
-	  },
-	  computed: {
-	  	requestCode: function(){
-	  		return ['const res = await fetch("' + this.BaseUrl + '/translate", {',
-'	method: "POST",',
-'	body: JSON.stringify({',
-'		q: "' + this.$options.filters.escape(this.inputText) + '",',
-'		source: "' + this.$options.filters.escape(this.sourceLang) + '",',
-'		target: "' + this.$options.filters.escape(this.targetLang) + '"',
-'	}),',
-'	headers: { "Content-Type": "application/json" }',
-'});',
-'',
-'console.log(await res.json());'].join("\n");
-	  	}
-	  },
-	  filters: {
-	  	escape: function(v){
-	  		return v.replace('"', '\\\"');
-	  	},
-	  	highlight: function(v){
-	  		return Prism.highlight(v, Prism.languages.javascript, 'javascript');
-	  	}
-	  },
-	  methods: {
-	  	abortPreviousTransRequest: function(){
-	  		if (this.transRequest){
-	  			this.transRequest.abort();
-	  			this.transRequest = null;
-	  		}
-	  	},
-	  	swapLangs: function(){
-	  		var t = this.sourceLang;
-	  		this.sourceLang = this.targetLang;
-	  		this.targetLang = t;
-	  		this.inputText = this.translatedText;
-	  		this.translatedText = "";
-	  		this.handleInput();
-	  	},
-	  	dismissError: function(){
-	  		this.error = '';
-	  	},
-	  	handleInput: function(e){
-	  		if (this.timeout) clearTimeout(this.timeout);
-	  		this.timeout = null;
-
-	  		if (this.inputText === ""){
-	  			this.translatedText = "";
-	  			this.output = "";
-	  			this.abortPreviousTransRequest();
-	  			this.loadingTranslation = false;
-	  			return;
-	  		}
-
-	  		var self = this;
-
-	  		self.loadingTranslation = true;
-	  		this.timeout = setTimeout(function(){
-	  			self.abortPreviousTransRequest();
-
-	  			var request = new XMLHttpRequest();
-	  			self.transRequest = request;
-
-	  			var data = new FormData();
-	  			data.append("q", self.inputText);
-	  			data.append("source", self.sourceLang);
-	  			data.append("target", self.targetLang);
-				data.append("api_key", localStorage.getItem("api_key") || "");
-
-				request.open('POST', BaseUrl + '/translate', true);
-
-				request.onload = function() {
-				  try{
-				  	var res = JSON.parse(this.response);
-					// Success!
-					if (res.translatedText !== undefined){
-						self.translatedText = res.translatedText;
-					    self.loadingTranslation = false;
-					    self.output = JSON.stringify(res, null, 4);
-					}else{
-						throw new Error(res.error || "Unknown error");
-					}
-				  }catch(e){
- 					self.error = e.message;
- 					self.loadingTranslation = false;
-				  }
-				};
-
-				request.onerror = function() {
-				  self.error = "Error while calling /translate";
-				  self.loadingTranslation = false;
-				};
-
-				request.send(data);
-	  		}, {{ frontendTimeout }});
-	  	},
-
-		copyText: function(e){
-			e.preventDefault();
-			this.$refs.translatedTextarea.select();
-			this.$refs.translatedTextarea.setSelectionRange(0, 9999999); /* For mobile devices */
-			document.execCommand("copy");
-
-			if (this.copyTextLabel === "Copy Text"){
-				this.copyTextLabel = "Copied!";
-				var self = this;
-				setTimeout(function(){
-					self.copyTextLabel = "Copy Text";
-				}, 1500);
+			requestLanguages.send();
+		},
+		updated: function(){
+				M.FormSelect.init(this.$refs.sourceLangDropdown);
+				M.FormSelect.init(this.$refs.targetLangDropdown);
+				if (this.inputText === ""){
+					this.$refs.inputTextarea.style.height = this.inputTextareaHeight + "px";
+					this.$refs.translatedTextarea.style.height = this.inputTextareaHeight + "px";
+				}else{
+					this.$refs.inputTextarea.style.height = this.$refs.translatedTextarea.style.height = "1px";
+					this.$refs.inputTextarea.style.height = Math.max(this.inputTextareaHeight, this.$refs.inputTextarea.scrollHeight + 32) + "px";
+					this.$refs.translatedTextarea.style.height = Math.max(this.inputTextareaHeight, this.$refs.translatedTextarea.scrollHeight + 32) + "px";
+				}
+
+				if (this.charactersLimit !== -1 && this.inputText.length >= this.charactersLimit){
+					this.inputText = this.inputText.substring(0, this.charactersLimit);
+				}
+
+		},
+		computed: {
+			requestCode: function(){
+				return ['const res = await fetch("' + this.BaseUrl + '/translate", {',
+	'	method: "POST",',
+	'	body: JSON.stringify({',
+	'		q: "' + this.$options.filters.escape(this.inputText) + '",',
+	'		source: "' + this.$options.filters.escape(this.sourceLang) + '",',
+	'		target: "' + this.$options.filters.escape(this.targetLang) + '"',
+	'	}),',
+	'	headers: { "Content-Type": "application/json" }',
+	'});',
+	'',
+	'console.log(await res.json());'].join("\n");
 			}
 		},
+		filters: {
+			escape: function(v){
+				return v.replace('"', '\\\"');
+			},
+			highlight: function(v){
+				return Prism.highlight(v, Prism.languages.javascript, 'javascript');
+			}
+		},
+		methods: {
+			abortPreviousTransRequest: function(){
+				if (this.transRequest){
+					this.transRequest.abort();
+					this.transRequest = null;
+				}
+			},
+			swapLangs: function(){
+				var t = this.sourceLang;
+				this.sourceLang = this.targetLang;
+				this.targetLang = t;
+				this.inputText = this.translatedText;
+				this.translatedText = "";
+				this.handleInput();
+			},
+			dismissError: function(){
+				this.error = '';
+			},
+			handleInput: function(e){
+				if (this.timeout) clearTimeout(this.timeout);
+				this.timeout = null;
+
+				if (this.inputText === ""){
+					this.translatedText = "";
+					this.output = "";
+					this.abortPreviousTransRequest();
+					this.loadingTranslation = false;
+					return;
+				}
 
-		deleteText: function(e){
-			e.preventDefault();
-			this.inputText = this.translatedText = "";
+				var self = this;
+
+				self.loadingTranslation = true;
+				this.timeout = setTimeout(function(){
+					self.abortPreviousTransRequest();
+
+					var request = new XMLHttpRequest();
+					self.transRequest = request;
+
+					var data = new FormData();
+					data.append("q", self.inputText);
+					data.append("source", self.sourceLang);
+					data.append("target", self.targetLang);
+					data.append("api_key", localStorage.getItem("api_key") || "");
+
+					request.open('POST', BaseUrl + '/translate', true);
+
+					request.onload = function() {
+					try{
+						var res = JSON.parse(this.response);
+						// Success!
+						if (res.translatedText !== undefined){
+							self.translatedText = res.translatedText;
+							self.loadingTranslation = false;
+							self.output = JSON.stringify(res, null, 4);
+						}else{
+							throw new Error(res.error || "Unknown error");
+						}
+					}catch(e){
+						self.error = e.message;
+						self.loadingTranslation = false;
+					}
+					};
+
+					request.onerror = function() {
+					self.error = "Error while calling /translate";
+					self.loadingTranslation = false;
+					};
+
+					request.send(data);
+				}, {{ frontendTimeout }});
+			},
+
+			copyText: function(e){
+				e.preventDefault();
+				this.$refs.translatedTextarea.select();
+				this.$refs.translatedTextarea.setSelectionRange(0, 9999999); /* For mobile devices */
+				document.execCommand("copy");
+
+				if (this.copyTextLabel === "Copy text"){
+					this.copyTextLabel = "Copied";
+					var self = this;
+					setTimeout(function(){
+						self.copyTextLabel = "Copy text";
+					}, 1500);
+				}
+			},
+
+			deleteText: function(e){
+				e.preventDefault();
+				this.inputText = this.translatedText = "";
+			}
 		}
-	  }
-	});
+		});
 
-});
+	});
 
-function setApiKey(){
-    var prevKey = localStorage.getItem("api_key") || "";
-    var newKey = "";
-    newKey = window.prompt("Type in your API Key. If you need an API key, contact the server operator.", prevKey);
-    if (newKey === null) newKey = "";
+	function setApiKey(){
+		var prevKey = localStorage.getItem("api_key") || "";
+		var newKey = "";
+		newKey = window.prompt("Type in your API Key. If you need an API key, contact the server operator.", prevKey);
+		if (newKey === null) newKey = "";
 
-	localStorage.setItem("api_key", newKey);
-}
-// @license-end
-</script>
+		localStorage.setItem("api_key", newKey);
+	}
+	// @license-end
+	</script>
 </body>
 </html>