core/templates/pages/exploration-player-page/services/audio-translation-language.service.ts
// Copyright 2017 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Service to manage the current language being
* used for audio translations.
*/
import {downgradeInjectable} from '@angular/upgrade/static';
import {Injectable} from '@angular/core';
import {BrowserCheckerService} from 'domain/utilities/browser-checker.service';
import {LanguageUtilService} from 'domain/utilities/language-util.service';
export interface ExplorationLanguageInfo {
/**
* This inteface is used to keep track of the audio language code (value)
* and the audio language description to display (displayed) for the
* _languagesInExploration property.
*/
value: string;
displayed: string;
}
@Injectable({
providedIn: 'root',
})
export class AudioTranslationLanguageService {
constructor(
private browserCheckerService: BrowserCheckerService,
private languageUtilService: LanguageUtilService
) {}
_currentAudioLanguageCode: string | null = null;
_allAudioLanguageCodesInExploration: string[] = [];
_explorationLanguageCode: string | null = null;
_automaticTextToSpeechEnabled: boolean = false;
_languagesInExploration: ExplorationLanguageInfo[] = [];
attemptToSetAudioLanguageToExplorationLanguage(): void {
// We minimize the number of related languages, because we want to
// pick the language that is the most directly related to the exploration
// language. For example, this would prioritize Hindi over Hinglish
// if both were available as audio languages.
let numRelatedLanguages = Number.MAX_VALUE;
this._allAudioLanguageCodesInExploration.forEach(
(audioLanguageCode: string) => {
let relatedLanguageCodes =
this.languageUtilService.getLanguageCodesRelatedToAudioLanguageCode(
audioLanguageCode
);
if (
relatedLanguageCodes.length < numRelatedLanguages &&
this._explorationLanguageCode &&
relatedLanguageCodes.indexOf(this._explorationLanguageCode) !== -1
) {
this._currentAudioLanguageCode = audioLanguageCode;
numRelatedLanguages = relatedLanguageCodes.length;
}
}
);
}
_isAutogeneratedAudioAllowed(): boolean {
return (
this._automaticTextToSpeechEnabled &&
this._explorationLanguageCode !== null &&
this.languageUtilService.supportsAutogeneratedAudio(
this._explorationLanguageCode
)
);
}
_init(
allAudioLanguageCodesInExploration: string[],
preferredAudioLanguageCode: string | null,
explorationLanguageCode: string,
automaticTextToSpeechEnabled: boolean
): void {
this._allAudioLanguageCodesInExploration =
allAudioLanguageCodesInExploration;
this._explorationLanguageCode = explorationLanguageCode;
this._automaticTextToSpeechEnabled = automaticTextToSpeechEnabled;
this._languagesInExploration = [];
// Set the audio language that is chosen initially.
// Use the following priority (highest to lowest):
// 1. If the learner has a preferred audio language set, then set it to
// that language if it is available.
// 2. If the exploration language has a related audio language, then set
// it to that.
// 3. If only the autogenerated audio language is available, then set it
// to that.
// 4. Otherwise, just pick an available non-autogenerated audio language
// at random.
if (
preferredAudioLanguageCode &&
allAudioLanguageCodesInExploration.indexOf(preferredAudioLanguageCode) !==
-1
) {
this._currentAudioLanguageCode = preferredAudioLanguageCode;
}
if (this._currentAudioLanguageCode === null) {
this.attemptToSetAudioLanguageToExplorationLanguage();
}
if (
this._currentAudioLanguageCode === null &&
this._allAudioLanguageCodesInExploration.length >= 1
) {
this._currentAudioLanguageCode =
this._allAudioLanguageCodesInExploration[0];
}
if (
this._currentAudioLanguageCode === null &&
this._allAudioLanguageCodesInExploration.length === 0 &&
this._isAutogeneratedAudioAllowed()
) {
this._currentAudioLanguageCode =
this.languageUtilService.getAutogeneratedAudioLanguage(
this._explorationLanguageCode
).id;
}
this._allAudioLanguageCodesInExploration.forEach((languageCode: string) => {
let languageDescription =
this.languageUtilService.getAudioLanguageDescription(languageCode);
if (languageDescription) {
this._languagesInExploration.push({
value: languageCode,
displayed: languageDescription,
});
}
});
if (this._isAutogeneratedAudioAllowed()) {
let autogeneratedAudioLanguage =
this.languageUtilService.getAutogeneratedAudioLanguage(
this._explorationLanguageCode
);
this._languagesInExploration.push({
value: autogeneratedAudioLanguage.id,
displayed: autogeneratedAudioLanguage.description,
});
}
}
init(
allAudioLanguageCodesInExploration: string[],
preferredAudioLanguageCode: string | null,
explorationLanguageCode: string,
automaticTextToSpeechEnabled: boolean
): void {
this._init(
allAudioLanguageCodesInExploration,
preferredAudioLanguageCode,
explorationLanguageCode,
automaticTextToSpeechEnabled
);
}
/**
* @return {string} The current audio language code (eg. en).
*/
getCurrentAudioLanguageCode(): string | null {
return this._currentAudioLanguageCode;
}
/**
* @return {string} The current language description (eg. English).
*/
getCurrentAudioLanguageDescription(): string | null {
if (this._currentAudioLanguageCode) {
return this.languageUtilService.getAudioLanguageDescription(
this._currentAudioLanguageCode
);
}
return null;
}
/**
* @return {string[]} An array of the audio language codes in
* exploration.
*/
getAllAudioLanguageCodesInExploration(): string[] {
return this._allAudioLanguageCodesInExploration;
}
/**
* @return {Array<ExplorationLanguageInfo>}
* An array of ExplorationLanguageInfo objects which consist of audio
* language codes as well as their displayed language description for
* the exploration.
*/
getLanguageOptionsForDropdown(): ExplorationLanguageInfo[] {
return this._languagesInExploration;
}
clearCurrentAudioLanguageCode(): void {
this._currentAudioLanguageCode = null;
}
/**
* @param {string} set a new language code.
*/
setCurrentAudioLanguageCode(newLanguageCode: string): void {
this._currentAudioLanguageCode = newLanguageCode;
}
/**
* @return {boolean} Whether auto generation for the audio is allowed.
*/
isAutogeneratedAudioAllowed(): boolean {
return this._isAutogeneratedAudioAllowed();
}
/**
* @return {boolean} Whether an auto generated language code is selected.
*/
isAutogeneratedLanguageCodeSelected(): boolean {
if (this._currentAudioLanguageCode) {
return this.languageUtilService.isAutogeneratedAudioLanguage(
this._currentAudioLanguageCode
);
}
return false;
}
/**
* @return {boolean} Whether an automatic text to speech is enabled.
*/
isAutomaticTextToSpeechEnabled(): boolean {
return this._automaticTextToSpeechEnabled;
}
/**
* @return {string} the speech synthesis language code.
*/
getSpeechSynthesisLanguageCode(): string | null {
if (!this._explorationLanguageCode) {
return null;
}
let autogeneratedAudioLanguage =
this.languageUtilService.getAutogeneratedAudioLanguage(
this._explorationLanguageCode
);
if (this.browserCheckerService.isMobileDevice()) {
return autogeneratedAudioLanguage.speechSynthesisCodeMobile;
}
return autogeneratedAudioLanguage.speechSynthesisCode;
}
}
angular
.module('oppia')
.factory(
'AudioTranslationLanguageService',
downgradeInjectable(AudioTranslationLanguageService)
);