1const PUBLIC_API_KEYS = { 2 'boat-ed': 'd94b80d7f0654b4ab83cd4bb02e84cb0', 3 "examenbateau": '29f7623970084cab8fde3fa9d609b520', 4 'hunter-ed': '5dd8ad4352394aebbed677e036880581', 5 'huntercourse': '8b05d970de22419f9d66785dde26ce30', 6 'boaterexam': '4d5ecd43489d45178d3be6ffe394a330', 7 'snowmobilecourse': 'c5a30bf9bffc48879f37177b57968bee', 8 'boatsmartexam': '06708b65a2e24653ae97d9a9b9dea028' 9}; 10 11const LANGUAGE_MAPS = { 12 'en': { 13 displayCode: 'EN', 14 displayName: 'English (EN)' 15 }, 16 'es_US': { 17 displayCode: 'ES', 18 displayName: 'Español (ES)' 19 }, 20 'fr_CA': { 21 displayCode: 'FR', 22 displayName: 'Français (FR)' 23 }, 24 'iu': { 25 displayCode: 'IU', 26 displayName: 'Inuktitut (IU)' 27 } 28}; 29 30const VIMEO_MAPS = [ 31 { 32 'en': "https://player.vimeo.com/video/36145684", 33 'es_US': "https://player.vimeo.com/video/905744446" 34 }, 35 { 36 'en': "https://player.vimeo.com/video/36145600", 37 'es_US': "https://player.vimeo.com/video/905747070" 38 }, 39 { 40 'en': "https://player.vimeo.com/video/37252756", 41 'es_US': "https://player.vimeo.com/video/905747830" 42 } 43]; 44 45const hostName = window.location.hostname.split('.').filter(str => str !== "www")[0] 46 47window.liveSettings = { api_key: PUBLIC_API_KEYS[hostName] }; 48 49function initializeTransifex( 50 studentId, 51 courseId, 52 courseName, 53 courseState, 54 translationEnabled, 55 defaultLanguage, 56 allowedLanguageCodes = null 57) { 58 const iframes = window.document.querySelectorAll("iframe"); 59 60 Transifex.live.onReady(() => { 61 const lang_code = Transifex.live.getSelectedLanguageCode(); 62 63 iframes.forEach(frame => { 64 handleUpdateLanguageInFrame(frame, lang_code); 65 frame.addEventListener('load', () => hideLanguagePicker(frame.contentDocument)); 66 }); 67 }); 68 69 Transifex.live.onTranslatePage(lang_code => { 70 iframes.forEach(frame => handleUpdateLanguageInFrame(frame, lang_code)); 71 }); 72 73 Transifex.live.onFetchLanguages(async languages => {
74 let currentLanguage = Transifex.live.getSourceLanguageCode(); 75 76 if (translationEnabled) { 77 currentLanguage = await getCurrentLanguage(studentId) || Transifex.live.getSelectedLanguageCode(); 78 } else { 79 currentLanguage = defaultLanguage; 80 } 81 82 Transifex.live.translateTo(currentLanguage); 83 84 setLanguageDisplayCode(LANGUAGE_MAPS[currentLanguage].displayCode); 85 86 document.querySelectorAll('.language-selector').forEach(languageSelector => { 87 languageSelector.replaceChildren(); 88 89 for (let i = 0; i < languages.length; i++) { 90 if (allowedLanguageCodes && !allowedLanguageCodes.includes(languages[i].code)) continue; 91 92 // Skip Inuktitut and French for huntercourse 93 if (hostName === "huntercourse" && ["fr_CA", "iu"].includes(languages[i].code)) continue; 94 95 const listItem = document.createElement('li'); 96 const { displayName } = LANGUAGE_MAPS[languages[i].code]; 97 listItem.innerHTML = `<a class="dropdown-item language-selector-option" href="#" role="menuitemradio" data-code="${languages[i].code}">${displayName}</a>`; 98 languageSelector.append(listItem); 99 } 100 101 languageSelector.querySelectorAll('a').forEach(anchor => { 102 anchor.addEventListener('click', function(e) { 103 e?.preventDefault(); 104 105 const code = this.closest('[data-code]').dataset.code; 106 Transifex.live.translateTo(code, true); 107 if (!!studentId) { 108 updateStudentLanguage(code); 109 } 110 111 submitGoogleAnalyticsEvent(code, studentId, courseId, courseName, courseState); 112 }); 113 }); 114 }); 115 116 Transifex.live.onTranslatePage(lang_code => { 117 setLanguageDisplayCode(LANGUAGE_MAPS[lang_code].displayCode); 118 }); 119 }); 120} 121 122function handleUpdateLanguageInFrame(frame, lang_code) { 123 if (!lang_code) return; 124 updateVimeoUrl(frame, lang_code); 125 updateHostUrl(frame, lang_code); 126} 127 128function hideLanguagePicker(document) { 129 const languagePicker = document?.getElementById("tx-live-lang-container"); 130 if (languagePicker) { 131 languagePicker.style.display = "none"; 132 } 133} 134 135function updateVimeoUrl(frame, lang_code) { 136 const url = new URL(frame.src); 137 if (url.host !== "player.vimeo.com") return; 138 139 const vimeoMap = VIMEO_MAPS.find(map => Object.values(map).includes(url.href)); 140 if (vimeoMap && vimeoMap[lang_code]) { 141 frame.src = vimeoMap[lang_code]; 142 } 143} 144 145function updateHostUrl(frame, lang_code) { 146 const url = new URL(frame.src); 147 if (url.host !== window.location.host) return; 148 149 url.searchParams.set('lang', lang_code); 150 url.pathname = getPathForLanguage(url, lang_code); 151 frame.src = url.pathname + url.search; 152} 153 154function getPathForLanguage(url, lang_code) { 155 switch(lang_code) { 156 case "es_US": 157 return url.pathname.replace("/english/", "/spanish/"); 158 case "en": 159 return url.pathname.replace("/spanish/", "/english/"); 160 default: 161 return url.pathname 162 } 163} 164 165function setLanguageDisplayCode(displayCode) { 166 document.querySelectorAll('.language-current').forEach(el => { el.textContent = displayCode; }); 167} 168 169function csrfToken() { 170 return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); 171} 172 173function updateStudentLanguage(languageCode) { 174 fetch("/students/update_language", { 175 method: "POST", 176 headers: { 177 "Content-Type": "application/x-www-form-urlencoded", 178 "X-CSRF-Token": csrfToken() 179 }, 180 body: new URLSearchParams({ language_code: languageCode }) 181 }); 182} 183 184async function getCurrentLanguage(studentId) { 185 if (!studentId) { 186 return await getBrowserLanguage(); 187 } 188 189 const currentLanguage = await getSavedLanguage() 190 .catch(getBrowserLanguage); 191 192 if (Object.keys(LANGUAGE_MAPS).includes(currentLanguage)) { 193 return currentLanguage; 194 } 195} 196 197async function getSavedLanguage() { 198 const response = await fetch("/students/current_language"); 199 if (!response.ok) { 200 throw new Error('Current language unavailable'); 201 } 202 const data = await response.json(); 203 return data.language_code; 204} 205 206async function getBrowserLanguage() { 207 const urlParams = new URLSearchParams(window.location.search);
208 return urlParams.get('language'); 209} 210 211function submitGoogleAnalyticsEvent(languageCode, studentId, courseId, courseName, courseState) { 212 window.dataLayer.push({ 213 event: 'languageSelected', 214 selectedElement: languageCode, 215 course_name: courseName, 216 course_id: courseId, 217 student_id: studentId, 218 state: courseState 219 }); 220} 221 222function reapplyTransifexLanguage() { 223 const transifex = window.Transifex?.live; 224 if (!transifex) return; 225 226 const langCode = transifex.getSelectedLanguageCode(); 227 if (langCode) { 228 transifex.translateTo(langCode); 229 } 230} 231 232document.addEventListener("turbo:load", reapplyTransifexLanguage); 233document.addEventListener("turbo:frame-render", reapplyTransifexLanguage);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.