├── .gitignore ├── README.md ├── icon.png ├── manifest.json └── src ├── content ├── content.css └── content.js └── options ├── options.html └── options.js /.gitignore: -------------------------------------------------------------------------------- 1 | /presentation -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Currently, this project is not working. But new improvements are coming soon! 3 | 4 | > # Universal Word 5 | > 6 | > ![perfect](https://user-images.githubusercontent.com/16020123/31504060-174ac44e-af7a-11e7-9a4d-55d949de1240.gif) 7 | > 8 | > src="https://camo.githubusercontent.com/bd0218ae6d0e95a38e8f4a73a70ad9d4b0ebda23/68747470733a2f2f73332d75732d776573742d312e616d617a6f6e6177732e636f6d2f70617472656f6e2d7265776172642d696d616765732f313533373730342e706e67"> 10 | > 11 | > 12 | > # 🥇 Gold Server Supporter * [Adem İlter](https://github.com/ademilter) 13 | > # 🥉 Bronze Server Supporter * [Anıl İyidoğan](https://github.com/aniliyidogan) 14 | > 15 | > ## Dil Seçin / Select Language 16 | > * [Türkçe](#-türkçe) 17 | > * [English](#english) 18 | > 19 | > ## 🇹🇷 Türkçe 20 | > 21 | > ### 📰 İncelemeler src="https://pbs.twimg.com/profile_images/661545729584943104/fsIId8WQ.png" 23 | > height="150"> 24 | > 25 | > ### 🙄 Problem Youtube'da İngilizce alt yazılı video izlerken bilmediğiniz sözcük gördüğünüz zaman videoyu durdurup her sözcüğün 26 | > çevirisine bakmak bazen can sıkıcı olabilir. 27 | > 28 | > 29 | > ![](https://user-images.githubusercontent.com/16020123/31394850-04471cdc-ade8-11e7-8c2d-dc500231ec33.gif) 30 | > 31 | > Altyazıyı youtube'dan otomatik çevirebilir fakat bu seferde anlam 32 | > bütünlüğü bozuluyor... 33 | > 34 | > 35 | > ### 🎊🎉🎈 Çözüm 36 | > 37 | > 38 | > ![](https://user-images.githubusercontent.com/16020123/31394887-188f5a6a-ade8-11e7-9883-9f26ade57830.gif) 39 | > Bu eklenti ile altyazının üzerine gelerek 3 anlama kadar sözcüğün çevirisini görebilmek mümkün! 🎊🎉🎈 40 | > 41 | > ### ⬇️ Nasıl Kurulur? 42 | > 43 | > #### Manuel Kurma 44 | > 1. [Buradan](https://github.com/yasinguzel/universal-word/releases/download/v1.2.1/universal-wordv1.2.1.zip) 45 | > indirin 46 | > 2. ZIP dosyasını açın 47 | > 3. Dosyayı sürükleyip bırakın -> Chrome Extensions (chrome://extensions/) 48 | > 49 | > #### Chrome Eklenti Mağazasından Kurma 50 | > 1. [Buradan](https://chrome.google.com/webstore/detail/universal-word/gpdfbmcmghechfppnckabnhojmogdifl?hl=en) 51 | > direkt yükleyebilirsiniz. 52 | > 53 | > ### ⚙️ Nasıl Çalışır? 54 | > #### 🏁 Nasıl Çalıştırılmaya Başlanır ? Alt yazı ekranda gözüktükten sonra `alt+shift+t` tuş kombinasyonuna basmanız yeterli. Daha sonra 55 | > alt yazının içindeki çevirisini görmek istediğiniz sözcüğün üzerine 56 | > gelerek çevirisini görebilirsiniz eklenti sizin için videoyu otomatik 57 | > olarak durduracaktır. 58 | > #### 👅 Nasıl Dil Ayarlanır ? 59 | > 1. Ayarlar sayfasına gidin. 60 | > ![](https://user-images.githubusercontent.com/16020123/31394709-aaac26d6-ade7-11e7-8fa4-b08d9a3042da.png) 61 | > 62 | > 2.İstediğiniz dili seçin ardından "save" butonuna basın. 63 | > ![](https://user-images.githubusercontent.com/16020123/31394736-ba99037a-ade7-11e7-9e60-3a457bb6d607.png) 64 | > 65 | > ### 📝 Yapılacaklar 66 | > 67 | > - [x] Dil seçeneği eklenecek. 68 | > - [x] İngilizce README hazırlanacak. 69 | > - [ ] Kısayol değiştirme seçeneği eklenecek. 70 | > - [ ] API'ye gönderilen çoğul İngilizce sözcükler tekil yapılıp gönderilecek. 71 | > 72 | > ### 👏 Teşekkürler Çeviri alt yapısını ücretsiz bir şekilde sağlayan [Glosbe](https://glosbe.com/) 'ye teşekkürler. 73 | > 74 | > ## English 75 | > 76 | > ### 📰 Reviews 77 | > 78 | > src="https://pbs.twimg.com/profile_images/661545729584943104/fsIId8WQ.png" 80 | > height="150"> 81 | > 82 | > ### 🙄 Problem When you watching the video on youtube which has different language subtitle, stop the video for each word which you 83 | > don't know. That can be annoying. 84 | > 85 | > 86 | > ![](https://user-images.githubusercontent.com/16020123/31394850-04471cdc-ade8-11e7-8c2d-dc500231ec33.gif) 87 | > 88 | > Youtube can translate the subtitle but that will corrupt the 89 | > integrity of meaning. 90 | > 91 | > ### 🎊🎉🎈 Solution 92 | > 93 | > 94 | > ![](https://user-images.githubusercontent.com/16020123/31394887-188f5a6a-ade8-11e7-9883-9f26ade57830.gif) 95 | > That extension can easily translate a word in the subtitle to multiple languages. 🎊🎉🎈 96 | > 97 | > ### ⬇️ How to set up? 98 | > 99 | > #### Manuel 100 | > 1. [Here](https://github.com/yasinguzel/universal-word/releases/download/v1.2.1/universal-wordv1.2.1.zip) 101 | > download 102 | > 2. Open ZIP file 103 | > 3. Drag and drop -> Chrome Extensions (chrome://extensions/) 104 | > 105 | > #### Set up via Chrome extension store 106 | > 1. [Here](https://chrome.google.com/webstore/detail/universal-word/gpdfbmcmghechfppnckabnhojmogdifl?hl=en) 107 | > you can directly set up 108 | > 109 | > ### ⚙️ How to work? #### 🏁 How to use? * After you see the subtitle press the `alt+shift+t` key combination. * Move the mouse 110 | > cursor to a word which you want to translate then it translates it. 111 | > Video will pause automatically. 112 | > 113 | > #### 👅 How to set up language? 114 | > 1. Go to the options page. 115 | > 116 | > 117 | > ![](https://user-images.githubusercontent.com/16020123/31394709-aaac26d6-ade7-11e7-8fa4-b08d9a3042da.png) 118 | > 119 | > 2. Select language then click "save" button. 120 | > 121 | > 122 | > ![](https://user-images.githubusercontent.com/16020123/31394736-ba99037a-ade7-11e7-9e60-3a457bb6d607.png) 123 | > 124 | > ### 👏 Thanks Glosbe Thanks [Glosbe](https://glosbe.com/) for API. 125 | > 126 | > ### 📝 Todo 127 | > 128 | > - [ ] Added option for change shourtcut. 129 | > - [ ] Make app work again. :D 130 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasinguzel/universal-word/ea1cba06975c2112416baa68b55634bb31809a21/icon.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | 4 | "name": "Universal Word", 5 | "description": "Translate a word easily in the youtube subtitle", 6 | "version": "1.2.1", 7 | "options_ui": { 8 | "page": "src/options/options.html", 9 | "chrome_style": true, 10 | "open_in_tab": true 11 | }, 12 | 13 | "content_scripts": [{ 14 | "matches": ["http://*/*", "https://*/*"], 15 | "css": ["src/content/content.css"], 16 | "js": ["src/content/content.js"], 17 | "all_frames": true 18 | }], 19 | 20 | "permissions": [ 21 | "storage" 22 | ], 23 | 24 | "browser_action": { 25 | "default_icon": "icon.png" 26 | } 27 | } -------------------------------------------------------------------------------- /src/content/content.css: -------------------------------------------------------------------------------- 1 | [data-tooltip] { 2 | position: relative; 3 | z-index: 2; 4 | cursor: pointer; 5 | } 6 | 7 | [data-tooltip]:before, 8 | [data-tooltip]:after { 9 | visibility: hidden; 10 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 11 | filter: progid: DXImageTransform.Microsoft.Alpha(Opacity=0); 12 | opacity: 0; 13 | pointer-events: none; 14 | } 15 | 16 | [data-tooltip]:before { 17 | position: absolute; 18 | bottom: 150%; 19 | left: 50%; 20 | margin-bottom: 5px; 21 | margin-left: -80px; 22 | padding: 7px; 23 | width: 160px; 24 | -webkit-border-radius: 3px; 25 | -moz-border-radius: 3px; 26 | border-radius: 3px; 27 | background-color: #000; 28 | background-color: hsla(0, 0%, 20%, 0.9); 29 | color: #fff; 30 | content: attr(data-tooltip); 31 | text-align: center; 32 | font-size: 14px; 33 | line-height: 1.2; 34 | } 35 | 36 | [data-tooltip]:after { 37 | position: absolute; 38 | bottom: 150%; 39 | left: 50%; 40 | margin-left: -5px; 41 | width: 0; 42 | border-top: 5px solid #000; 43 | border-top: 5px solid hsla(0, 0%, 20%, 0.9); 44 | border-right: 5px solid transparent; 45 | border-left: 5px solid transparent; 46 | content: " "; 47 | font-size: 0; 48 | line-height: 0; 49 | } 50 | 51 | [data-tooltip]:hover:before, 52 | [data-tooltip]:hover:after { 53 | visibility: visible; 54 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 55 | filter: progid: DXImageTransform.Microsoft.Alpha(Opacity=100); 56 | opacity: 1; 57 | } -------------------------------------------------------------------------------- /src/content/content.js: -------------------------------------------------------------------------------- 1 | let from, dest; 2 | 3 | function KeyPress(e) { 4 | var evtobj = window.event ? event : e 5 | if (evtobj.keyCode == 84 && evtobj.altKey && evtobj.shiftKey) { 6 | chrome.storage.sync.get({ 7 | from: "eng", 8 | dest: "tur" 9 | }, (items) => { 10 | from = items.from; 11 | dest = items.dest; 12 | main(); 13 | }) 14 | } 15 | } 16 | 17 | async function fetchTranslateResult(from, dest, phrase) { 18 | const response = await fetch( 19 | "https://glosbe.com/gapi/translate?from=" + 20 | from + 21 | "&dest=" + 22 | dest + 23 | "&format=json&phrase=" + 24 | phrase 25 | ); 26 | 27 | const data = await response.json(); 28 | 29 | let threeResult = ""; 30 | 31 | for (let index = 0; index < 3; index++) { 32 | if ( 33 | data.tuc[index] && 34 | data.tuc[index].phrase && 35 | data.tuc[index].phrase.text 36 | ) { 37 | threeResult += " " + (index + 1) + ". " + data.tuc[index].phrase.text; 38 | } else if (index === 0) { 39 | threeResult = "no result"; 40 | } 41 | } 42 | 43 | return threeResult; 44 | } 45 | 46 | function specialCharacterEncode(specialCharacter) { 47 | specialCharacter = specialCharacter.split(""); 48 | var index = specialCharacter.indexOf("'"); 49 | specialCharacter[index] = "%27"; 50 | specialCharacter = specialCharacter.join(""); 51 | return specialCharacter; 52 | } 53 | 54 | function main() { 55 | let subtitleWrapper = document.getElementById("caption-window-1"); 56 | 57 | if (!subtitleWrapper) { 58 | subtitleWrapper = document.getElementById("caption-window-_0"); 59 | } 60 | 61 | const video = document.getElementsByTagName("video")[0]; 62 | 63 | subtitleWrapper.addEventListener("mouseenter", () => { 64 | 65 | video.pause(); 66 | 67 | const subtitle = document.getElementsByClassName("captions-text")[0]; 68 | const subtitleArray = subtitle.firstChild.textContent.trim().split(/\s+/); 69 | const inSubtitle = subtitle.firstChild, 70 | style = window.getComputedStyle(inSubtitle), 71 | firstFontSize = style.getPropertyValue("font-size"); 72 | 73 | inSubtitle.innerHTML = ""; 74 | 75 | subtitleArray.map((word, index) => { 76 | 77 | const span = document.createElement("SPAN"); 78 | const textnode = document.createTextNode(" " + word); 79 | 80 | span.appendChild(textnode); 81 | 82 | inSubtitle.appendChild(span); 83 | 84 | span.setAttribute("data-tooltip", "Loading..."); 85 | 86 | span.addEventListener("mouseenter", () => { 87 | 88 | const howMuchPxGrow = 5; 89 | let newFontSize = parseInt(firstFontSize) + howMuchPxGrow; 90 | 91 | newFontSize += "px"; 92 | span.style.fontSize = newFontSize; 93 | 94 | if (word.includes("'")) { 95 | word = specialCharacterEncode(word); 96 | } 97 | 98 | const result = fetchTranslateResult(from, dest, word); 99 | 100 | result.then(translatedWords => 101 | span.setAttribute("data-tooltip", translatedWords) 102 | ); 103 | }); 104 | 105 | span.addEventListener("mouseleave", () => { 106 | span.style.fontSize = firstFontSize; 107 | }); 108 | }); 109 | }); 110 | 111 | subtitleWrapper.addEventListener("mouseleave", () => { 112 | video.play(); 113 | }); 114 | } 115 | 116 | document.onkeydown = KeyPress; -------------------------------------------------------------------------------- /src/options/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Universal Word Options 6 | 30 | 31 | 32 | 33 |
34 |
From:
35 | 36 |
Dest:
37 | 38 |
39 | 40 |
41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/options/options.js: -------------------------------------------------------------------------------- 1 | async function fetchISO6393() { 2 | const response = await fetch( 3 | "https://gist.githubusercontent.com/yasinguzel/4f62dccc3b4760f4b0b1c830d9c99fb1/raw/cbecc380bea16621a12b7fbc03ebcdbc44516f50/ISO6393.json" 4 | ); 5 | 6 | const data = await response.json(); 7 | 8 | return data; 9 | } 10 | 11 | function addedISO3933Optionss(select, name, value) { 12 | let option = document.createElement("option"); 13 | let text = document.createTextNode(name); 14 | 15 | option.appendChild(text); 16 | option.value = value; 17 | 18 | select.appendChild(option); 19 | } 20 | 21 | function saveOptions() { 22 | let from = document.getElementById("from").value; 23 | let dest = document.getElementById("dest").value; 24 | 25 | chrome.storage.sync.set({ 26 | from: from, 27 | dest: dest 28 | }, () => { 29 | let status = document.getElementById('status'); 30 | status.textContent = 'Options saved.'; 31 | setTimeout(function () { 32 | status.textContent = ''; 33 | }, 750); 34 | }) 35 | } 36 | 37 | function restoreOptions() { 38 | chrome.storage.sync.get({ 39 | from: "eng", 40 | dest: "tur" 41 | }, (items) => { 42 | document.getElementById("from").value = items.from; 43 | document.getElementById("dest").value = items.dest; 44 | }) 45 | } 46 | 47 | let fromSelect = document.getElementById("from"); 48 | let destSelect = document.getElementById("dest"); 49 | 50 | fetchISO6393().then((iso6393Codes) => { 51 | Object.values(iso6393Codes).map((iso6393Code) => { 52 | addedISO3933Optionss(fromSelect, iso6393Code.name, iso6393Code.iso6393); 53 | addedISO3933Optionss(destSelect, iso6393Code.name, iso6393Code.iso6393); 54 | }) 55 | }).then(() => { 56 | restoreOptions(); 57 | }) 58 | 59 | document.getElementById("save").addEventListener("click", saveOptions); --------------------------------------------------------------------------------