// ==UserScript== // @name Wayfarer Translate // @version 0.3.3 // @description Add translate option to Wayfarer // @namespace https://gitlab.com/NvlblNm/wayfarer/ // @downloadURL https://gitlab.com/NvlblNm/wayfarer/raw/master/wayfarer-translate.user.js // @homepageURL https://gitlab.com/NvlblNm/wayfarer/ // @match https://wayfarer.nianticlabs.com/* // ==/UserScript== /* eslint-env es6 */ /* eslint no-var: "error" */ function init() { let tryNumber = 15 let translateButton let candidate const SPACING = '\r\n\r\n' let engine = localStorage['translate-engine'] if (!engine) { engine = 'Google' localStorage['translate-engine'] = engine } /** * Overwrite the open method of the XMLHttpRequest.prototype to intercept the server calls */ ;(function (open) { XMLHttpRequest.prototype.open = function (method, url) { if (url === '/api/v1/vault/review') { if (method === 'GET') { this.addEventListener('load', parseCandidate, false) } if (method === 'POST') { hideButton() } } open.apply(this, arguments) } })(XMLHttpRequest.prototype.open) addCss() function parseCandidate(e) { try { const response = this.response const json = JSON.parse(response) if (!json) { console.log(response) alert('Failed to parse response from Wayfarer') return } // ignore if it's related to captchas if (json.captcha) { return } if (json.code !== 'OK') { return } candidate = json.result if (!candidate) { console.log(json) alert("Wayfarer's response didn't include a candidate.") return } addTranslateButton() } catch (e) { console.log(e) // eslint-disable-line no-console } } function getTranslatorLink() { switch (engine) { case 'Google': return 'https://translate.google.com/?sl=auto&q=' default: return ( 'https://www.deepl.com/translator#auto/' + navigator.language + '/' ) } } function createButton(ref) { if (!translateButton) { const div = document.createElement('div') div.className = 'wayfarertranslate' const link = document.createElement('a') link.className = '' link.title = 'Translate nomination' link.innerHTML = '' link.target = '_blank' const select = document.createElement('select') select.title = 'Select translation engine' const engines = [ { name: 'Google', title: 'Google Translate' }, { name: 'DeepL', title: 'DeepL Translate' } ] select.innerHTML = engines .map( (item) => `` ) .join('') select.addEventListener('change', function () { engine = select.value localStorage['translate-engine'] = engine link.href = getTranslatorLink() + encodeURIComponent(link.dataset.text) }) div.appendChild(link) div.appendChild(select) translateButton = div } const container = ref.parentNode.parentNode if (!container.contains(translateButton)) { container.appendChild(translateButton) } } function addTranslateButton() { const ref = document.querySelector('wf-logo') if (!ref) { if (tryNumber === 0) { document .querySelector('body') .insertAdjacentHTML( 'afterBegin', '
Wayfarer Translate initialization failed, refresh page
' ) return } setTimeout(addTranslateButton, 1000) tryNumber-- return } let text = '' if (candidate.type === 'NEW') { text = candidate.title + SPACING + candidate.description + SPACING + candidate.statement } if (candidate.type === 'EDIT') { const title = candidate.title || candidate.titleEdits.map((d) => d.value).join(SPACING) const description = candidate.description || candidate.descriptionEdits.map((d) => d.value).join(SPACING) text = title + SPACING + SPACING + description } if (candidate.type === 'PHOTO') { text = candidate.title + SPACING + candidate.description } if (text !== '') { createButton(ref) const link = translateButton.querySelector('a') link.dataset.text = text link.href = getTranslatorLink() + encodeURIComponent(text) translateButton.classList.add('wayfarertranslate__visible') } } function hideButton() { translateButton.classList.remove('wayfarertranslate__visible') } function addCss() { const css = ` .wayfarertranslate { color: #333; margin-left: 2em; padding-top: 0.3em; text-align: center; display: none; } .wayfarertranslate__visible { display: inline; } .wayfarertranslate svg { width: 24px; height: 24px; filter: none; fill: currentColor; margin: 0 auto; } .dark .wayfarertranslate { color: #ddd; } .dark .wayfarertranslate select, .dark .wayfarertranslate option { background: #000; } ` const style = document.createElement('style') style.type = 'text/css' style.innerHTML = css document.querySelector('head').appendChild(style) } } init()