Skip to content
Snippets Groups Projects
app.js 15.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • // @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;
    var htmlRegex = /<(.*)>.*?|<(.*)\/>/;
    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,
                savedTanslatedText: "",
                translatedText: "",
                output: "",
                charactersLimit: -1,
    
                copyTextLabel: "Copy text",
    
                suggestions: false,
                isSuggesting: false,
    
                supportedFilesFormat : [],
    
                translationType: "text",
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                inputFile: false,
                loadingFileTranslation: false,
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                translatedFileUrl: false,
    
                disableFilesTranslation: false,
    
            },
            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;
                        self.suggestions = self.settings.suggestions;
    
                        self.supportedFilesFormat = self.settings.supportedFilesFormat;
    
                        self.disableFilesTranslation = self.settings.disableFilesTranslation;
    
                    }else {
                        self.error = "Cannot load /frontend/settings";
                        self.loading = false;
                    }
                };
    
                requestSettings.onerror = function() {
                    self.error = "Error while calling /frontend/settings";
                    self.loading = false;
                };
    
                requestSettings.send();
    
                var requestLanguages = new XMLHttpRequest();
                requestLanguages.open('GET', BaseUrl + '/languages', 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;
                        }
    
                        self.loading = false;
                    } else {
                        self.error = "Cannot load /languages";
                        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 = 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);
                }
    
                // Update "selected" attribute (to overcome a vue.js limitation)
                // but properly display checkmarks on supported browsers.
                // Also change the <select> width value depending on the <option> length
                for (var i = 0; i < this.$refs.sourceLangDropdown.children.length; i++){
                    var el = this.$refs.sourceLangDropdown.children[i];
                    if (el.value === this.sourceLang){
                        el.setAttribute('selected', '');
                        this.$refs.sourceLangDropdown.style.width = getTextWidth(el.text) + 24 + 'px';
                    }else{
                        el.removeAttribute('selected');
                    }
                }
                for (var i = 0; i < this.$refs.targetLangDropdown.children.length; i++){
                    var el = this.$refs.targetLangDropdown.children[i];
                    if (el.value === this.targetLang){
                        el.setAttribute('selected', '');
                        this.$refs.targetLangDropdown.style.width = getTextWidth(el.text) + 24 + 'px';
                    }else{
                        el.removeAttribute('selected');
                    }
                }
    
            },
            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) + '",',
                        '		format: "' + (this.isHtml ? "html" : "text") + '"',
                        '	}),',
                        '	headers: { "Content-Type": "application/json" }',
                        '});',
                        '',
                        'console.log(await res.json());'].join("\n");
                },
    
                supportedFilesFormatFormatted: function() {
                    return this.supportedFilesFormat.join(', ');
                },
    
                isHtml: function(){
                    return htmlRegex.test(this.inputText);
                },
                canSendSuggestion() {
                    return this.translatedText.trim() !== "" && this.translatedText !== this.savedTanslatedText;
                }
            },
            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(e){
                    this.closeSuggestTranslation(e)
    
                    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){
                    this.closeSuggestTranslation(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("format", self.isHtml ? "html" : "text");
                        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);
                    }
                },
                suggestTranslation: function(e) {
                    e.preventDefault();
                    this.savedTanslatedText = this.translatedText
    
                    this.isSuggesting = true;
                },
                closeSuggestTranslation: function(e) {
                    this.translatedText = this.savedTanslatedText
    
                    e.preventDefault();
    
                    this.isSuggesting = false;
                },
                sendSuggestion: function(e) {
                    e.preventDefault();
    
                    var self = this;
    
                    var request = new XMLHttpRequest();
                    self.transRequest = request;
    
                    var data = new FormData();
                    data.append("q", self.inputText);
                    data.append("s", self.translatedText);
                    data.append("source", self.sourceLang);
                    data.append("target", self.targetLang);
    
                    request.open('POST', BaseUrl + '/suggest', true);
                    request.onload = function() {
                        try{
                            var res = JSON.parse(this.response);
                            if (res.success){
                                M.toast({html: 'Thanks for your correction.'})
                                self.closeSuggestTranslation(e)
                            }else{
                                throw new Error(res.error || "Unknown error");
                            }
                        }catch(e){
                            self.error = e.message;
                            self.closeSuggestTranslation(e)
                        }
                    };
    
                    request.onerror = function() {
                        self.error = "Error while calling /suggest";
                        self.loadingTranslation = false;
                    };
    
                    request.send(data);
                },
                deleteText: function(e){
                    e.preventDefault();
                    this.inputText = this.translatedText = this.output = "";
    
                },
                switchType: function(type) {
                    this.translationType = type;
    
                },
                handleInputFile: function(e) {
                    this.inputFile = e.target.files[0];
                },
                removeFile: function(e) {
                  e.preventDefault()
                  this.inputFile = false;
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                  this.translatedFileUrl = false;
    
                  this.loadingFileTranslation = false;
    
                },
                translateFile: function(e) {
                    e.preventDefault();
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                    let translateFileRequest = new XMLHttpRequest();
    
                    translateFileRequest.open("POST", BaseUrl + "/translate_file", true);
    
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                    let data = new FormData();
                    data.append("file", this.inputFile);
                    data.append("source", this.sourceLang);
                    data.append("target", this.targetLang);
                    data.append("api_key", localStorage.getItem("api_key") || "");
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
    
                    this.loadingFileTranslation = true
    
    
                    translateFileRequest.onload = function()  {
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                        if (translateFileRequest.readyState === 4 && translateFileRequest.status === 200) {
    
                            try{
                                self.loadingFileTranslation = false;
    
                                let res = JSON.parse(this.response);
                                if (res.translatedFileUrl){
                                    self.translatedFileUrl = res.translatedFileUrl;
    
                                    let link = document.createElement("a");
                                    link.target = "_blank";
                                    link.href = self.translatedFileUrl;
                                    link.click();
                                }else{
                                    throw new Error(res.error || "Unknown error");
                                }
    
                            }catch(e){
                                self.error = e.message;
                                self.loadingFileTranslation = false;
                                self.inputFile = false;
                            }
    
                    translateFileRequest.onerror = function() {
                        self.error = "Error while calling /translate_file";
                        self.loadingFileTranslation = false;
                        self.inputFile = false;
                    };
    
    
    Sébastien Thuret's avatar
    Sébastien Thuret committed
                    translateFileRequest.send(data);
    
                }
            }
        });
    
    });
    
    function getTextWidth(text) {
        var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
        var ctx = canvas.getContext("2d");
        ctx.font = 'bold 16px sans-serif';
        var textWidth = Math.ceil(ctx.measureText(text).width);
        return textWidth;
    }
    
    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