diff --git a/src/i18n/en-US.properties b/src/i18n/en-US.properties index 73b44ed6c..a65189b04 100644 --- a/src/i18n/en-US.properties +++ b/src/i18n/en-US.properties @@ -150,3 +150,23 @@ notification_annotation_mode=Click anywhere to add a comment to the document 360_images=360-degree images # 3-dimensional model file type 3d_models=3D models + +# Languages +chinese=Chinese +danish=Danish +dutch=Dutch +english=English +finnish=Finnish +french=French +german=German +hebrew=Hebrew +italian=Italian +japanese=Japanese +korean=Korean +norwegian=Norwegian +polish=Polish +portuguese=Portuguese +russian=Russian +spanish=Spanish +swedish=Swedish +turkish=Turkish diff --git a/src/lib/lang.js b/src/lib/lang.js new file mode 100644 index 000000000..ed0807a9b --- /dev/null +++ b/src/lib/lang.js @@ -0,0 +1,53 @@ +const languageMap = { + chi: __('chinese'), + zh: __('chinese'), + zho: __('chinese'), + da: __('danish'), + dan: __('danish'), + dut: __('dutch'), + nl: __('dutch'), + nld: __('dutch'), + en: __('english'), + eng: __('english'), + fi: __('finnish'), + fin: __('finnish'), + fr: __('french'), + fra: __('french'), + fre: __('french'), + de: __('german'), + deu: __('german'), + ger: __('german'), + he: __('hebrew'), + heb: __('hebrew'), + it: __('italian'), + ita: __('italian'), + ja: __('japanese'), + jpn: __('japanese'), + ko: __('korean'), + kor: __('korean'), + no: __('norwegian'), + nor: __('norwegian'), + pl: __('polish'), + pol: __('polish'), + por: __('portuguese'), + pt: __('portuguese'), + ru: __('russian'), + rus: __('russian'), + es: __('spanish'), + spa: __('spanish'), + sv: __('swedish'), + swe: __('swedish'), + tr: __('turkish'), + tur: __('turkish') +}; + +/** + * Returns a localized language name, given an ISO-639-1/2/3/5 code: + * https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes + * + * @param {string} iso639Code - a 2 or 3-char language code per https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes + * @return {string} Returns the localized name of language represented by iso639Code + */ +export default function getLanguageName(iso639Code) { + return languageMap[iso639Code.toLowerCase()]; +} diff --git a/src/lib/viewers/media/DashViewer.js b/src/lib/viewers/media/DashViewer.js index 41ad4d018..d00ee7a0a 100644 --- a/src/lib/viewers/media/DashViewer.js +++ b/src/lib/viewers/media/DashViewer.js @@ -6,6 +6,7 @@ import { get } from '../../util'; import { getRepresentation } from '../../file'; import { MEDIA_STATIC_ASSETS_VERSION } from '../../constants'; import './Dash.scss'; +import getLanguageName from '../../lang'; const CSS_CLASS_DASH = 'bp-media-dash'; const CSS_CLASS_HD = 'bp-media-controls-is-hd'; @@ -312,7 +313,7 @@ class DashViewer extends VideoBaseViewer { loadSubtitles() { this.textTracks = this.player.getTextTracks().sort((track1, track2) => track1.id - track2.id); if (this.textTracks.length > 0) { - this.mediaControls.initSubtitles(this.textTracks.map((track) => track.language)); + this.mediaControls.initSubtitles(this.textTracks.map((track) => getLanguageName(track.language) || track.language)); } } /** diff --git a/src/lib/viewers/media/__tests__/DashViewer-test.js b/src/lib/viewers/media/__tests__/DashViewer-test.js index d382dfebc..4c3b34e86 100644 --- a/src/lib/viewers/media/__tests__/DashViewer-test.js +++ b/src/lib/viewers/media/__tests__/DashViewer-test.js @@ -450,25 +450,67 @@ describe('lib/viewers/media/DashViewer', () => { }); describe('loadSubtitles()', () => { - it('should initialize subtitles in sorted order if there are available subtitles', () => { - const english = { language: 'English', id: 5 }; - const russian = { language: 'Russian', id: 4 }; - const spanish = { language: 'Spanish', id: 6 }; - const korean = { language: 'Korean', id: 3 }; - const arabic = { language: 'Arabic', id: 7 }; + it('should translate and initialize subtitles in sorted order if there are available subtitles', () => { + const english = { language: 'eng', id: 5 }; + const russian = { language: 'rus', id: 4 }; + const spanish = { language: 'spa', id: 6 }; + const korean = { language: 'kor', id: 3 }; + const chinese = { language: 'zho', id: 7 }; const subs = [ english, russian, spanish, korean, - arabic + chinese ]; stubs.mockPlayer.expects('getTextTracks').returns(subs); - stubs.mockControls.expects('initSubtitles').withArgs(['Korean', 'Russian', 'English', 'Spanish', 'Arabic']); + stubs.mockControls.expects('initSubtitles').withArgs(['Korean', 'Russian', 'English', 'Spanish', 'Chinese']); dash.loadSubtitles(); - expect(dash.textTracks).to.deep.equal([korean, russian, english, spanish, arabic]); + expect(dash.textTracks).to.deep.equal([korean, russian, english, spanish, chinese]); + }); + + it('should be robust to capital iso639 codes', () => { + const russian = { language: 'RUS', id: 3 }; + const spanish = { language: 'spa', id: 4 }; + const korean = { language: 'KoR', id: 5 }; + const chinese = { language: 'zHO', id: 6 }; + const subs = [ + russian, + spanish, + korean, + chinese + ]; + stubs.mockPlayer.expects('getTextTracks').returns(subs); + stubs.mockControls.expects('initSubtitles').withArgs(['Russian', 'Spanish', 'Korean', 'Chinese']); + + dash.loadSubtitles(); + + expect(dash.textTracks).to.deep.equal([russian, spanish, korean, chinese]); + }); + + it('should pass through unrecognized codes', () => { + const russian = { language: 'rus', id: 3 }; + const foo = { language: 'foo', id: 4 }; + const und = { language: 'und', id: 5 }; + const empty = { language: '', id: 6 }; + const doesntmatter = { language: 'doesntmatter', id: 6 }; + const zero = { language: '0', id: 7 }; + const subs = [ + russian, + foo, + und, + empty, + doesntmatter, + zero + ]; + stubs.mockPlayer.expects('getTextTracks').returns(subs); + stubs.mockControls.expects('initSubtitles').withArgs(['Russian', 'foo', 'und', '', 'doesntmatter', '0']); + + dash.loadSubtitles(); + + expect(dash.textTracks).to.deep.equal([russian, foo, und, empty, doesntmatter, zero]); }); it('should do nothing if there are no available subtitles', () => { @@ -482,10 +524,10 @@ describe('lib/viewers/media/DashViewer', () => { describe('handleSubtitle()', () => { it('should select track from front of text track list', () => { - const english = { language: 'English', id: 3 }; - const russian = { language: 'Russian', id: 4 }; - const french = { language: 'French', id: 5 }; - const spanish = { language: 'Spanish', id: 6 }; + const english = { language: 'eng', id: 3 }; + const russian = { language: 'rus', id: 4 }; + const french = { language: 'fra', id: 5 }; + const spanish = { language: 'spa', id: 6 }; dash.textTracks = [ english, russian, @@ -498,14 +540,14 @@ describe('lib/viewers/media/DashViewer', () => { dash.handleSubtitle(); - expect(stubs.emit).to.be.calledWith('subtitlechange', 'English'); + expect(stubs.emit).to.be.calledWith('subtitlechange', 'eng'); }); it('should select track from end of text track list', () => { - const english = { language: 'English', id: 3 }; - const russian = { language: 'Russian', id: 4 }; - const french = { language: 'French', id: 5 }; - const spanish = { language: 'Spanish', id: 6 }; + const english = { language: 'eng', id: 3 }; + const russian = { language: 'rus', id: 4 }; + const french = { language: 'fre', id: 5 }; + const spanish = { language: 'spa', id: 6 }; dash.textTracks = [ english, russian, @@ -518,14 +560,14 @@ describe('lib/viewers/media/DashViewer', () => { dash.handleSubtitle(); - expect(stubs.emit).to.be.calledWith('subtitlechange', 'Spanish'); + expect(stubs.emit).to.be.calledWith('subtitlechange', 'spa'); }); it('should select track from middle of text track list', () => { - const english = { language: 'English', id: 3 }; - const russian = { language: 'Russian', id: 4 }; - const french = { language: 'French', id: 5 }; - const spanish = { language: 'Spanish', id: 6 }; + const english = { language: 'eng', id: 3 }; + const russian = { language: 'rus', id: 4 }; + const french = { language: 'fre', id: 5 }; + const spanish = { language: 'spa', id: 6 }; dash.textTracks = [ english, russian, @@ -538,14 +580,14 @@ describe('lib/viewers/media/DashViewer', () => { dash.handleSubtitle(); - expect(stubs.emit).to.be.calledWith('subtitlechange', 'Russian'); + expect(stubs.emit).to.be.calledWith('subtitlechange', 'rus'); }); it('should turn off subtitles when idx out of bounds', () => { - const english = { language: 'English', id: 3 }; - const russian = { language: 'Russian', id: 4 }; - const french = { language: 'French', id: 5 }; - const spanish = { language: 'Spanish', id: 6 }; + const english = { language: 'eng', id: 3 }; + const russian = { language: 'rus', id: 4 }; + const french = { language: 'fre', id: 5 }; + const spanish = { language: 'spa', id: 6 }; dash.textTracks = [ english, russian,