diff --git a/app/src/main/java/org/wikipedia/language/AppLanguageState.kt b/app/src/main/java/org/wikipedia/language/AppLanguageState.kt index 6889408d8e5..26c2ca9f38d 100644 --- a/app/src/main/java/org/wikipedia/language/AppLanguageState.kt +++ b/app/src/main/java/org/wikipedia/language/AppLanguageState.kt @@ -6,7 +6,7 @@ import org.wikipedia.R import org.wikipedia.WikipediaApp import org.wikipedia.settings.Prefs import org.wikipedia.util.ReleaseUtil -import java.util.* +import java.util.Locale class AppLanguageState(context: Context) { @@ -37,7 +37,9 @@ class AppLanguageState(context: Context) { get() = appLanguageCodes.first() val remainingSuggestedLanguageCodes: List - get() = LanguageUtil.suggestedLanguagesFromSystem.filter { !_appLanguageCodes.contains(it) && appLanguageLookUpTable.isSupportedCode(it) } + get() = LanguageUtil.suggestedLanguagesFromSystem + .filter { it !in _appLanguageCodes && appLanguageLookUpTable.isSupportedCode(it) } + .toList() val systemLanguageCode: String get() { diff --git a/app/src/main/java/org/wikipedia/language/LanguageUtil.kt b/app/src/main/java/org/wikipedia/language/LanguageUtil.kt index cabe0ddb764..36ca8d47887 100644 --- a/app/src/main/java/org/wikipedia/language/LanguageUtil.kt +++ b/app/src/main/java/org/wikipedia/language/LanguageUtil.kt @@ -1,86 +1,61 @@ package org.wikipedia.language -import android.content.Context import android.os.Build import android.view.inputmethod.InputMethodManager +import android.view.inputmethod.InputMethodSubtype +import androidx.core.content.getSystemService import androidx.core.os.LocaleListCompat import org.apache.commons.lang3.StringUtils import org.wikipedia.WikipediaApp -import org.wikipedia.util.StringUtil import java.util.Locale object LanguageUtil { - private const val MAX_SUGGESTED_LANGUAGES = 8 private const val HONG_KONG_COUNTRY_CODE = "HK" private const val MACAU_COUNTRY_CODE = "MO" private val TRADITIONAL_CHINESE_COUNTRY_CODES = listOf(Locale.TAIWAN.country, HONG_KONG_COUNTRY_CODE, MACAU_COUNTRY_CODE) - val suggestedLanguagesFromSystem: List + private val InputMethodSubtype.localeObject: Locale? get() { - val languages = mutableListOf() + val languageTag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) languageTag else "" + val actualTag = languageTag.ifEmpty { + // The keyboard reports locale variants with underscores ("en_US") whereas + // Locale.forLanguageTag() expects dashes ("en-US"), so convert them. + @Suppress("DEPRECATION") + locale.replace('_', '-') + } + return if (actualTag.isNotEmpty()) Locale.forLanguageTag(actualTag) else null + } + val suggestedLanguagesFromSystem: Sequence + get() { // First, look at languages installed on the system itself. - var localeList = LocaleListCompat.getDefault() - for (i in 0 until localeList.size()) { - localeList[i]?.let { - val languageCode = localeToWikiLanguageCode(it) - if (!languages.contains(languageCode)) { - languages.add(languageCode) - } + val systemLocales = sequence { + val localeList = LocaleListCompat.getDefault() + for (i in 0 until localeList.size()) { + yield(localeList[i]!!) } } - if (languages.isEmpty()) { - // Always default to at least one system language in the list. - languages.add(localeToWikiLanguageCode(Locale.getDefault())) - } - // Query the installed keyboard languages, and add them to the list, if they don't exist. - val imm = WikipediaApp.instance.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - val ims = imm.enabledInputMethodList ?: emptyList() - val langTagList = mutableListOf() - for (method in ims) { - val submethods = imm.getEnabledInputMethodSubtypeList(method, true) ?: emptyList() - for (submethod in submethods) { - if (submethod.mode == "keyboard") { - var langTag = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && submethod.languageTag.isNotEmpty()) submethod.languageTag - else submethod.locale - if (langTag.isEmpty()) { - continue - } - if (langTag.contains("_")) { - // The keyboard reports locale variants with underscores ("en_US") whereas - // Locale.forLanguageTag() expects dashes ("en-US"), so convert them. - langTag = langTag.replace('_', '-') - } - if (!langTagList.contains(langTag)) { - langTagList.add(langTag) - } - // A Pinyin keyboard will report itself as zh-CN (simplified), but we want to add - // both Simplified and Traditional in that case. - if (langTag.lowercase(Locale.getDefault()) == AppLanguageLookUpTable.CHINESE_CN_LANGUAGE_CODE && - !langTagList.contains("zh-TW")) { - langTagList.add("zh-TW") - } - } + // Query the installed keyboard languages lazily. + val imm = WikipediaApp.instance.getSystemService()!! + val keyboardLocales = imm.enabledInputMethodList.asSequence() + .flatMap { imm.getEnabledInputMethodSubtypeList(it, true) } + .filter { it.mode == "keyboard" } + .mapNotNull { it.localeObject } + .flatMap { + // A Pinyin keyboard will report itself as zh-CN (simplified), but we want to add + // both Simplified and Traditional in that case. + if (it == Locale.SIMPLIFIED_CHINESE) listOf(it, Locale.TRADITIONAL_CHINESE) else listOf(it) } - } - if (langTagList.isNotEmpty()) { - localeList = LocaleListCompat.forLanguageTags(StringUtil.listToCsv(langTagList)) - for (i in 0 until localeList.size()) { - localeList[i]?.let { - val langCode = localeToWikiLanguageCode(it) - if (langCode.isNotEmpty() && !languages.contains(langCode) && langCode != "und") { - languages.add(langCode) - } - } - } - } - return languages.take(MAX_SUGGESTED_LANGUAGES) + + return (systemLocales + keyboardLocales) + .map { localeToWikiLanguageCode(it) } + .distinct() + .filter { it.isNotEmpty() && it != "und" } + .take(MAX_SUGGESTED_LANGUAGES) } - @JvmStatic fun localeToWikiLanguageCode(locale: Locale): String { // Convert deprecated language codes to modern ones. // See https://developer.android.com/reference/java/util/Locale.html