From e44c079302fec9a55f31c2287e86047e4feba04f Mon Sep 17 00:00:00 2001
From: Maham Akif <maham.akif@A006-00821.local>
Date: Tue, 20 Aug 2024 18:18:05 +0500
Subject: [PATCH] fix: default transcript language should match browser default

---
 .../tests/CoursePreview.test.jsx              |  5 +++++
 .../microlearning/styles/VideoDetailPage.scss |  1 +
 src/components/video/VideoJS.jsx              |  3 +++
 src/components/video/data/hooks.js            | 22 +++++++++++--------
 src/components/video/data/tests/hooks.test.js |  4 ++--
 src/components/video/data/utils.js            | 13 +++++++++++
 src/components/video/tests/VideoJS.test.jsx   |  5 +++++
 .../video/tests/VideoPlayer.test.jsx          |  5 +++++
 8 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/src/components/course/course-header/tests/CoursePreview.test.jsx b/src/components/course/course-header/tests/CoursePreview.test.jsx
index cf11e23688..9c142f9571 100644
--- a/src/components/course/course-header/tests/CoursePreview.test.jsx
+++ b/src/components/course/course-header/tests/CoursePreview.test.jsx
@@ -11,6 +11,11 @@ const imageURL = 'https://test-domain.com/test-image/id.png';
 const hlsUrl = 'https://test-domain.com/test-prefix/id.m3u8';
 const ytUrl = 'https://www.youtube.com/watch?v=oHg5SJYRHA0';
 
+jest.mock('@edx/frontend-platform/i18n', () => ({
+  ...jest.requireActual('@edx/frontend-platform/i18n'),
+  getLocale: () => 'en',
+}));
+
 describe('Course Preview Tests', () => {
   it('Renders preview image and not the video when video URL is not given.', () => {
     const { container, getByAltText } = renderWithRouter(<CoursePreview previewImage={imageURL} />);
diff --git a/src/components/microlearning/styles/VideoDetailPage.scss b/src/components/microlearning/styles/VideoDetailPage.scss
index 835aeadf6e..08c18d917f 100644
--- a/src/components/microlearning/styles/VideoDetailPage.scss
+++ b/src/components/microlearning/styles/VideoDetailPage.scss
@@ -29,6 +29,7 @@
 
   .video-player-container-with-transcript {
     display: flex;
+    padding-bottom: 55px;
   }
 
   .video-js-wrapper {
diff --git a/src/components/video/VideoJS.jsx b/src/components/video/VideoJS.jsx
index 3cb25a6e81..03eab95476 100644
--- a/src/components/video/VideoJS.jsx
+++ b/src/components/video/VideoJS.jsx
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import 'videojs-youtube';
 import videojs from 'video.js';
 import 'video.js/dist/video-js.css';
+import { getLocale } from '@edx/frontend-platform/i18n';
 import { PLAYBACK_RATES } from './data/constants';
 import { usePlayerOptions, useTranscripts } from './data';
 
@@ -14,10 +15,12 @@ require('videojs-vjstranscribe');
 const VideoJS = ({ options, onReady, customOptions }) => {
   const videoRef = useRef(null);
   const playerRef = useRef(null);
+  const siteLanguage = getLocale();
 
   const transcripts = useTranscripts({
     player: playerRef.current,
     customOptions,
+    siteLanguage,
   });
 
   const playerOptions = usePlayerOptions({
diff --git a/src/components/video/data/hooks.js b/src/components/video/data/hooks.js
index cf5100a165..a54bcdf643 100644
--- a/src/components/video/data/hooks.js
+++ b/src/components/video/data/hooks.js
@@ -2,11 +2,12 @@ import { useEffect, useState } from 'react';
 import { logError } from '@edx/frontend-platform/logging';
 
 import { fetchAndAddTranscripts } from './service';
+import { sortTextTracks } from './utils';
 
-export function useTranscripts({ player, customOptions }) {
+export function useTranscripts({ player, customOptions, siteLanguage }) {
   const shouldUseTranscripts = !!(customOptions?.showTranscripts && customOptions?.transcriptUrls);
   const [isLoading, setIsLoading] = useState(shouldUseTranscripts);
-  const [textTracks, setTextTracks] = useState([]);
+  const [textTracks, setTextTracks] = useState({});
   const [transcriptUrl, setTranscriptUrl] = useState(null);
 
   useEffect(() => {
@@ -15,12 +16,15 @@ export function useTranscripts({ player, customOptions }) {
       if (shouldUseTranscripts) {
         try {
           const result = await fetchAndAddTranscripts(customOptions.transcriptUrls, player);
-          setTextTracks(result);
-          // We are only catering to English transcripts for now as we don't have the option to change
-          // the transcript language yet.
-          if (result.en) {
-            setTranscriptUrl(result.en);
-          }
+
+          // Sort the text tracks to prioritize the site language at the top of the list.
+          // Currently, video.js selects the top language from the list of transcripts.
+          const sortedResult = sortTextTracks(result, siteLanguage);
+          setTextTracks(sortedResult);
+
+          // Default to site language, fallback to English
+          const preferredTranscript = sortedResult[siteLanguage] || sortedResult.en;
+          setTranscriptUrl(preferredTranscript);
         } catch (error) {
           logError(`Error fetching transcripts for player: ${error}`);
         } finally {
@@ -29,7 +33,7 @@ export function useTranscripts({ player, customOptions }) {
       }
     };
     fetchFn();
-  }, [customOptions?.transcriptUrls, player, shouldUseTranscripts]);
+  }, [customOptions?.transcriptUrls, player, shouldUseTranscripts, siteLanguage]);
 
   return {
     textTracks,
diff --git a/src/components/video/data/tests/hooks.test.js b/src/components/video/data/tests/hooks.test.js
index 1c0b24a2fb..da92e51a6c 100644
--- a/src/components/video/data/tests/hooks.test.js
+++ b/src/components/video/data/tests/hooks.test.js
@@ -49,7 +49,7 @@ describe('useTranscripts', () => {
 
     expect(logError).toHaveBeenCalledWith(`Error fetching transcripts for player: Error: ${errorMessage}`);
     expect(result.current.isLoading).toBe(false);
-    expect(result.current.textTracks).toEqual([]);
+    expect(result.current.textTracks).toEqual({});
     expect(result.current.transcriptUrl).toBeNull();
   });
 
@@ -64,7 +64,7 @@ describe('useTranscripts', () => {
       customOptions: customOptionsWithoutTranscripts,
     }));
 
-    expect(result.current.textTracks).toEqual([]);
+    expect(result.current.textTracks).toEqual({});
     expect(result.current.transcriptUrl).toBeNull();
   });
 });
diff --git a/src/components/video/data/utils.js b/src/components/video/data/utils.js
index d75d693e39..939348687c 100644
--- a/src/components/video/data/utils.js
+++ b/src/components/video/data/utils.js
@@ -26,3 +26,16 @@ export const createWebVttFile = (webVttContent) => {
   const blob = new Blob([webVttContent], { type: 'text/vtt' });
   return URL.createObjectURL(blob);
 };
+
+export const sortTextTracks = (tracks, siteLanguage) => {
+  const sortedKeys = Object.keys(tracks).sort((a, b) => {
+    if (a === siteLanguage) { return -1; }
+    if (b === siteLanguage) { return 1; }
+    return a.localeCompare(b);
+  });
+
+  return sortedKeys.reduce((acc, key) => {
+    acc[key] = tracks[key];
+    return acc;
+  }, {});
+};
diff --git a/src/components/video/tests/VideoJS.test.jsx b/src/components/video/tests/VideoJS.test.jsx
index c21aaf0be0..e559c25360 100644
--- a/src/components/video/tests/VideoJS.test.jsx
+++ b/src/components/video/tests/VideoJS.test.jsx
@@ -11,6 +11,11 @@ jest.mock('../data', () => ({
   usePlayerOptions: jest.fn(),
 }));
 
+jest.mock('@edx/frontend-platform/i18n', () => ({
+  ...jest.requireActual('@edx/frontend-platform/i18n'),
+  getLocale: () => 'en',
+}));
+
 const hlsUrl = 'https://test-domain.com/test-prefix/id.m3u8';
 const ytUrl = 'https://www.youtube.com/watch?v=oHg5SJYRHA0';
 
diff --git a/src/components/video/tests/VideoPlayer.test.jsx b/src/components/video/tests/VideoPlayer.test.jsx
index 61711c6108..8b1b991353 100644
--- a/src/components/video/tests/VideoPlayer.test.jsx
+++ b/src/components/video/tests/VideoPlayer.test.jsx
@@ -7,6 +7,11 @@ const hlsUrl = 'https://test-domain.com/test-prefix/id.m3u8';
 const ytUrl = 'https://www.youtube.com/watch?v=oHg5SJYRHA0';
 const mp3Url = 'https://example.com/audio.mp3';
 
+jest.mock('@edx/frontend-platform/i18n', () => ({
+  ...jest.requireActual('@edx/frontend-platform/i18n'),
+  getLocale: () => 'en',
+}));
+
 describe('Video Player component', () => {
   it('Renders Video Player components correctly for HLS videos.', async () => {
     const { container } = renderWithRouter(<VideoPlayer videoURL={hlsUrl} />);