Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ class AudioLanguageSelectionViewModel @Inject constructor(
val selectedLanguage = MutableLiveData<AudioLanguage>()

/** Sets the list of audio languages supported by the app based on [OppiaLanguage]. */
// TODO(#6020): Replace getSupportedAppLanguages with an audio languages specific API.
val supportedOppiaLanguagesLiveData: LiveData<List<OppiaLanguage>> =
Transformations.map(
translationController.getSupportedAppLanguages().toLiveData()
translationController.getSupportedAudioLanguages().toLiveData()
) { supportedLanguagesResult ->
when (supportedLanguagesResult) {
is AsyncResult.Failure -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ private const val AUDIO_TRANSLATION_CONTENT_LANG_RES_DATA_PROVIDER_ID =
private const val AUDIO_TRANSLATION_CONTENT_SELECTION_DATA_PROVIDER_ID =
"audio_translation_content_selection"
private const val SUPPORTED_AUDIO_LANGUAGES_DATA_PROVIDER_ID = "supported_audio_languages"
private const val SUPPORTED_AUDIO_LANGUAGES_LIST_DATA_PROVIDER_ID =
"supported_audio_languages_list"
private const val UPDATE_AUDIO_TRANSLATION_CONTENT_DATA_PROVIDER_ID =
"update_audio_translation_content"
private const val PROFILE_AUDIO_LANGUAGE_PROVIDER_ID = "profile_audio_language"
Expand Down Expand Up @@ -133,6 +135,23 @@ class TranslationController @Inject constructor(
}
}

/**
* Returns a data provider for a list of [OppiaLanguage] which can be passed to
* [updateAudioTranslationContentLanguage].
*
* Note that this list may differ from [getSupportedAppLanguages] since some languages support
* audio voiceovers but not app strings (e.g. Hinglish).
*/
fun getSupportedAudioLanguages(): DataProvider<List<OppiaLanguage>> {
return dataProviders.createInMemoryDataProvider(
SUPPORTED_AUDIO_LANGUAGES_LIST_DATA_PROVIDER_ID
) {
languageConfigRetriever.loadSupportedLanguages().languageDefinitionsList.filter {
it.hasAudioTranslationId()
}.map { it.language }
}
}

/**
* Returns a data provider for a [OppiaLocale.DisplayLocale] corresponding to the user's selected
* language for app strings (see [getAppLanguage]).
Expand Down Expand Up @@ -311,14 +330,13 @@ class TranslationController @Inject constructor(
fun getAudioTranslationContentLocale(
profileId: ProfileId
): DataProvider<OppiaLocale.ContentLocale> {
// TODO(#6020): Replace getSupportedAppLanguages with an audio languages specific API.
val resolvedLanguageProvider =
getAudioTranslationContentLanguageSelection(profileId).combineWith(
getSupportedAppLanguages(), SUPPORTED_AUDIO_LANGUAGES_DATA_PROVIDER_ID
) { audioLanguageSelection, supportedAppLanguages ->
getSupportedAudioLanguages(), SUPPORTED_AUDIO_LANGUAGES_DATA_PROVIDER_ID
) { audioLanguageSelection, supportedAudioLanguages ->
// Before a profile sets an audio language, LANGUAGE_UNSPECIFIED is always returned.
// In some cases, a language might not be supported but has a fallback configured.
if (audioLanguageSelection.selectedLanguage in supportedAppLanguages ||
if (audioLanguageSelection.selectedLanguage in supportedAudioLanguages ||
audioLanguageSelection.selectionTypeCase == SelectionTypeCase.USE_APP_LANGUAGE ||
audioLanguageSelection.selectedLanguage == OppiaLanguage.LANGUAGE_UNSPECIFIED
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,7 @@ class TranslationControllerTest {
}

@Test
fun testGetAudioLocale_updateLanguageToHinglish_returnsEnglishLocale() {
fun testGetAudioLocale_updateLanguageToHinglish_returnsHinglishLocale() {
Comment thread
Neer-rn marked this conversation as resolved.
forceDefaultLocale(Locale.ROOT)
ensureAudioTranslationsLanguageIsUpdatedTo(PROFILE_ID_0, HINGLISH)

Expand All @@ -1187,6 +1187,22 @@ class TranslationControllerTest {
val locale = monitorFactory.waitForNextSuccessfulResult(localeProvider)
val context = locale.localeContext
assertThat(context.usageMode).isEqualTo(AUDIO_TRANSLATIONS)
assertThat(context.languageDefinition.language).isEqualTo(HINGLISH)
assertThat(context.regionDefinition.region).isEqualTo(REGION_UNSPECIFIED)
}

@Test
fun testGetAudioLocale_updateLanguageToPortuguese_returnsEnglishLocale() {
forceDefaultLocale(Locale.ROOT)
ensureAudioTranslationsLanguageIsUpdatedTo(PROFILE_ID_0, PORTUGUESE)

val localeProvider = translationController.getAudioTranslationContentLocale(PROFILE_ID_0)

val locale = monitorFactory.waitForNextSuccessfulResult(localeProvider)
val context = locale.localeContext
assertThat(context.usageMode).isEqualTo(AUDIO_TRANSLATIONS)
// PORTUGUESE does not have an audio_translation_id, so it is unsupported for audio translations.
// Therefore, it should fall back to ENGLISH.
assertThat(context.languageDefinition.language).isEqualTo(ENGLISH)
// This region comes from the default locale.
assertThat(context.regionDefinition.region).isEqualTo(REGION_UNSPECIFIED)
Expand Down Expand Up @@ -2036,6 +2052,20 @@ class TranslationControllerTest {
.containsExactly(ARABIC, ENGLISH, HINDI, BRAZILIAN_PORTUGUESE, SWAHILI, NIGERIAN_PIDGIN)
}

@Test
fun testGetSupportedAudioLanguages_returnsAudioLanguageDefinitions() {
val languageListProvider = translationController.getSupportedAudioLanguages()
val languageListData = monitorFactory.waitForNextSuccessfulResult(languageListProvider)

// Audio languages include HINGLISH which has an audio_translation_id but no app_string_id,
// so it correctly appears here but not in getSupportedAppLanguages(). This is a change
// detector test to ensure the audio language selection system provides exactly the list of
// intended languages.
assertThat(languageListData).containsExactly(
ARABIC, ENGLISH, HINDI, HINGLISH, BRAZILIAN_PORTUGUESE, SWAHILI, NIGERIAN_PIDGIN
)
}

private fun setUpTestApplicationComponent() {
ApplicationProvider.getApplicationContext<TestApplication>().inject(this)
}
Expand Down
Loading