[android] Setting to manually set app language (#2951)
It is on the app settings section Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2951 Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev> Co-authored-by: kleidis <kleidis1@protonmail.com> Co-committed-by: kleidis <kleidis1@protonmail.com>
This commit is contained in:
parent
f51d61e4a4
commit
cfbef5c487
|
|
@ -16,11 +16,15 @@ import java.io.FileOutputStream
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
import javax.net.ssl.TrustManagerFactory
|
import javax.net.ssl.TrustManagerFactory
|
||||||
import javax.net.ssl.X509TrustManager
|
import javax.net.ssl.X509TrustManager
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.os.LocaleList
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.DocumentsTree
|
import org.yuzu.yuzu_emu.utils.DocumentsTree
|
||||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
import org.yuzu.yuzu_emu.utils.PowerStateUpdater
|
import org.yuzu.yuzu_emu.utils.PowerStateUpdater
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
||||||
|
|
||||||
|
|
@ -73,5 +77,38 @@ class YuzuApplication : Application() {
|
||||||
|
|
||||||
val appContext: Context
|
val appContext: Context
|
||||||
get() = application.applicationContext
|
get() = application.applicationContext
|
||||||
|
|
||||||
|
private val LANGUAGE_CODES = arrayOf(
|
||||||
|
"system", "en", "es", "fr", "de", "it", "pt", "pt-BR", "ru", "ja", "ko",
|
||||||
|
"zh-CN", "zh-TW", "pl", "cs", "nb", "hu", "uk", "vi", "id", "ar", "ckb", "fa", "he", "sr"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun applyLanguage(context: Context): Context {
|
||||||
|
val languageIndex = IntSetting.APP_LANGUAGE.getInt()
|
||||||
|
val langCode = if (languageIndex in LANGUAGE_CODES.indices) {
|
||||||
|
LANGUAGE_CODES[languageIndex]
|
||||||
|
} else {
|
||||||
|
"system"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (langCode == "system") {
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
val locale = when {
|
||||||
|
langCode.contains("-") -> {
|
||||||
|
val parts = langCode.split("-")
|
||||||
|
Locale.Builder().setLanguage(parts[0]).setRegion(parts[1]).build()
|
||||||
|
}
|
||||||
|
else -> Locale.Builder().setLanguage(langCode).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
Locale.setDefault(locale)
|
||||||
|
|
||||||
|
val config = Configuration(context.resources.configuration)
|
||||||
|
config.setLocales(LocaleList(locale))
|
||||||
|
|
||||||
|
return context.createConfigurationContext(config)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
|
|
||||||
private var foregroundService: Intent? = null
|
private var foregroundService: Intent? = null
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context) {
|
||||||
|
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
Log.gameLaunched = true
|
Log.gameLaunched = true
|
||||||
ThemeHelper.setTheme(this)
|
ThemeHelper.setTheme(this)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||||
MAX_ANISOTROPY("max_anisotropy"),
|
MAX_ANISOTROPY("max_anisotropy"),
|
||||||
THEME("theme"),
|
THEME("theme"),
|
||||||
THEME_MODE("theme_mode"),
|
THEME_MODE("theme_mode"),
|
||||||
|
APP_LANGUAGE("app_language"),
|
||||||
OVERLAY_SCALE("control_scale"),
|
OVERLAY_SCALE("control_scale"),
|
||||||
OVERLAY_OPACITY("control_opacity"),
|
OVERLAY_OPACITY("control_opacity"),
|
||||||
LOCK_DRAWER("lock_drawer"),
|
LOCK_DRAWER("lock_drawer"),
|
||||||
|
|
|
||||||
|
|
@ -757,6 +757,15 @@ abstract class SettingsItem(
|
||||||
titleId = R.string.enable_update_checks,
|
titleId = R.string.enable_update_checks,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SingleChoiceSetting(
|
||||||
|
IntSetting.APP_LANGUAGE,
|
||||||
|
titleId = R.string.app_language,
|
||||||
|
descriptionId = R.string.app_language_description,
|
||||||
|
choicesId = R.array.appLanguageNames,
|
||||||
|
valuesId = R.array.appLanguageValues
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_DEBUG,
|
BooleanSetting.RENDERER_DEBUG,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.ui
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
|
|
@ -24,6 +29,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||||
import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment
|
import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment
|
||||||
import org.yuzu.yuzu_emu.utils.*
|
import org.yuzu.yuzu_emu.utils.*
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class SettingsActivity : AppCompatActivity() {
|
class SettingsActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivitySettingsBinding
|
private lateinit var binding: ActivitySettingsBinding
|
||||||
|
|
@ -32,6 +38,10 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context) {
|
||||||
|
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
ThemeHelper.setTheme(this)
|
ThemeHelper.setTheme(this)
|
||||||
|
|
||||||
|
|
@ -125,6 +135,16 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
NativeConfig.savePerGameConfig()
|
NativeConfig.savePerGameConfig()
|
||||||
NativeConfig.unloadPerGameConfig()
|
NativeConfig.unloadPerGameConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsViewModel.shouldRecreateForLanguageChange.value) {
|
||||||
|
settingsViewModel.setShouldRecreateForLanguageChange(false)
|
||||||
|
val relaunchIntent = packageManager?.getLaunchIntentForPackage(packageName)
|
||||||
|
if (relaunchIntent != null) {
|
||||||
|
relaunchIntent.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK or android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
startActivity(relaunchIntent)
|
||||||
|
android.os.Process.killProcess(android.os.Process.myPid())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,6 +425,14 @@ class SettingsAdapter(
|
||||||
position
|
position
|
||||||
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
||||||
|
|
||||||
|
// reset language if detected
|
||||||
|
if (item.setting.key == "app_language") {
|
||||||
|
// recreate page apply language change instantly
|
||||||
|
fragment.requireActivity().recreate()
|
||||||
|
|
||||||
|
settingsViewModel.setShouldRecreateForLanguageChange(true)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -387,6 +387,12 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
scSetting.setSelectedValue(value)
|
scSetting.setSelectedValue(value)
|
||||||
|
|
||||||
|
if (scSetting.setting.key == "app_language") {
|
||||||
|
settingsViewModel.setShouldRecreateForLanguageChange(true)
|
||||||
|
// recreate page apply language change instantly
|
||||||
|
requireActivity().recreate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is StringSingleChoiceSetting -> {
|
is StringSingleChoiceSetting -> {
|
||||||
|
|
|
||||||
|
|
@ -1030,8 +1030,10 @@ class SettingsFragmentPresenter(
|
||||||
override fun reset() = IntSetting.THEME.setInt(defaultValue)
|
override fun reset() = IntSetting.THEME.setInt(defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add(HeaderSetting(R.string.app_settings))
|
||||||
|
add(IntSetting.APP_LANGUAGE.key)
|
||||||
|
|
||||||
if (NativeLibrary.isUpdateCheckerEnabled()) {
|
if (NativeLibrary.isUpdateCheckerEnabled()) {
|
||||||
add(HeaderSetting(R.string.app_settings))
|
|
||||||
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
|
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -54,6 +57,8 @@ class SettingsViewModel : ViewModel() {
|
||||||
private val _shouldShowResetInputDialog = MutableStateFlow(false)
|
private val _shouldShowResetInputDialog = MutableStateFlow(false)
|
||||||
val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow()
|
val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow()
|
||||||
|
|
||||||
|
private val _shouldRecreateForLanguageChange = MutableStateFlow(false)
|
||||||
|
val shouldRecreateForLanguageChange = _shouldRecreateForLanguageChange.asStateFlow()
|
||||||
fun setShouldRecreate(value: Boolean) {
|
fun setShouldRecreate(value: Boolean) {
|
||||||
_shouldRecreate.value = value
|
_shouldRecreate.value = value
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +108,10 @@ class SettingsViewModel : ViewModel() {
|
||||||
_shouldShowResetInputDialog.value = value
|
_shouldShowResetInputDialog.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setShouldRecreateForLanguageChange(value: Boolean) {
|
||||||
|
_shouldRecreateForLanguageChange.value = value
|
||||||
|
}
|
||||||
|
|
||||||
fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage =
|
fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage =
|
||||||
try {
|
try {
|
||||||
InputHandler.registeredControllers[currentDevice]
|
InputHandler.registeredControllers[currentDevice]
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
package org.yuzu.yuzu_emu.ui.main
|
package org.yuzu.yuzu_emu.ui.main
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
@ -53,6 +54,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import kotlin.text.compareTo
|
import kotlin.text.compareTo
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), ThemeProvider {
|
class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
|
|
@ -68,6 +70,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
private val CHECKED_DECRYPTION = "CheckedDecryption"
|
private val CHECKED_DECRYPTION = "CheckedDecryption"
|
||||||
private var checkedDecryption = false
|
private var checkedDecryption = false
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context) {
|
||||||
|
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
val splashScreen = installSplashScreen()
|
val splashScreen = installSplashScreen()
|
||||||
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ namespace AndroidSettings {
|
||||||
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
||||||
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
|
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
|
||||||
Settings::Category::Android};
|
Settings::Category::Android};
|
||||||
|
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
|
||||||
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
|
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
|
||||||
Settings::Category::Android};
|
Settings::Category::Android};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,61 @@
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
<string-array name="appLanguageNames">
|
||||||
|
<item>@string/app_language_system</item>
|
||||||
|
<item>@string/app_language_english</item>
|
||||||
|
<item>@string/app_language_spanish</item>
|
||||||
|
<item>@string/app_language_french</item>
|
||||||
|
<item>@string/app_language_german</item>
|
||||||
|
<item>@string/app_language_italian</item>
|
||||||
|
<item>@string/app_language_portuguese</item>
|
||||||
|
<item>@string/app_language_brazilian_portuguese</item>
|
||||||
|
<item>@string/app_language_russian</item>
|
||||||
|
<item>@string/app_language_japanese</item>
|
||||||
|
<item>@string/app_language_korean</item>
|
||||||
|
<item>@string/app_language_simplified_chinese</item>
|
||||||
|
<item>@string/app_language_traditional_chinese</item>
|
||||||
|
<item>@string/app_language_polish</item>
|
||||||
|
<item>@string/app_language_czech</item>
|
||||||
|
<item>@string/app_language_norwegian</item>
|
||||||
|
<item>@string/app_language_hungarian</item>
|
||||||
|
<item>@string/app_language_ukrainian</item>
|
||||||
|
<item>@string/app_language_vietnamese</item>
|
||||||
|
<item>@string/app_language_indonesian</item>
|
||||||
|
<item>@string/app_language_arabic</item>
|
||||||
|
<item>@string/app_language_central_kurdish</item>
|
||||||
|
<item>@string/app_language_persian</item>
|
||||||
|
<item>@string/app_language_hebrew</item>
|
||||||
|
<item>@string/app_language_serbian</item>
|
||||||
|
</string-array>
|
||||||
|
<integer-array name="appLanguageValues">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>6</item>
|
||||||
|
<item>7</item>
|
||||||
|
<item>8</item>
|
||||||
|
<item>9</item>
|
||||||
|
<item>10</item>
|
||||||
|
<item>11</item>
|
||||||
|
<item>12</item>
|
||||||
|
<item>13</item>
|
||||||
|
<item>14</item>
|
||||||
|
<item>15</item>
|
||||||
|
<item>16</item>
|
||||||
|
<item>17</item>
|
||||||
|
<item>18</item>
|
||||||
|
<item>19</item>
|
||||||
|
<item>20</item>
|
||||||
|
<item>21</item>
|
||||||
|
<item>22</item>
|
||||||
|
<item>23</item>
|
||||||
|
<item>24</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="outputEngineEntries">
|
<string-array name="outputEngineEntries">
|
||||||
<item>@string/auto</item>
|
<item>@string/auto</item>
|
||||||
<item>@string/oboe</item>
|
<item>@string/oboe</item>
|
||||||
|
|
|
||||||
|
|
@ -1028,6 +1028,35 @@
|
||||||
<string name="use_black_backgrounds">Black backgrounds</string>
|
<string name="use_black_backgrounds">Black backgrounds</string>
|
||||||
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
||||||
|
|
||||||
|
<!-- App Language -->
|
||||||
|
<string name="app_language">App Language</string>
|
||||||
|
<string name="app_language_description">Change the language of the app interface</string>
|
||||||
|
<string name="app_language_system">Follow System</string>
|
||||||
|
<string name="app_language_english">English</string>
|
||||||
|
<string name="app_language_spanish">Español</string>
|
||||||
|
<string name="app_language_french">Français</string>
|
||||||
|
<string name="app_language_german">Deutsch</string>
|
||||||
|
<string name="app_language_italian">Italiano</string>
|
||||||
|
<string name="app_language_portuguese">Português</string>
|
||||||
|
<string name="app_language_brazilian_portuguese">Português do Brasil</string>
|
||||||
|
<string name="app_language_russian">Русский</string>
|
||||||
|
<string name="app_language_japanese">日本語</string>
|
||||||
|
<string name="app_language_korean">한국어</string>
|
||||||
|
<string name="app_language_simplified_chinese">简体中文</string>
|
||||||
|
<string name="app_language_traditional_chinese">繁體中文</string>
|
||||||
|
<string name="app_language_polish">Polski</string>
|
||||||
|
<string name="app_language_czech">Čeština</string>
|
||||||
|
<string name="app_language_norwegian">Norsk bokmål</string>
|
||||||
|
<string name="app_language_hungarian">Magyar</string>
|
||||||
|
<string name="app_language_ukrainian">Українська</string>
|
||||||
|
<string name="app_language_vietnamese">Tiếng Việt</string>
|
||||||
|
<string name="app_language_indonesian">Bahasa Indonesia</string>
|
||||||
|
<string name="app_language_arabic">العربية</string>
|
||||||
|
<string name="app_language_central_kurdish">کوردیی ناوەندی</string>
|
||||||
|
<string name="app_language_persian">فارسی</string>
|
||||||
|
<string name="app_language_hebrew">עברית</string>
|
||||||
|
<string name="app_language_serbian">Српски</string>
|
||||||
|
|
||||||
<!-- Static Themes -->
|
<!-- Static Themes -->
|
||||||
<string name="static_theme_color">Theme Color</string>
|
<string name="static_theme_color">Theme Color</string>
|
||||||
<string name="eden_theme">Eden (Default)</string>
|
<string name="eden_theme">Eden (Default)</string>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue