├── .gitignore
├── coursera-subtitle-translation-to-arabic.zip
├── js
├── background.js
└── content.js
├── manifest.json
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | __MACOSX
3 |
--------------------------------------------------------------------------------
/coursera-subtitle-translation-to-arabic.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imAbdelhadi/coursera-subtitle-translation-arabic/HEAD/coursera-subtitle-translation-to-arabic.zip
--------------------------------------------------------------------------------
/js/background.js:
--------------------------------------------------------------------------------
1 | // 点击扩展图标,发送请求到当前标签页
2 | chrome.browserAction.onClicked.addListener(() => {
3 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
4 | chrome.tabs.sendMessage(tabs[0].id, {})
5 | })
6 | })
7 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Coursera Subtitle Translation to Arabic",
4 | "version": "0.0.1",
5 | "content_scripts": [
6 | {
7 | "matches": [
8 | "*://www.coursera.org/*"
9 | ],
10 | "js": [
11 | "js/content.js"
12 | ]
13 | }
14 | ],
15 | "browser_action": {},
16 | "background": {
17 | "scripts": [
18 | "js/background.js"
19 | ],
20 | "persistent": false
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 tamshadow
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > This repository is a fork of [Coursera Subtitle Translatio, made by Tamshadow](https://github.com/tamshadow/coursera-subtitle-translation).
2 |
3 |
4 |
5 | # ترجمة دورات كورسيرا - Coursera إلى اللغة العربية
6 |
7 | قم بتشغيل الترجمة ثنائية اللغة باللغتين العربية والإنجليزية لمقاطع فيديو كورسيرا.
8 |
9 | * إذا كانت الدورة تحتوي على ترجمة باللغتين العربية والإنجليزية، فافتحها مباشرة.
10 | * إذا كانت الدورة التدريبية لا تحتوي على ترجمة عربية، فسيتم تلقائيًا ترجمة Subtitle إلى العربية.
11 |
12 | ## التثبيت
13 |
14 | قم بتنزيل المشروع أو الملف التالي ([نسخة zip](https://github.com/imAbdelhadi/coursera-subtitle-translation-arabic/blob/main/coursera-subtitle-translation-to-arabic.zip?raw=true))، فك الضغط عنه، افتح اعدادات Chrome وفعّل اعدادات وضع المطوّر ثم حدد (Unpack Load).
15 |
16 | ## الاستخدام
17 |
18 | انقر فوق أيقونة الامتداد في صفحة فيديو الدورة التدريبية عند تشغيل الفيديو.
19 |
20 | > يمكنك قراءة تفاصيل أكثر على مدونتي [ترجمة دورات كورسيرا - Coursera إلى اللغة العربية](https://blog.abdelhadi.org/coursera-cources-translate-to-arabic-language/).
21 |
22 | 
23 |
24 |
25 |
26 | # Coursera Subtitle Translation to Arabic
27 |
28 | Turn on bilingual subtitles in Arabic and English for Coursera course videos.
29 |
30 | * If the course has both Arabic and English subtitles, open it directly.
31 | * If the course does not have Arabic subtitles, English subtitles will be automatically translated.
32 |
33 | ## Installation
34 |
35 | Download the project, Chrome opens the extension and loads the unzipped extension (developer mode needs to be turned on)
36 |
37 | ## Use
38 |
39 | Click the extension icon on the course video page.
40 |
--------------------------------------------------------------------------------
/js/content.js:
--------------------------------------------------------------------------------
1 | async function openBilingual () {
2 | // Turn on bilingual subtitles
3 | let tracks = document.getElementsByTagName('track')
4 | let en
5 | let ArabicLang
6 | if (tracks.length) {
7 | // 1. Traverse the subtitle nodes and find Arabic and English subtitles
8 | for (let i = 0; i < tracks.length; i++) {
9 | if (tracks[i].srclang === 'en') {
10 | en = tracks[i]
11 | } else if (tracks[i].srclang === 'ar-SA') {
12 | ArabicLang = tracks[i]
13 | }
14 | }
15 | // 2. If English subtitles exist, turn on
16 | if (en) {
17 | en.track.mode = 'showing'
18 | // 3. Determine whether the Arabic subtitles exist, if they exist, open them directly
19 | if (ArabicLang) {
20 | ArabicLang.track.mode = 'showing'
21 | } else {
22 | // 4. If it does not exist, turn on translation
23 | // After Chrome is updated to 74
24 | // It seems that there is a delay between when track.mode ='showing' is set for the first time and when the cues are loaded?
25 | // temporarily use sleep to let cues have enough time to load the subtitles to ensure normal work, and solve it later
26 | await sleep(500)
27 | let cues = en.track.cues
28 | // Since the sentence-by-sentence translation requires a large number of translation APIs, the number of requests needs to be reduced
29 | const cuesTextList = getCuesTextList(cues)
30 | // Perform translation
31 | for (let i = 0; i < cuesTextList.length; i++) {
32 | getTranslation(cuesTextList[i][1], translatedText => {
33 | // Get the returned text, split according to the line break inserted before
34 | // Then determine the sequence of the cues text, which is the starting position stored before + the current relative position
35 | // Add the translated text directly after the English subtitles
36 | const translatedTextList = translatedText.split('\n\n')
37 | for (let j = 0; j < translatedTextList.length; j++) {
38 | cues[cuesTextList[i][0] + j].text += '\n' + translatedTextList[j]
39 | }
40 | })
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
47 | function sleep (ms) {
48 | return new Promise(resolve => setTimeout(resolve, ms))
49 | }
50 |
51 | function getCuesTextList (cues) {
52 | // Take out all the text content of the subtitles and integrate them into a list
53 | // Each item is a string of no more than 5000 words, (it seems that the API currently used has a 5000 word limit?)
54 | // and its starting position in cues
55 | // The returned data structure is probably [[0, text], [95, text]]
56 | let cuesTextList = []
57 | for (let i = 0; i < cues.length; i++) {
58 | if (cuesTextList.length &&
59 | cuesTextList[cuesTextList.length - 1][1].length +
60 | cues[i].text.length < 5000) {
61 | // Need to insert a delimiter (line feed) to split the translated string later
62 | // Use two newlines to split, because some video subtitles have their own newlines
63 | cuesTextList[cuesTextList.length - 1][1] += '\n\n' + cues[i].text
64 | } else {
65 | cuesTextList.push([i, cues[i].text])
66 | }
67 | }
68 | return cuesTextList
69 | }
70 |
71 | function getTranslation (words, callback) {
72 | // Translate through the Google Translate API, enter the string to be translated, and return the translated string
73 | const xhr = new XMLHttpRequest()
74 | let url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=ar&dt=t&q=${encodeURI(words)}`
75 | xhr.open('GET', url, true)
76 | xhr.responseType = 'text'
77 | xhr.onload = function () {
78 | if (xhr.readyState === xhr.DONE) {
79 | if (xhr.status === 200 || xhr.status === 304) {
80 | // The translated text returned is probably
81 | // [["مرحبا.","hello.",null,null,1],["مرحبا","hello",null,null,1]],null,"en"]
82 | // such a string
83 | // Need to splice the result into a complete string
84 | const translatedList = JSON.parse(xhr.responseText)[0]
85 | let translatedText = ''
86 | for (let i = 0; i < translatedList.length; i++) {
87 | translatedText += translatedList[i][0]
88 | }
89 | callback(translatedText)
90 | }
91 | }
92 | }
93 | xhr.send()
94 | }
95 |
96 | // Set up monitoring, if a request is received, execute the function to enable bilingual subtitles
97 | chrome.runtime.onMessage.addListener(
98 | function (request, sender) {
99 | openBilingual()
100 | }
101 | )
102 |
--------------------------------------------------------------------------------