PageSourceSearch

https://www.hunter-ed.com/transifex.js?v=2026-06-22

js hunter-ed.com collected 2026-10-02 03:37:24 UTC 6,779 bytes, 233 lines download raw bytes

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.