Skip to content

Instantly share code, notes, and snippets.

@ericksli
Created January 25, 2023 05:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericksli/f5d4047c920de4a510fe0cce581a8d85 to your computer and use it in GitHub Desktop.
Save ericksli/f5d4047c920de4a510fe0cce581a8d85 to your computer and use it in GitHub Desktop.
Android 13 Per-app Language Preferences
package net.swiftzer.metroride.common
enum class AppLocale {
SystemDefault,
English,
Chinese,
}
package net.swiftzer.metroride.common
import java.util.*
enum class EquivalentAppLocale(val locale: Locale) {
English(
locale = Locale.Builder()
.setLanguage("en")
.setRegion("HK")
.build(),
),
Chinese(
locale = Locale.Builder()
.setLanguage("zh")
.setRegion("HK")
.setScript("Hant")
.build(),
),
}
package net.swiftzer.metroride.local.system
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import dagger.hilt.android.AndroidEntryPoint
import net.swiftzer.metroride.data.system.LocaleDataSource
import javax.inject.Inject
@AndroidEntryPoint
class LocaleChangedBroadcastReceiver : BroadcastReceiver() {
@Inject
lateinit var localeDataSource: LocaleDataSource
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_LOCALE_CHANGED) return
localeDataSource.fetchAppLocale()
}
}
package net.swiftzer.metroride.data.system
import kotlinx.coroutines.flow.Flow
import net.swiftzer.metroride.common.AppLocale
import net.swiftzer.metroride.common.EquivalentAppLocale
interface LocaleDataSource {
val appLocale: Flow<AppLocale>
val equivalentAppLocale: Flow<EquivalentAppLocale>
fun fetchAppLocale()
fun updateLocale(locale: AppLocale)
}
package net.swiftzer.metroride.local.system
import android.content.res.Resources
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.ConfigurationCompat
import androidx.core.os.LocaleListCompat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import net.swiftzer.metroride.common.AppLocale
import net.swiftzer.metroride.common.EquivalentAppLocale
import net.swiftzer.metroride.data.system.LocaleDataSource
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LocaleDataSourceImpl @Inject constructor() : LocaleDataSource {
private val _appLocale = MutableSharedFlow<AppLocale>(replay = 1)
override val appLocale: Flow<AppLocale> = _appLocale.distinctUntilChanged()
override val equivalentAppLocale: Flow<EquivalentAppLocale> = _appLocale
.map(::resolveSystemLocale)
.distinctUntilChanged()
override fun fetchAppLocale() {
val currentLocale = AppCompatDelegate.getApplicationLocales()
val appLocale = when {
currentLocale.toLanguageTags().startsWith("zh") -> AppLocale.Chinese
currentLocale.toLanguageTags().startsWith("en") -> AppLocale.English
else -> AppLocale.SystemDefault
}
_appLocale.tryEmit(appLocale)
}
private fun resolveSystemLocale(appLocale: AppLocale): EquivalentAppLocale = when (appLocale) {
AppLocale.SystemDefault -> {
val systemLocale =
ConfigurationCompat.getLocales(Resources.getSystem().configuration)[0]!!
when {
systemLocale.language == "zh" && systemLocale.script == "Hant" -> EquivalentAppLocale.Chinese
else -> EquivalentAppLocale.English
}
}
AppLocale.English -> EquivalentAppLocale.English
AppLocale.Chinese -> EquivalentAppLocale.Chinese
}
override fun updateLocale(locale: AppLocale) {
val localeList = when (locale) {
AppLocale.SystemDefault -> LocaleListCompat.getEmptyLocaleList()
AppLocale.English -> LocaleListCompat.forLanguageTags("en")
AppLocale.Chinese -> LocaleListCompat.forLanguageTags("zh-Hant-HK")
}
_appLocale.tryEmit(locale)
AppCompatDelegate.setApplicationLocales(localeList)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment