Skip to content

Commit

Permalink
set system language as default language (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
amir1376 authored Jan 27, 2025
1 parent ddec1f3 commit 30e70f8
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -318,26 +318,36 @@ fun themeConfig(
fun languageConfig(
languageManager: LanguageManager,
scope: CoroutineScope,
): EnumConfigurable<LanguageInfo> {
val currentLanguageName = languageManager.selectedLanguage
val allLanguages = languageManager.languageList
): EnumConfigurable<LanguageInfo?> {
val currentLanguageName = languageManager.selectedLanguageInStorage
val allLanguages = languageManager.languageList.value
return EnumConfigurable(
title = Res.string.settings_language.asStringSource(),
description = "".asStringSource(),
backedBy = createMutableStateFlowFromStateFlow(
flow = currentLanguageName.mapStateFlow { l ->
allLanguages.value.find {
it.toLocaleString() == l
} ?: LanguageManager.DefaultLanguageInfo
flow = currentLanguageName.mapStateFlow { language ->
language?.let {
allLanguages.find {
it.toLocaleString() == language
}
}
},
updater = { languageInfo ->
languageManager.selectLanguage(languageInfo)
},
scope = scope,
),
possibleValues = allLanguages.value,
possibleValues = listOf(null).plus(allLanguages),
describe = {
it.nativeName.asStringSource()
val isAuto = it == null
val language = it ?: languageManager.systemLanguageOrDefault
val languageName = language.nativeName
if (isAuto) {
// always use english here!
"System ($languageName)".asStringSource()
} else {
languageName.asStringSource()
}
},
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import java.io.File
@Serializable
data class AppSettingsModel(
val theme: String = "dark",
val language: String = "en",
val language: String? = null,
val uiScale: Float? = null,
val mergeTopBarWithTitleBar: Boolean = false,
val threadCount: Int = 8,
Expand Down Expand Up @@ -95,7 +95,7 @@ data class AppSettingsModel(
override fun set(source: MapConfig, focus: AppSettingsModel): MapConfig {
return source.apply {
put(Keys.theme, focus.theme)
put(Keys.language, focus.language)
putNullable(Keys.language, focus.language)
putNullable(Keys.uiScale, focus.uiScale)
put(Keys.mergeTopBarWithTitleBar, focus.mergeTopBarWithTitleBar)
put(Keys.threadCount, focus.threadCount)
Expand Down Expand Up @@ -127,14 +127,23 @@ private val uiScaleLens: Lens<AppSettingsModel, Float?>
s.copy(uiScale = f)
}
)
private val languageLens: Lens<AppSettingsModel, String?>
get() = Lens(
get = {
it.language
},
set = { s, f ->
s.copy(language = f)
}
)

class AppSettingsStorage(
settings: DataStore<MapConfig>,
) :
ConfigBaseSettingsByMapConfig<AppSettingsModel>(settings, AppSettingsModel.ConfigLens),
LanguageStorage {
var theme = from(AppSettingsModel.theme)
override val selectedLanguage = from(AppSettingsModel.language)
override val selectedLanguage = from(languageLens)
var uiScale = from(uiScaleLens)
var mergeTopBarWithTitleBar = from(AppSettingsModel.mergeTopBarWithTitleBar)
val threadCount = from(AppSettingsModel.threadCount)
Expand All @@ -152,4 +161,4 @@ class AppSettingsStorage(
val browserIntegrationPort = from(AppSettingsModel.browserIntegrationPort)
val trackDeletedFilesOnDisk = from(AppSettingsModel.trackDeletedFilesOnDisk)
val useBitsForSpeed = from(AppSettingsModel.useBitsForSpeed)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,32 @@ import androidx.compose.runtime.Immutable
import ir.amirab.util.compose.contants.FILE_PROTOCOL
import ir.amirab.util.compose.contants.RESOURCE_PROTOCOL
import ir.amirab.util.flow.mapStateFlow
import ir.amirab.util.flow.mapTwoWayStateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import okio.FileSystem
import okio.Path.Companion.toPath
import okio.buffer
import java.io.InputStream
import java.net.URI
import java.util.Properties
import java.util.*

class LanguageManager(
private val storage: LanguageStorage,
) {
private val _languageList: MutableStateFlow<List<LanguageInfo>> = MutableStateFlow(emptyList())
val languageList = _languageList.asStateFlow()
val selectedLanguage = storage.selectedLanguage
val systemLanguageOrDefault: LanguageInfo by lazy {
getSystemLanguageIfWeCanUse()
}
val selectedLanguageInStorage = storage.selectedLanguage
val selectedLanguage = storage.selectedLanguage.mapStateFlow {
it ?: systemLanguageOrDefault.toLocaleString()
}

// val selectedLanguageInfo = selectedLanguage.mapStateFlow {
// bestLanguageInfo(it)
// }
val isRtl = selectedLanguage.mapStateFlow { selectedLanguage ->
rtlLanguages.any { selectedLanguage.startsWith(it) }
}
Expand All @@ -28,11 +39,11 @@ class LanguageManager(
instance = this
}

fun selectLanguage(languageInfo: LanguageInfo) {
fun selectLanguage(languageInfo: LanguageInfo?) {
// ensure that language info is in the list!
// val languageInfo = languageList.value.find { it == languageInfo }
// selectedLanguage.value = (languageInfo ?: DefaultLanguageInfo).toLocaleString()
selectedLanguage.value = languageInfo.toLocaleString()
selectedLanguageInStorage.value = languageInfo?.toLocaleString()
}

fun getMessage(key: String): String {
Expand All @@ -42,7 +53,7 @@ class LanguageManager(
}

private fun getRequestedLanguage(): String {
return selectedLanguage.value
return selectedLanguage.value ?: systemLanguageOrDefault.toLocaleString()
}

@Volatile
Expand Down Expand Up @@ -74,6 +85,10 @@ class LanguageManager(
}
}

/**
* Find the best language info for the given locale.
* the returned language is guaranteed to be available. (at least [DefaultLanguageInfo])
*/
private fun bestLanguageInfo(locale: String): LanguageInfo {
return languageList.value.find {
it.toLocaleString() == locale
Expand Down Expand Up @@ -122,6 +137,11 @@ class LanguageManager(
}
}

private fun getSystemLanguageIfWeCanUse(): LanguageInfo {
val systemLocale = getSystemLocale().toString()
return bestLanguageInfo(systemLocale)
}

companion object {
lateinit var instance: LanguageManager
private const val LOCALES_PATH = "/com/abdownloadmanager/resources/locales"
Expand All @@ -130,10 +150,8 @@ class LanguageManager(
languageCode = "en",
countryCode = "US",
)
LanguageInfo(
locale = locale,
nativeName = "English",
path = URI("$RESOURCE_PROTOCOL:$LOCALES_PATH/${locale}.properties")
locale.toLanguageInfo(
path = "$RESOURCE_PROTOCOL:$LOCALES_PATH/${locale}.properties",
)
}

Expand Down Expand Up @@ -204,3 +222,11 @@ data class LanguageInfo(
return locale.toString()
}
}

private fun getSystemLocale(): MyLocale {
val javaSystemLocale = Locale.getDefault(Locale.Category.DISPLAY)
return MyLocale(
languageCode = javaSystemLocale.language,
countryCode = javaSystemLocale.country,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package ir.amirab.util.compose.localizationmanager
import kotlinx.coroutines.flow.MutableStateFlow

interface LanguageStorage {
val selectedLanguage: MutableStateFlow<String>
}
// null means auto
val selectedLanguage: MutableStateFlow<String?>
}

0 comments on commit 30e70f8

Please sign in to comment.