diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt index 2a2fb431b..2421d45d9 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt @@ -20,16 +20,231 @@ class LocaleViewHolder( ) : BaseLocaleViewHolder(view, selectedLocale) { override fun bind(locale: Locale) { + if (locale.toString().equals("vec", ignoreCase = true)) { + locale.toString() + } // Capitalisation is done using the rules of the appropriate locale (endonym and exonym). - locale_title_text.text = locale.getDisplayName(locale).capitalize(locale) + locale_title_text.text = getDisplayName(locale) // Show the given locale using the device locale for the subtitle. - locale_subtitle_text.text = locale.displayName.capitalize(Locale.getDefault()) + locale_subtitle_text.text = locale.getProperDisplayName() locale_selected_icon.isVisible = isCurrentLocaleSelected(locale, isDefault = false) itemView.setOnClickListener { interactor.onLocaleSelected(locale) } } + + private fun getDisplayName(locale: Locale): String { + val displayName = locale.getDisplayName(locale).capitalize(locale) + if (displayName.equals(locale.toString(), ignoreCase = true)) { + return LOCALE_TO_DISPLAY_NATIVE_NAME_MAP[locale.toString()] ?: displayName + } + return displayName + } + + @SuppressWarnings("LargeClass") + companion object { + val LOCALE_TO_DISPLAY_NATIVE_NAME_MAP: Map = mapOf( + "an" to "Aragonés", + "anp" to "अंगिका", + "ar" to "العربية", + "ast" to "Asturianu", + "ay" to "Aimara", + "az" to "Azərbaycan dili", + "be" to "беларуская мова", + "bg" to "български език", + "bn" to "বাংলা", + "br" to "Brezhoneg", + "bs" to "Bosanski jezik", + "ca" to "Català", + "cak" to "Kaqchikel", + "ceb" to "Cebuano", + "co" to "Corsu, ", + "cs" to "čeština", + "cy" to "Cymraeg", + "da" to "dansk", + "de" to "Deutsch", + "dsb" to "dolnoserbski", + "el" to "ελληνικά", + "eo" to "Esperanto", + "es" to "Español", + "et" to "Eesti", + "eu" to "Euskara", + "fa" to "فارسی", + "ff" to "Fulfulde", + "fi" to "Suomi", + "fr" to "Français", + "fy-NL" to "Frisian", + "ga-IE" to "Gaeilge", + "gd" to "Gàidhlig", + "gl" to "Galego", + "gn" to "Avañe'ẽ", + "gu-IN" to "ગુજરાતી", + "he" to "עברית", + "hi-IN" to "हिन्दी ", + "hil" to "Ilonggo", + "hr" to "hrvatski jezik", + "hsb" to "Hornjoserbsce", + "hu" to "Magyar", + "hus" to "Tének", + "hy-AM" to "հայերեն", + "ia" to "Interlingua", + "id" to "Bahasa Indonesia", + "is" to "Íslenska", + "it" to "Italiano", + "ixl" to "Ixil", + "ja" to "日本語 (にほんご)", + "jv" to "Basa Jawa", + "ka" to "ქართული", + "kab" to "Taqbaylit", + "kk" to "қазақ тілі", + "kmr" to "Kurmancî", + "kn" to "ಕನ್ನಡ", + "ko" to "한국어", + "lij" to "Ligure", + "lo" to "ພາສາລາວ", + "lt" to "lietuvių kalba", + "mix" to "Tu'un savi", + "ml" to "മലയാളം", + "mr" to "मराठी", + "ms" to "Bahasa Melayu ملايو‎", + "my" to "ဗမာစာ", + "meh" to "Tu´un savi ñuu Yasi'í Yuku Iti", + "nb-NO" to "Bokmål", + "ne-NP" to "नेपाली", + "nl" to "Nederlands", + "nn-NO" to "Nynorsk", + "nv" to "Diné bizaad", + "oc" to "Occitan", + "pa-IN" to "Panjābī", + "pl" to "Polszczyzna", + "pt" to "Português", + "pai" to "Paa ipai", + "ppl" to "Náhuat Pipil", + "quy" to "Chanka Qhichwa", + "quc" to "K'iche'", + "rm" to "Rumantsch Grischun", + "ro" to "Română", + "ru" to "русский", + "sat" to "ᱥᱟᱱᱛᱟᱲᱤ", + "sk" to "Slovak", + "sl" to "Slovenian", + "sn" to "ChiShona", + "sq" to "Shqip", + "sr" to "српски језик", + "su" to "Basa Sunda", + "sv-SE" to "Svenska", + "ta" to "தமிழ்", + "te" to "తెలుగు", + "tg" to "тоҷикӣ, toçikī, تاجیکی‎", + "th" to "ไทย", + "tl" to "Wikang Tagalog", + "tr" to "Türkçe", + "trs" to "Triqui", + "tt" to "татарча", + "tsz" to "P'urhepecha", + "uk" to "Українська", + "ur" to "اردو", + "uz" to "Oʻzbek", + "vec" to "Vèneto", + "vi" to "Tiếng Việt", + "wo" to "Wolof", + "zam" to "DíɁztè" + ) + + val LOCALE_TO_DISPLAY_ENGLISH_NAME_MAP: Map = mapOf( + "an" to "Aragonese", + "ar" to "Arabic", + "ast" to "Asturianu", + "az" to "Azerbaijani", + "be" to "Belarusian", + "bg" to "Bulgarian", + "bn" to "Bengali", + "br" to "Breton", + "bs" to "Bosnian", + "ca" to "Catalan", + "cak" to "Kaqchikel", + "ceb" to "Cebuano", + "co" to "Corsican", + "cs" to "Czech", + "cy" to "Welsh", + "da" to "Danish", + "de" to "German", + "dsb" to "Sorbian, Lower", + "el" to "Greek", + "eo" to "Esperanto", + "es" to "Spanish", + "et" to "Estonian", + "eu" to "Basque", + "fa" to "Persian", + "ff" to "Fulah", + "fi" to "Finnish", + "fr" to "French", + "fy-NL" to "Frisian", + "ga-IE" to "Irish", + "gd" to "Gaelic", + "gl" to "Galician", + "gn" to "Guarani", + "gu-IN" to "Gujarati", + "he" to "Hebrew", + "hi-IN" to "Hindi", + "hil" to "Hiligaynon", + "hr" to "Croatian", + "hsb" to "Sorbian, Upper", + "hu" to "Hungarian", + "hy-AM" to "Armenian", + "id" to "Indonesian", + "is" to "Icelandic", + "it" to "Italian", + "ja" to "Japanese", + "ka" to "Georgian", + "kab" to "Kabyle ", + "kk" to "Kazakh", + "kmr" to "Kurmanji Kurdish", + "kn" to "Kannada", + "ko" to "Korean", + "lij" to "Ligurian", + "lo" to "Lao", + "lt" to "Lithuanian", + "mix" to "Mixtepec Mixtec", + "ml" to "Malayalam", + "mr" to "Marathi", + "ms" to "Malay", + "my" to "Burmese", + "nb-NO" to "Norwegian Bokmål", + "ne-NP" to "Nepali ", + "nl" to "Dutch, Flemish", + "nn-NO" to "Norwegian Nynorsk", + "nv" to "Navajo, Navaho", + "oc" to "Occitan", + "pa-IN" to "Punjabi", + "pl" to "Polish", + "pt-BR" to "", + "pt-PT" to "", + "rm" to "Romansh", + "ro" to "Română", + "ru" to "Russian", + "sat" to "Santali", + "sk" to "Slovak", + "sl" to "Slovenian", + "sq" to "Albanian", + "sr" to "Serbian", + "su" to "Sundanese", + "sv-SE" to "Swedish", + "ta" to "Tamil", + "te" to "Telugu", + "tg" to "Tajik", + "th" to "Thai", + "tl" to "Tagalog", + "tr" to "Turkish", + "trs" to "Triqui", + "uk" to "Ukrainian", + "ur" to "Urdu", + "uz" to "Uzbek", + "vec" to "Venitian", + "vi" to "Vietnamese" + ) + } } class SystemLocaleViewHolder( @@ -72,3 +287,14 @@ abstract class BaseLocaleViewHolder( private fun String.capitalize(locale: Locale): String { return substring(0, 1).toUpperCase(locale) + substring(1) } + +/** + * Returns the locale in the selected language, with fallback to English name + */ +private fun Locale.getProperDisplayName(): String { + val displayName = this.displayName.capitalize(Locale.getDefault()) + if (displayName.equals(this.toString(), ignoreCase = true)) { + return LocaleViewHolder.LOCALE_TO_DISPLAY_ENGLISH_NAME_MAP[this.toString()] ?: displayName + } + return displayName +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleViewHoldersTest.kt b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleViewHoldersTest.kt index 451d67a89..b1d005b89 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleViewHoldersTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleViewHoldersTest.kt @@ -66,6 +66,29 @@ class LocaleViewHoldersTest { verify { interactor.onLocaleSelected(selectedLocale) } } + @Test + // Note that after we can run tests on SDK 30 the result of the locale.getDisplayName(locale) could differ and this test will fail + fun `GIVEN a locale is not properly identified in Android WHEN we bind locale THEN the title and subtitle are set from locale maps`() { + + val otherLocale = Locale("vec") + + localeViewHolder.bind(otherLocale) + + assertEquals("Vèneto", view.locale_title_text.text) + assertEquals("Venitian", view.locale_subtitle_text.text) + } + + @Test + fun `GIVEN a locale is not properly identified in Android and it is not mapped WHEN we bind locale THEN the text is the capitalised code`() { + + val otherLocale = Locale("yyy") + + localeViewHolder.bind(otherLocale) + + assertEquals("Yyy", view.locale_title_text.text) + assertEquals("Yyy", view.locale_subtitle_text.text) + } + @Test fun `bind SystemLocaleViewHolder`() { systemLocaleViewHolder.bind(selectedLocale)