|
| 1 | +package fr.free.nrw.commons.language |
| 2 | + |
| 3 | +import android.content.Context |
| 4 | +import android.content.res.Resources |
| 5 | +import android.text.TextUtils |
| 6 | + |
| 7 | +import androidx.annotation.ArrayRes |
| 8 | +import fr.free.nrw.commons.R |
| 9 | +import java.lang.ref.SoftReference |
| 10 | +import java.util.Arrays |
| 11 | +import java.util.Locale |
| 12 | + |
| 13 | + |
| 14 | +/** Immutable look up table for all app supported languages. All article languages may not be |
| 15 | + * present in this table as it is statically bundled with the app. */ |
| 16 | +class AppLanguageLookUpTable(context: Context) { |
| 17 | + |
| 18 | + companion object { |
| 19 | + const val SIMPLIFIED_CHINESE_LANGUAGE_CODE = "zh-hans" |
| 20 | + const val TRADITIONAL_CHINESE_LANGUAGE_CODE = "zh-hant" |
| 21 | + const val CHINESE_CN_LANGUAGE_CODE = "zh-cn" |
| 22 | + const val CHINESE_HK_LANGUAGE_CODE = "zh-hk" |
| 23 | + const val CHINESE_MO_LANGUAGE_CODE = "zh-mo" |
| 24 | + const val CHINESE_SG_LANGUAGE_CODE = "zh-sg" |
| 25 | + const val CHINESE_TW_LANGUAGE_CODE = "zh-tw" |
| 26 | + const val CHINESE_YUE_LANGUAGE_CODE = "zh-yue" |
| 27 | + const val CHINESE_LANGUAGE_CODE = "zh" |
| 28 | + const val NORWEGIAN_LEGACY_LANGUAGE_CODE = "no" |
| 29 | + const val NORWEGIAN_BOKMAL_LANGUAGE_CODE = "nb" |
| 30 | + const val TEST_LANGUAGE_CODE = "test" |
| 31 | + const val FALLBACK_LANGUAGE_CODE = "en" // Must exist in preference_language_keys. |
| 32 | + } |
| 33 | + |
| 34 | + private val resources: Resources = context.resources |
| 35 | + |
| 36 | + // Language codes for all app supported languages in fixed order. The special code representing |
| 37 | + // the dynamic system language is null. |
| 38 | + private var codesRef = SoftReference<List<String>>(null) |
| 39 | + |
| 40 | + // English names for all app supported languages in fixed order. |
| 41 | + private var canonicalNamesRef = SoftReference<List<String>>(null) |
| 42 | + |
| 43 | + // Native names for all app supported languages in fixed order. |
| 44 | + private var localizedNamesRef = SoftReference<List<String>>(null) |
| 45 | + |
| 46 | + /** |
| 47 | + * @return Nonnull immutable list. The special code representing the dynamic system language is |
| 48 | + * null. |
| 49 | + */ |
| 50 | + fun getCodes(): List<String> { |
| 51 | + var codes = codesRef.get() |
| 52 | + if (codes == null) { |
| 53 | + codes = getStringList(R.array.preference_language_keys) |
| 54 | + codesRef = SoftReference(codes) |
| 55 | + } |
| 56 | + return codes |
| 57 | + } |
| 58 | + |
| 59 | + fun getCanonicalName(code: String?): String? { |
| 60 | + var name = defaultIndex(getCanonicalNames(), indexOfCode(code), null) |
| 61 | + if (name.isNullOrEmpty() && !code.isNullOrEmpty()) { |
| 62 | + name = when (code) { |
| 63 | + Locale.CHINESE.language -> Locale.CHINESE.getDisplayName(Locale.ENGLISH) |
| 64 | + NORWEGIAN_LEGACY_LANGUAGE_CODE -> |
| 65 | + defaultIndex(getCanonicalNames(), indexOfCode(NORWEGIAN_BOKMAL_LANGUAGE_CODE), null) |
| 66 | + else -> null |
| 67 | + } |
| 68 | + } |
| 69 | + return name |
| 70 | + } |
| 71 | + |
| 72 | + fun getLocalizedName(code: String?): String? { |
| 73 | + var name = defaultIndex(getLocalizedNames(), indexOfCode(code), null) |
| 74 | + if (name.isNullOrEmpty() && !code.isNullOrEmpty()) { |
| 75 | + name = when (code) { |
| 76 | + Locale.CHINESE.language -> Locale.CHINESE.getDisplayName(Locale.CHINESE) |
| 77 | + NORWEGIAN_LEGACY_LANGUAGE_CODE -> |
| 78 | + defaultIndex(getLocalizedNames(), indexOfCode(NORWEGIAN_BOKMAL_LANGUAGE_CODE), null) |
| 79 | + else -> null |
| 80 | + } |
| 81 | + } |
| 82 | + return name |
| 83 | + } |
| 84 | + |
| 85 | + fun getCanonicalNames(): List<String> { |
| 86 | + var names = canonicalNamesRef.get() |
| 87 | + if (names == null) { |
| 88 | + names = getStringList(R.array.preference_language_canonical_names) |
| 89 | + canonicalNamesRef = SoftReference(names) |
| 90 | + } |
| 91 | + return names |
| 92 | + } |
| 93 | + |
| 94 | + fun getLocalizedNames(): List<String> { |
| 95 | + var names = localizedNamesRef.get() |
| 96 | + if (names == null) { |
| 97 | + names = getStringList(R.array.preference_language_local_names) |
| 98 | + localizedNamesRef = SoftReference(names) |
| 99 | + } |
| 100 | + return names |
| 101 | + } |
| 102 | + |
| 103 | + fun isSupportedCode(code: String?): Boolean { |
| 104 | + return getCodes().contains(code) |
| 105 | + } |
| 106 | + |
| 107 | + private fun <T> defaultIndex(list: List<T>, index: Int, defaultValue: T?): T? { |
| 108 | + return if (inBounds(list, index)) list[index] else defaultValue |
| 109 | + } |
| 110 | + |
| 111 | + /** |
| 112 | + * Searches #codes for the specified language code and returns the index for use in |
| 113 | + * #canonicalNames and #localizedNames. |
| 114 | + * |
| 115 | + * @param code The language code to search for. The special code representing the dynamic system |
| 116 | + * language is null. |
| 117 | + * @return The index of the language code or -1 if the code is not supported. |
| 118 | + */ |
| 119 | + private fun indexOfCode(code: String?): Int { |
| 120 | + return getCodes().indexOf(code) |
| 121 | + } |
| 122 | + |
| 123 | + /** @return Nonnull immutable list. */ |
| 124 | + private fun getStringList(id: Int): List<String> { |
| 125 | + return getStringArray(id).toList() |
| 126 | + } |
| 127 | + |
| 128 | + private fun inBounds(list: List<*>, index: Int): Boolean { |
| 129 | + return index in list.indices |
| 130 | + } |
| 131 | + |
| 132 | + fun getStringArray(@ArrayRes id: Int): Array<String> { |
| 133 | + return resources.getStringArray(id) |
| 134 | + } |
| 135 | +} |
0 commit comments