forked from shaka-project/shaka-player
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlanguage_utils.js
176 lines (156 loc) · 6.38 KB
/
language_utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/** @license
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.ui.LanguageUtils');
goog.require('mozilla.LanguageMapping');
goog.require('shaka.util.Dom');
shaka.ui.LanguageUtils = class {
/**
* @param {!Array.<shaka.extern.Track>} tracks
* @param {!HTMLElement} langMenu
* @param {function(!shaka.extern.Track)} onTrackSelected
* @param {boolean} updateChosen
* @param {!HTMLElement} currentSelectionElement
* @param {shaka.ui.Localization} localization
* @param {shaka.ui.TrackLabelFormat} trackLabelFormat
*/
// TODO: Do the benefits of having this common code in a method still
// outweigh the complexity of the parameter list?
static updateTracks(tracks, langMenu, onTrackSelected, updateChosen,
currentSelectionElement, localization, trackLabelFormat) {
// Using array.filter(f)[0] as an alternative to array.find(f) which is
// not supported in IE11.
const activeTracks = tracks.filter((track) => {
return track.active == true;
});
const selectedTrack = activeTracks[0];
// Remove old tracks
// 1. Save the back to menu button
const backButton = shaka.ui.Utils.getFirstDescendantWithClassName(
langMenu, 'shaka-back-to-overflow-button');
// 2. Remove everything
shaka.util.Dom.removeAllChildren(langMenu);
// 3. Add the backTo Menu button back
langMenu.appendChild(backButton);
// 4. Figure out which languages have multiple roles.
const getRolesString = (track) => {
if (track.type == 'variant') {
return track.audioRoles ? track.audioRoles.join(', ') : undefined;
} else {
return track.roles.join(', ');
}
};
/** @type {!Map.<string, !Set.<string>>} */
const rolesByLanguage = new Map();
for (const track of tracks) {
if (!rolesByLanguage.has(track.language)) {
rolesByLanguage.set(track.language, new Set());
}
rolesByLanguage.get(track.language).add(getRolesString(track));
}
// 5. Add new buttons
/** @type {!Set.<string>} */
const combinationsMade = new Set();
for (const track of tracks) {
const language = track.language;
const rolesString = getRolesString(track);
const combinationName = language + ': ' + rolesString;
if (combinationsMade.has(combinationName)) {
continue;
}
combinationsMade.add(combinationName);
const button = shaka.util.Dom.createHTMLElement('button');
button.addEventListener('click', () => {
onTrackSelected(track);
});
const span = shaka.util.Dom.createHTMLElement('span');
button.appendChild(span);
span.textContent =
shaka.ui.LanguageUtils.getLanguageName(language, localization);
switch (trackLabelFormat) {
case shaka.ui.TrackLabelFormat.ROLE:
if (!rolesString) {
// Fallback behavior. This probably shouldn't happen.
shaka.log.alwaysWarn('Track #' + track.id + ' does not have a ' +
'role, but the UI is configured to only show role.');
span.textContent = '?';
} else {
span.textContent = rolesString;
}
break;
case shaka.ui.TrackLabelFormat.LANGUAGE_ROLE:
if (rolesString) {
span.textContent += ': ' + rolesString;
}
break;
}
if (updateChosen && (track == selectedTrack)) {
button.appendChild(shaka.ui.Utils.checkmarkIcon());
span.classList.add('shaka-chosen-item');
button.setAttribute('aria-selected', 'true');
currentSelectionElement.textContent = span.textContent;
}
langMenu.appendChild(button);
}
}
/**
* Returns the language's name for itself in its own script (autoglottonym),
* if we have it.
*
* If the locale, including region, can be mapped to a name, we return a very
* specific name including the region. For example, "de-AT" would map to
* "Deutsch (Österreich)" or Austrian German.
*
* If only the language part of the locale is in our map, we append the locale
* itself for specificity. For example, "ar-EG" (Egyptian Arabic) would map
* to "ﺎﻠﻋﺮﺒﻳﺓ (ar-EG)". In this way, multiple versions of Arabic whose
* regions are not in our map would not all look the same in the language
* list, but could be distinguished by their locale.
*
* Finally, if language part of the locale is not in our map, we label it
* "unknown", as translated to the UI locale, and we append the locale itself
* for specificity. For example, "sjn" would map to "Unknown (sjn)". In this
* way, multiple unrecognized languages would not all look the same in the
* language list, but could be distinguished by their locale.
*
* @param {string} locale
* @param {shaka.ui.Localization} localization
* @return {string} The language's name for itself in its own script, or as
* close as we can get with the information we have.
*/
static getLanguageName(locale, localization) {
if (!locale && !localization) {
return '';
}
// Shorthand for resolving a localization ID.
const resolve = (id) => localization.resolve(id);
// Handle some special cases first. These are reserved language tags that
// are used to indicate something that isn't one specific language.
switch (locale) {
case 'mul':
return resolve(shaka.ui.Locales.Ids.MULTIPLE_LANGUAGES);
case 'und':
return resolve(shaka.ui.Locales.Ids.UNDETERMINED_LANGUAGE);
case 'zxx':
return resolve(shaka.ui.Locales.Ids.NOT_APPLICABLE);
}
// Extract the base language from the locale as a fallback step.
const language = shaka.util.LanguageUtils.getBase(locale);
// First try to resolve the full language name.
// If that fails, try the base.
// Finally, report "unknown".
// When there is a loss of specificity (either to a base language or to
// "unknown"), we should append the original language code.
// Otherwise, there may be multiple identical-looking items in the list.
if (locale in mozilla.LanguageMapping) {
return mozilla.LanguageMapping[locale].nativeName;
} else if (language in mozilla.LanguageMapping) {
return mozilla.LanguageMapping[language].nativeName +
' (' + locale + ')';
} else {
return resolve(shaka.ui.Locales.Ids.UNRECOGNIZED_LANGUAGE) +
' (' + locale + ')';
}
}
};