diff --git a/README.md b/README.md
index c5e92a983..efce1d86d 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,11 @@ The following is a list of all third-party dependencies included as part of the
- Purpose: Supplementary Android Compose features.
- License: Apache 2.0
+- **Appcompat**
+ - https://developer.android.com/jetpack/androidx/releases/appcompat
+ - Purpose: Allows access to new APIs on older API versions.
+ - License: Apache 2.0
+
- **AndroidX Browser**
- https://developer.android.com/jetpack/androidx/releases/browser
- Purpose: Displays webpages with the user's default browser.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 436ecc460..becd19745 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -29,6 +29,52 @@ android {
versionCode = 1
versionName = "1.0.0"
+ // This is so the build system only includes language resources in the APK for these
+ // languages, preventing translated strings from being included from other libraries that
+ // might support languages this app does not.
+ resourceConfigurations += arrayOf(
+ "af",
+ "be",
+ "bg",
+ "ca",
+ "cs",
+ "da",
+ "de",
+ "el",
+ "en",
+ "en-rGB",
+ "es",
+ "et",
+ "fa",
+ "fi",
+ "fr",
+ "hi",
+ "hr",
+ "hu",
+ "in",
+ "it",
+ "iw",
+ "ja",
+ "ko",
+ "lv",
+ "ml",
+ "nb",
+ "nl",
+ "pl",
+ "pt-rBR",
+ "pt-rPT",
+ "ro",
+ "ru",
+ "sk",
+ "sv",
+ "th",
+ "tr",
+ "uk",
+ "vi",
+ "zh-rCN",
+ "zh-rTW"
+ )
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -102,6 +148,7 @@ dependencies {
}
implementation(libs.androidx.activity.compose)
+ implementation(libs.androidx.appcompat)
implementation(libs.androidx.browser)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 183fe41f7..5ec4014e5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,10 +16,11 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:localeConfig="@xml/locales_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/LaunchTheme"
- tools:targetApi="31">
+ tools:targetApi="33">
+
+
+
+
diff --git a/app/src/main/java/com/x8bit/bitwarden/MainActivity.kt b/app/src/main/java/com/x8bit/bitwarden/MainActivity.kt
index 4882fa9fd..2989b5370 100644
--- a/app/src/main/java/com/x8bit/bitwarden/MainActivity.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/MainActivity.kt
@@ -2,26 +2,40 @@ package com.x8bit.bitwarden
import android.content.Intent
import android.os.Bundle
-import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatDelegate
+import androidx.core.os.LocaleListCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavScreen
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
/**
* Primary entry point for the application.
*/
@AndroidEntryPoint
-class MainActivity : ComponentActivity() {
+class MainActivity : AppCompatActivity() {
private val mainViewModel: MainViewModel by viewModels()
+ @Inject
+ lateinit var settingsRepository: SettingsRepository
+
override fun onCreate(savedInstanceState: Bundle?) {
var shouldShowSplashScreen = true
installSplashScreen().setKeepOnScreenCondition { shouldShowSplashScreen }
super.onCreate(savedInstanceState)
+ // Within the app the language will change dynamically and will be managed
+ // by the OS, but we need to ensure we properly set the language when
+ // upgrading from older versions that handle this differently.
+ settingsRepository.appLanguage.localeName?.let { localeName ->
+ val localeList = LocaleListCompat.forLanguageTags(localeName)
+ AppCompatDelegate.setApplicationLocales(localeList)
+ }
setContent {
BitwardenTheme {
RootNavScreen(
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt
index 928de1ec5..2341f2693 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt
@@ -1,12 +1,18 @@
package com.x8bit.bitwarden.data.platform.datasource.disk
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
+import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
import kotlinx.coroutines.flow.Flow
/**
* Primary access point for general settings-related disk information.
*/
interface SettingsDiskSource {
+ /**
+ * The currently persisted app language (or `null` if not set).
+ */
+ var appLanguage: AppLanguage?
+
/**
* Gets the current vault timeout (in minutes) for the given [userId] (or `null` if the vault
* should never time out).
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt
index c2e02e3ed..715b38cfb 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt
@@ -4,16 +4,19 @@ import android.content.SharedPreferences
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
+import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.onSubscription
+private const val APP_LANGUAGE_KEY = "$BASE_KEY:appLocale"
private const val VAULT_TIMEOUT_ACTION_KEY = "$BASE_KEY:vaultTimeoutAction"
private const val VAULT_TIME_IN_MINUTES_KEY = "$BASE_KEY:vaultTimeout"
/**
* Primary implementation of [SettingsDiskSource].
*/
+@Suppress("TooManyFunctions")
class SettingsDiskSourceImpl(
val sharedPreferences: SharedPreferences,
) : BaseDiskSource(sharedPreferences = sharedPreferences),
@@ -24,6 +27,18 @@ class SettingsDiskSourceImpl(
private val mutableVaultTimeoutInMinutesFlowMap =
mutableMapOf>()
+ override var appLanguage: AppLanguage?
+ get() = getString(key = APP_LANGUAGE_KEY)
+ ?.let { storedValue ->
+ AppLanguage.entries.firstOrNull { storedValue == it.localeName }
+ }
+ set(value) {
+ putString(
+ key = APP_LANGUAGE_KEY,
+ value = value?.localeName,
+ )
+ }
+
override fun getVaultTimeoutInMinutes(userId: String): Int? =
getInt(key = "${VAULT_TIME_IN_MINUTES_KEY}_$userId")
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt
index 7e878c19d..dd45c81bc 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt
@@ -2,12 +2,18 @@ package com.x8bit.bitwarden.data.platform.repository
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
+import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
import kotlinx.coroutines.flow.StateFlow
/**
* Provides an API for observing and modifying settings state.
*/
interface SettingsRepository {
+ /**
+ * The [AppLanguage] for the current user.
+ */
+ var appLanguage: AppLanguage
+
/**
* The [VaultTimeout] for the current user.
*/
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt
index 59dcbdb59..b7d0f990c 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt
@@ -5,6 +5,7 @@ import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
+import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -23,6 +24,12 @@ class SettingsRepositoryImpl(
private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined)
+ override var appLanguage: AppLanguage
+ get() = settingsDiskSource.appLanguage ?: AppLanguage.DEFAULT
+ set(value) {
+ settingsDiskSource.appLanguage = value
+ }
+
override var vaultTimeout: VaultTimeout
get() = activeUserId
?.let {
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceScreen.kt
index e32646206..5e6b0ef89 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceScreen.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceScreen.kt
@@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -25,12 +26,16 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
+import com.x8bit.bitwarden.ui.platform.base.util.asText
+import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
+import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.BitwardenSelectionDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenSelectionRow
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextRow
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
import com.x8bit.bitwarden.ui.platform.components.BitwardenWideSwitch
+import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
/**
* Displays the appearance screen.
@@ -74,7 +79,7 @@ fun AppearanceScreen(
) {
LanguageSelectionRow(
currentSelection = state.language,
- onThemeSelection = remember(viewModel) {
+ onLanguageSelection = remember(viewModel) {
{ viewModel.trySendAction(AppearanceAction.LanguageChange(it)) }
},
modifier = Modifier.fillMaxWidth(),
@@ -105,15 +110,22 @@ fun AppearanceScreen(
@Composable
private fun LanguageSelectionRow(
- currentSelection: AppearanceState.Language,
- onThemeSelection: (AppearanceState.Language) -> Unit,
+ currentSelection: AppLanguage,
+ onLanguageSelection: (AppLanguage) -> Unit,
modifier: Modifier = Modifier,
) {
- var shouldShowLanguageSelectionDialog by remember { mutableStateOf(false) }
+ var languageChangedDialogState: BasicDialogState by rememberSaveable {
+ mutableStateOf(BasicDialogState.Hidden)
+ }
+ var shouldShowLanguageSelectionDialog by rememberSaveable { mutableStateOf(false) }
+
+ BitwardenBasicDialog(
+ visibilityState = languageChangedDialogState,
+ onDismissRequest = { languageChangedDialogState = BasicDialogState.Hidden },
+ )
BitwardenTextRow(
text = stringResource(id = R.string.language),
- description = stringResource(id = R.string.language_change_requires_app_restart),
onClick = { shouldShowLanguageSelectionDialog = true },
modifier = modifier,
) {
@@ -129,14 +141,16 @@ private fun LanguageSelectionRow(
title = stringResource(id = R.string.language),
onDismissRequest = { shouldShowLanguageSelectionDialog = false },
) {
- AppearanceState.Language.entries.forEach { option ->
+ AppLanguage.entries.forEach { option ->
BitwardenSelectionRow(
text = option.text,
isSelected = option == currentSelection,
onClick = {
shouldShowLanguageSelectionDialog = false
- onThemeSelection(
- AppearanceState.Language.entries.first { it == option },
+ onLanguageSelection(option)
+ languageChangedDialogState = BasicDialogState.Shown(
+ title = R.string.language.asText(),
+ message = R.string.language_change_x_description.asText(option.text),
)
},
)
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceViewModel.kt
index 500863242..9480cc7c6 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceViewModel.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/AppearanceViewModel.kt
@@ -1,11 +1,15 @@
package com.x8bit.bitwarden.ui.platform.feature.settings.appearance
import android.os.Parcelable
+import androidx.appcompat.app.AppCompatDelegate
+import androidx.core.os.LocaleListCompat
import androidx.lifecycle.SavedStateHandle
import com.x8bit.bitwarden.R
+import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
+import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.update
import kotlinx.parcelize.Parcelize
@@ -18,11 +22,12 @@ private const val KEY_STATE = "state"
*/
@HiltViewModel
class AppearanceViewModel @Inject constructor(
+ private val settingsRepository: SettingsRepository,
savedStateHandle: SavedStateHandle,
) : BaseViewModel(
initialState = savedStateHandle[KEY_STATE]
?: AppearanceState(
- language = AppearanceState.Language.DEFAULT,
+ language = settingsRepository.appLanguage,
showWebsiteIcons = false,
theme = AppearanceState.Theme.DEFAULT,
),
@@ -39,8 +44,13 @@ class AppearanceViewModel @Inject constructor(
}
private fun handleLanguageChanged(action: AppearanceAction.LanguageChange) {
- // TODO: BIT-1328 implement language selection support
mutableStateFlow.update { it.copy(language = action.language) }
+ settingsRepository.appLanguage = action.language
+
+ val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(
+ action.language.localeName,
+ )
+ AppCompatDelegate.setApplicationLocales(appLocale)
}
private fun handleShowWebsiteIconsToggled(action: AppearanceAction.ShowWebsiteIconsToggle) {
@@ -59,20 +69,10 @@ class AppearanceViewModel @Inject constructor(
*/
@Parcelize
data class AppearanceState(
- val language: Language,
+ val language: AppLanguage,
val showWebsiteIcons: Boolean,
val theme: Theme,
) : Parcelable {
- /**
- * Represents the languages supported by the app.
- *
- * TODO BIT-1328 populate values
- */
- enum class Language(val text: Text) {
- DEFAULT(text = R.string.default_system.asText()),
- ENGLISH(text = "English".asText()),
- }
-
/**
* Represents the theme options the user can set.
*/
@@ -106,7 +106,7 @@ sealed class AppearanceAction {
* Indicates that the user changed the Language.
*/
data class LanguageChange(
- val language: AppearanceState.Language,
+ val language: AppLanguage,
) : AppearanceAction()
/**
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/model/AppLanguage.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/model/AppLanguage.kt
new file mode 100644
index 000000000..70f1d7431
--- /dev/null
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/appearance/model/AppLanguage.kt
@@ -0,0 +1,178 @@
+package com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model
+
+import com.x8bit.bitwarden.R
+import com.x8bit.bitwarden.ui.platform.base.util.Text
+import com.x8bit.bitwarden.ui.platform.base.util.asText
+
+/**
+ * Represents the languages supported by the app.
+ */
+enum class AppLanguage(
+ val localeName: String?,
+ val text: Text,
+) {
+ DEFAULT(
+ localeName = null,
+ text = R.string.default_system.asText(),
+ ),
+ AFRIKAANS(
+ localeName = "af",
+ text = "Afrikaans".asText(),
+ ),
+ BELARUSIAN(
+ localeName = "be",
+ text = "Беларуская".asText(),
+ ),
+ BULGARIAN(
+ localeName = "bg",
+ text = "български".asText(),
+ ),
+ CATALAN(
+ localeName = "ca",
+ text = "català".asText(),
+ ),
+ CZECH(
+ localeName = "cs",
+ text = "čeština".asText(),
+ ),
+ DANISH(
+ localeName = "da",
+ text = "Dansk".asText(),
+ ),
+ GERMAN(
+ localeName = "de",
+ text = "Deutsch".asText(),
+ ),
+ GREEK(
+ localeName = "el",
+ text = "Ελληνικά".asText(),
+ ),
+ ENGLISH(
+ localeName = "en",
+ text = "English".asText(),
+ ),
+ ENGLISH_BRITISH(
+ localeName = "en-GB",
+ text = "English (British)".asText(),
+ ),
+ SPANISH(
+ localeName = "es",
+ text = "Español".asText(),
+ ),
+ ESTONIAN(
+ localeName = "et",
+ text = "eesti".asText(),
+ ),
+ PERSIAN(
+ localeName = "fa",
+ text = "فارسی".asText(),
+ ),
+ FINNISH(
+ localeName = "fi",
+ text = "suomi".asText(),
+ ),
+ FRENCH(
+ localeName = "fr",
+ text = "Français".asText(),
+ ),
+ HINDI(
+ localeName = "hi",
+ text = "हिन्दी".asText(),
+ ),
+ CROATIAN(
+ localeName = "hr",
+ text = "hrvatski".asText(),
+ ),
+ HUNGARIAN(
+ localeName = "hu",
+ text = "magyar".asText(),
+ ),
+ INDONESIAN(
+ localeName = "in",
+ text = "Bahasa Indonesia".asText(),
+ ),
+ ITALIAN(
+ localeName = "it",
+ text = "Italiano".asText(),
+ ),
+ HEBREW(
+ localeName = "iw",
+ text = "עברית".asText(),
+ ),
+ JAPANESE(
+ localeName = "ja",
+ text = "日本語".asText(),
+ ),
+ KOREAN(
+ localeName = "ko",
+ text = "한국어".asText(),
+ ),
+ LATVIAN(
+ localeName = "lv",
+ text = "Latvietis".asText(),
+ ),
+ MALAYALAM(
+ localeName = "ml",
+ text = "മലയാളം".asText(),
+ ),
+ NORWEGIAN(
+ localeName = "nb",
+ text = "norsk (bokmål)".asText(),
+ ),
+ DUTCH(
+ localeName = "nl",
+ text = "Nederlands".asText(),
+ ),
+ POLISH(
+ localeName = "pl",
+ text = "Polski".asText(),
+ ),
+ PORTUGUESE_BRAZILIAN(
+ localeName = "pt-BR",
+ text = "Português do Brasil".asText(),
+ ),
+ PORTUGUESE(
+ localeName = "pt-PT",
+ text = "Português".asText(),
+ ),
+ ROMANIAN(
+ localeName = "ro",
+ text = "română".asText(),
+ ),
+ RUSSIAN(
+ localeName = "ru",
+ text = "русский".asText(),
+ ),
+ SLOVAK(
+ localeName = "sk",
+ text = "slovenčina".asText(),
+ ),
+ SWEDISH(
+ localeName = "sv",
+ text = "svenska".asText(),
+ ),
+ THAI(
+ localeName = "th",
+ text = "ไทย".asText(),
+ ),
+ TURKISH(
+ localeName = "tr",
+ text = "Türkçe".asText(),
+ ),
+ UKRAINIAN(
+ localeName = "uk",
+ text = "українська".asText(),
+ ),
+ VIETNAMESE(
+ localeName = "vi",
+ text = "Tiếng Việt".asText(),
+ ),
+ CHINESE_SIMPLIFIED(
+ localeName = "zh-CN",
+ text = "中文(中国大陆)".asText(),
+ ),
+ CHINESE_TRADITIONAL(
+ localeName = "zh-TW",
+ text = "中文(台灣)".asText(),
+ ),
+}
diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af/strings.xml
similarity index 100%
rename from app/src/main/res/values-af-rZA/strings.xml
rename to app/src/main/res/values-af/strings.xml
diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar/strings.xml
similarity index 100%
rename from app/src/main/res/values-ar-rSA/strings.xml
rename to app/src/main/res/values-ar/strings.xml
diff --git a/app/src/main/res/values-az-rAZ/strings.xml b/app/src/main/res/values-az/strings.xml
similarity index 100%
rename from app/src/main/res/values-az-rAZ/strings.xml
rename to app/src/main/res/values-az/strings.xml
diff --git a/app/src/main/res/values-be-rBY/strings.xml b/app/src/main/res/values-be/strings.xml
similarity index 100%
rename from app/src/main/res/values-be-rBY/strings.xml
rename to app/src/main/res/values-be/strings.xml
diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg/strings.xml
similarity index 100%
rename from app/src/main/res/values-bg-rBG/strings.xml
rename to app/src/main/res/values-bg/strings.xml
diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/app/src/main/res/values-bn/strings.xml
similarity index 100%
rename from app/src/main/res/values-bn-rBD/strings.xml
rename to app/src/main/res/values-bn/strings.xml
diff --git a/app/src/main/res/values-bs-rBA/strings.xml b/app/src/main/res/values-bs/strings.xml
similarity index 100%
rename from app/src/main/res/values-bs-rBA/strings.xml
rename to app/src/main/res/values-bs/strings.xml
diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca/strings.xml
similarity index 100%
rename from app/src/main/res/values-ca-rES/strings.xml
rename to app/src/main/res/values-ca/strings.xml
diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs/strings.xml
similarity index 100%
rename from app/src/main/res/values-cs-rCZ/strings.xml
rename to app/src/main/res/values-cs/strings.xml
diff --git a/app/src/main/res/values-cy-rGB/strings.xml b/app/src/main/res/values-cy/strings.xml
similarity index 100%
rename from app/src/main/res/values-cy-rGB/strings.xml
rename to app/src/main/res/values-cy/strings.xml
diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da/strings.xml
similarity index 100%
rename from app/src/main/res/values-da-rDK/strings.xml
rename to app/src/main/res/values-da/strings.xml
diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de/strings.xml
similarity index 100%
rename from app/src/main/res/values-de-rDE/strings.xml
rename to app/src/main/res/values-de/strings.xml
diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el/strings.xml
similarity index 100%
rename from app/src/main/res/values-el-rGR/strings.xml
rename to app/src/main/res/values-el/strings.xml
diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es/strings.xml
similarity index 100%
rename from app/src/main/res/values-es-rES/strings.xml
rename to app/src/main/res/values-es/strings.xml
diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et/strings.xml
similarity index 100%
rename from app/src/main/res/values-et-rEE/strings.xml
rename to app/src/main/res/values-et/strings.xml
diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu/strings.xml
similarity index 100%
rename from app/src/main/res/values-eu-rES/strings.xml
rename to app/src/main/res/values-eu/strings.xml
diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa/strings.xml
similarity index 100%
rename from app/src/main/res/values-fa-rIR/strings.xml
rename to app/src/main/res/values-fa/strings.xml
diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi/strings.xml
similarity index 100%
rename from app/src/main/res/values-fi-rFI/strings.xml
rename to app/src/main/res/values-fi/strings.xml
diff --git a/app/src/main/res/values-fil-rPH/strings.xml b/app/src/main/res/values-fil/strings.xml
similarity index 100%
rename from app/src/main/res/values-fil-rPH/strings.xml
rename to app/src/main/res/values-fil/strings.xml
diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr/strings.xml
similarity index 100%
rename from app/src/main/res/values-fr-rFR/strings.xml
rename to app/src/main/res/values-fr/strings.xml
diff --git a/app/src/main/res/values-gl-rES/strings.xml b/app/src/main/res/values-gl/strings.xml
similarity index 100%
rename from app/src/main/res/values-gl-rES/strings.xml
rename to app/src/main/res/values-gl/strings.xml
diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi/strings.xml
similarity index 100%
rename from app/src/main/res/values-hi-rIN/strings.xml
rename to app/src/main/res/values-hi/strings.xml
diff --git a/app/src/main/res/values-hr-rHR/strings.xml b/app/src/main/res/values-hr/strings.xml
similarity index 100%
rename from app/src/main/res/values-hr-rHR/strings.xml
rename to app/src/main/res/values-hr/strings.xml
diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu/strings.xml
similarity index 100%
rename from app/src/main/res/values-hu-rHU/strings.xml
rename to app/src/main/res/values-hu/strings.xml
diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in/strings.xml
similarity index 100%
rename from app/src/main/res/values-in-rID/strings.xml
rename to app/src/main/res/values-in/strings.xml
diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it/strings.xml
similarity index 100%
rename from app/src/main/res/values-it-rIT/strings.xml
rename to app/src/main/res/values-it/strings.xml
diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw/strings.xml
similarity index 100%
rename from app/src/main/res/values-iw-rIL/strings.xml
rename to app/src/main/res/values-iw/strings.xml
diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja/strings.xml
similarity index 100%
rename from app/src/main/res/values-ja-rJP/strings.xml
rename to app/src/main/res/values-ja/strings.xml
diff --git a/app/src/main/res/values-ka-rGE/strings.xml b/app/src/main/res/values-ka/strings.xml
similarity index 100%
rename from app/src/main/res/values-ka-rGE/strings.xml
rename to app/src/main/res/values-ka/strings.xml
diff --git a/app/src/main/res/values-kn-rIN/strings.xml b/app/src/main/res/values-kn/strings.xml
similarity index 100%
rename from app/src/main/res/values-kn-rIN/strings.xml
rename to app/src/main/res/values-kn/strings.xml
diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko/strings.xml
similarity index 100%
rename from app/src/main/res/values-ko-rKR/strings.xml
rename to app/src/main/res/values-ko/strings.xml
diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt/strings.xml
similarity index 100%
rename from app/src/main/res/values-lt-rLT/strings.xml
rename to app/src/main/res/values-lt/strings.xml
diff --git a/app/src/main/res/values-lv-rLV/strings.xml b/app/src/main/res/values-lv/strings.xml
similarity index 100%
rename from app/src/main/res/values-lv-rLV/strings.xml
rename to app/src/main/res/values-lv/strings.xml
diff --git a/app/src/main/res/values-ml-rIN/strings.xml b/app/src/main/res/values-ml/strings.xml
similarity index 100%
rename from app/src/main/res/values-ml-rIN/strings.xml
rename to app/src/main/res/values-ml/strings.xml
diff --git a/app/src/main/res/values-mr-rIN/strings.xml b/app/src/main/res/values-mr/strings.xml
similarity index 100%
rename from app/src/main/res/values-mr-rIN/strings.xml
rename to app/src/main/res/values-mr/strings.xml
diff --git a/app/src/main/res/values-my-rMM/strings.xml b/app/src/main/res/values-my/strings.xml
similarity index 100%
rename from app/src/main/res/values-my-rMM/strings.xml
rename to app/src/main/res/values-my/strings.xml
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb/strings.xml
similarity index 100%
rename from app/src/main/res/values-nb-rNO/strings.xml
rename to app/src/main/res/values-nb/strings.xml
diff --git a/app/src/main/res/values-ne-rNP/strings.xml b/app/src/main/res/values-ne/strings.xml
similarity index 100%
rename from app/src/main/res/values-ne-rNP/strings.xml
rename to app/src/main/res/values-ne/strings.xml
diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl/strings.xml
similarity index 100%
rename from app/src/main/res/values-nl-rNL/strings.xml
rename to app/src/main/res/values-nl/strings.xml
diff --git a/app/src/main/res/values-nn-rNO/strings.xml b/app/src/main/res/values-nn/strings.xml
similarity index 100%
rename from app/src/main/res/values-nn-rNO/strings.xml
rename to app/src/main/res/values-nn/strings.xml
diff --git a/app/src/main/res/values-or-rIN/strings.xml b/app/src/main/res/values-or/strings.xml
similarity index 100%
rename from app/src/main/res/values-or-rIN/strings.xml
rename to app/src/main/res/values-or/strings.xml
diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl/strings.xml
similarity index 100%
rename from app/src/main/res/values-pl-rPL/strings.xml
rename to app/src/main/res/values-pl/strings.xml
diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro/strings.xml
similarity index 100%
rename from app/src/main/res/values-ro-rRO/strings.xml
rename to app/src/main/res/values-ro/strings.xml
diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru/strings.xml
similarity index 100%
rename from app/src/main/res/values-ru-rRU/strings.xml
rename to app/src/main/res/values-ru/strings.xml
diff --git a/app/src/main/res/values-si-rLK/strings.xml b/app/src/main/res/values-si/strings.xml
similarity index 100%
rename from app/src/main/res/values-si-rLK/strings.xml
rename to app/src/main/res/values-si/strings.xml
diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk/strings.xml
similarity index 100%
rename from app/src/main/res/values-sk-rSK/strings.xml
rename to app/src/main/res/values-sk/strings.xml
diff --git a/app/src/main/res/values-sl-rSI/strings.xml b/app/src/main/res/values-sl/strings.xml
similarity index 100%
rename from app/src/main/res/values-sl-rSI/strings.xml
rename to app/src/main/res/values-sl/strings.xml
diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr/strings.xml
similarity index 100%
rename from app/src/main/res/values-sr-rSP/strings.xml
rename to app/src/main/res/values-sr/strings.xml
diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv/strings.xml
similarity index 100%
rename from app/src/main/res/values-sv-rSE/strings.xml
rename to app/src/main/res/values-sv/strings.xml
diff --git a/app/src/main/res/values-ta-rIN/strings.xml b/app/src/main/res/values-ta/strings.xml
similarity index 100%
rename from app/src/main/res/values-ta-rIN/strings.xml
rename to app/src/main/res/values-ta/strings.xml
diff --git a/app/src/main/res/values-te-rIN/strings.xml b/app/src/main/res/values-te/strings.xml
similarity index 100%
rename from app/src/main/res/values-te-rIN/strings.xml
rename to app/src/main/res/values-te/strings.xml
diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th/strings.xml
similarity index 100%
rename from app/src/main/res/values-th-rTH/strings.xml
rename to app/src/main/res/values-th/strings.xml
diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr/strings.xml
similarity index 100%
rename from app/src/main/res/values-tr-rTR/strings.xml
rename to app/src/main/res/values-tr/strings.xml
diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk/strings.xml
similarity index 100%
rename from app/src/main/res/values-uk-rUA/strings.xml
rename to app/src/main/res/values-uk/strings.xml
diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi/strings.xml
similarity index 100%
rename from app/src/main/res/values-vi-rVN/strings.xml
rename to app/src/main/res/values-vi/strings.xml
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 0c1a56ce8..4c5b16f9f 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,7 +1,7 @@
-