From 069e090c2ad9649d8dc694fd65379c349eb8bd46 Mon Sep 17 00:00:00 2001 From: junkfood <69683722+JunkFood02@users.noreply.github.com> Date: Wed, 31 Jan 2024 01:47:26 +0800 Subject: [PATCH] fix(i18n): configuration loss when switching locale (#541) * fix(i18n): configuration loss when switching locale * feat(locale): enable auto-localeconfig --- app/build.gradle | 7 + app/src/main/AndroidManifest.xml | 9 + .../infrastructure/android/MainActivity.kt | 7 +- .../preference/LanguagesPreference.kt | 197 +++++++++--------- app/src/main/res/resources.properties | 1 + 5 files changed, 114 insertions(+), 107 deletions(-) create mode 100644 app/src/main/res/resources.properties diff --git a/app/build.gradle b/app/build.gradle index b38744b7a..95c0e6105 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -97,6 +97,12 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + +// https://developer.android.com/guide/topics/resources/app-languages#auto-localeconfig + androidResources { + generateLocaleConfig true + } + namespace 'me.ash.reader' } @@ -197,6 +203,7 @@ dependencies { // android implementation "androidx.core:core-ktx:1.12.0" implementation "androidx.activity:activity-compose:1.8.2" + implementation 'androidx.appcompat:appcompat:1.6.1' testImplementation "junit:junit:4.13.2" androidTestImplementation "androidx.test.ext:junit:1.1.3" androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4641be3e8..d5ddc99ab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -49,6 +49,15 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> + + + + diff --git a/app/src/main/java/me/ash/reader/infrastructure/android/MainActivity.kt b/app/src/main/java/me/ash/reader/infrastructure/android/MainActivity.kt index a95e08989..ff746690d 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/android/MainActivity.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/android/MainActivity.kt @@ -6,8 +6,8 @@ import android.os.Bundle import android.util.Log import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS -import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.CompositionLocalProvider import androidx.core.view.WindowCompat import androidx.profileinstaller.ProfileInstallerInitializer @@ -28,7 +28,7 @@ import javax.inject.Inject * The Single-Activity Architecture. */ @AndroidEntryPoint -class MainActivity : ComponentActivity() { +class MainActivity : AppCompatActivity() { @Inject lateinit var imageLoader: ImageLoader @@ -46,8 +46,7 @@ class MainActivity : ComponentActivity() { // Set the language LanguagesPreference.fromValue(languages).let { - if (it == LanguagesPreference.UseDeviceLanguages) return@let - it.setLocale(this) + LanguagesPreference.setLocale(it) } // Workaround for https://github.com/Ashinch/ReadYou/issues/312: increase cursor window size diff --git a/app/src/main/java/me/ash/reader/infrastructure/preference/LanguagesPreference.kt b/app/src/main/java/me/ash/reader/infrastructure/preference/LanguagesPreference.kt index a5349b383..296169302 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/preference/LanguagesPreference.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/preference/LanguagesPreference.kt @@ -1,9 +1,11 @@ package me.ash.reader.infrastructure.preference import android.content.Context -import android.os.LocaleList +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.os.LocaleListCompat import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import me.ash.reader.R import me.ash.reader.ui.ext.DataStoreKeys @@ -31,124 +33,113 @@ sealed class LanguagesPreference(val value: Int) : Preference() { override fun put(context: Context, scope: CoroutineScope) { scope.launch { context.dataStore.put( - DataStoreKeys.Languages, - value + DataStoreKeys.Languages, + value ) - setLocale(context) + scope.launch(Dispatchers.Main) { setLocale(this@LanguagesPreference) } } } fun toDesc(context: Context): String = - when (this) { - UseDeviceLanguages -> context.getString(R.string.use_device_languages) - English -> context.getString(R.string.english) - ChineseSimplified -> context.getString(R.string.chinese_simplified) - German -> context.getString(R.string.german) - French -> context.getString(R.string.french) - Czech -> context.getString(R.string.czech) - Italian -> context.getString(R.string.italian) - Hindi -> context.getString(R.string.hindi) - Spanish -> context.getString(R.string.spanish) - Polish -> context.getString(R.string.polish) - Russian -> context.getString(R.string.russian) - Basque -> context.getString(R.string.basque) - Indonesian -> context.getString(R.string.indonesian) - ChineseTraditional -> context.getString(R.string.chinese_traditional) - } - - fun getLocale(): Locale = - when (this) { - UseDeviceLanguages -> LocaleList.getDefault().get(0) - English -> Locale("en", "US") - ChineseSimplified -> Locale("zh", "CN") - German -> Locale("de", "DE") - French -> Locale("fr", "FR") - Czech -> Locale("cs", "CZ") - Italian -> Locale("it", "IT") - Hindi -> Locale("hi", "IN") - Spanish -> Locale("es", "ES") - Polish -> Locale("pl", "PL") - Russian -> Locale("ru", "RU") - Basque -> Locale("eu", "ES") - Indonesian -> Locale("in", "ID") - ChineseTraditional -> Locale("zh", "TW") - } + when (this) { + UseDeviceLanguages -> context.getString(R.string.use_device_languages) + English -> context.getString(R.string.english) + ChineseSimplified -> context.getString(R.string.chinese_simplified) + German -> context.getString(R.string.german) + French -> context.getString(R.string.french) + Czech -> context.getString(R.string.czech) + Italian -> context.getString(R.string.italian) + Hindi -> context.getString(R.string.hindi) + Spanish -> context.getString(R.string.spanish) + Polish -> context.getString(R.string.polish) + Russian -> context.getString(R.string.russian) + Basque -> context.getString(R.string.basque) + Indonesian -> context.getString(R.string.indonesian) + ChineseTraditional -> context.getString(R.string.chinese_traditional) + } - fun setLocale(context: Context) { - val locale = getLocale() - val resources = context.resources - val metrics = resources.displayMetrics - val configuration = resources.configuration - configuration.setLocale(locale) - configuration.setLocales(LocaleList(locale)) - context.createConfigurationContext(configuration) - resources.updateConfiguration(configuration, metrics) + private fun toLocale(): Locale? = + when (this) { + UseDeviceLanguages -> null + English -> Locale("en", "US") + ChineseSimplified -> Locale("zh", "CN") + German -> Locale("de", "DE") + French -> Locale("fr", "FR") + Czech -> Locale("cs", "CZ") + Italian -> Locale("it", "IT") + Hindi -> Locale("hi", "IN") + Spanish -> Locale("es", "ES") + Polish -> Locale("pl", "PL") + Russian -> Locale("ru", "RU") + Basque -> Locale("eu", "ES") + Indonesian -> Locale("in", "ID") + ChineseTraditional -> Locale("zh", "TW") + } - val appResources = context.applicationContext.resources - val appMetrics = appResources.displayMetrics - val appConfiguration = appResources.configuration - appConfiguration.setLocale(locale) - appConfiguration.setLocales(LocaleList(locale)) - context.applicationContext.createConfigurationContext(appConfiguration) - appResources.updateConfiguration(appConfiguration, appMetrics) - } + private fun toLocaleList(): LocaleListCompat = toLocale()?.let { LocaleListCompat.create(it) } + ?: LocaleListCompat.getEmptyLocaleList() companion object { val default = UseDeviceLanguages val values = listOf( - UseDeviceLanguages, - English, - ChineseSimplified, - German, - French, - Czech, - Italian, - Hindi, - Spanish, - Polish, - Russian, - Basque, - Indonesian, - ChineseTraditional, + UseDeviceLanguages, + English, + ChineseSimplified, + German, + French, + Czech, + Italian, + Hindi, + Spanish, + Polish, + Russian, + Basque, + Indonesian, + ChineseTraditional, ) fun fromPreferences(preferences: Preferences): LanguagesPreference = - when (preferences[DataStoreKeys.Languages.key]) { - 0 -> UseDeviceLanguages - 1 -> English - 2 -> ChineseSimplified - 3 -> German - 4 -> French - 5 -> Czech - 6 -> Italian - 7 -> Hindi - 8 -> Spanish - 9 -> Polish - 10 -> Russian - 11 -> Basque - 12 -> Indonesian - 13 -> ChineseTraditional - else -> default - } + when (preferences[DataStoreKeys.Languages.key]) { + 0 -> UseDeviceLanguages + 1 -> English + 2 -> ChineseSimplified + 3 -> German + 4 -> French + 5 -> Czech + 6 -> Italian + 7 -> Hindi + 8 -> Spanish + 9 -> Polish + 10 -> Russian + 11 -> Basque + 12 -> Indonesian + 13 -> ChineseTraditional + else -> default + } fun fromValue(value: Int): LanguagesPreference = - when (value) { - 0 -> UseDeviceLanguages - 1 -> English - 2 -> ChineseSimplified - 3 -> German - 4 -> French - 5 -> Czech - 6 -> Italian - 7 -> Hindi - 8 -> Spanish - 9 -> Polish - 10 -> Russian - 11 -> Basque - 12 -> Indonesian - 13 -> ChineseTraditional - else -> default - } + when (value) { + 0 -> UseDeviceLanguages + 1 -> English + 2 -> ChineseSimplified + 3 -> German + 4 -> French + 5 -> Czech + 6 -> Italian + 7 -> Hindi + 8 -> Spanish + 9 -> Polish + 10 -> Russian + 11 -> Basque + 12 -> Indonesian + 13 -> ChineseTraditional + else -> default + } + + fun setLocale(preference: LanguagesPreference) { + AppCompatDelegate.setApplicationLocales(preference.toLocaleList()) + } + } } diff --git a/app/src/main/res/resources.properties b/app/src/main/res/resources.properties new file mode 100644 index 000000000..d5a3ddc92 --- /dev/null +++ b/app/src/main/res/resources.properties @@ -0,0 +1 @@ +unqualifiedResLocale=en-US \ No newline at end of file