[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:
@@ -16,11 +16,15 @@ import java.io.FileOutputStream
|
||||
import java.security.KeyStore
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
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.DocumentsTree
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.PowerStateUpdater
|
||||
import java.util.Locale
|
||||
|
||||
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
||||
|
||||
@@ -73,5 +77,38 @@ class YuzuApplication : Application() {
|
||||
|
||||
val appContext: Context
|
||||
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
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Log.gameLaunched = true
|
||||
ThemeHelper.setTheme(this)
|
||||
|
||||
@@ -32,6 +32,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
MAX_ANISOTROPY("max_anisotropy"),
|
||||
THEME("theme"),
|
||||
THEME_MODE("theme_mode"),
|
||||
APP_LANGUAGE("app_language"),
|
||||
OVERLAY_SCALE("control_scale"),
|
||||
OVERLAY_OPACITY("control_opacity"),
|
||||
LOCK_DRAWER("lock_drawer"),
|
||||
|
||||
@@ -757,6 +757,15 @@ abstract class SettingsItem(
|
||||
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(
|
||||
SwitchSetting(
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
import android.content.Context
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
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.fragments.ResetSettingsDialogFragment
|
||||
import org.yuzu.yuzu_emu.utils.*
|
||||
import org.yuzu.yuzu_emu.utils.collect
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
@@ -32,6 +38,10 @@ class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ThemeHelper.setTheme(this)
|
||||
|
||||
@@ -125,6 +135,16 @@ class SettingsActivity : AppCompatActivity() {
|
||||
NativeConfig.savePerGameConfig()
|
||||
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
|
||||
).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
|
||||
}
|
||||
|
||||
|
||||
@@ -387,6 +387,12 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||
.show()
|
||||
}
|
||||
scSetting.setSelectedValue(value)
|
||||
|
||||
if (scSetting.setting.key == "app_language") {
|
||||
settingsViewModel.setShouldRecreateForLanguageChange(true)
|
||||
// recreate page apply language change instantly
|
||||
requireActivity().recreate()
|
||||
}
|
||||
}
|
||||
|
||||
is StringSingleChoiceSetting -> {
|
||||
|
||||
@@ -1030,8 +1030,10 @@ class SettingsFragmentPresenter(
|
||||
override fun reset() = IntSetting.THEME.setInt(defaultValue)
|
||||
}
|
||||
|
||||
add(HeaderSetting(R.string.app_settings))
|
||||
add(IntSetting.APP_LANGUAGE.key)
|
||||
|
||||
if (NativeLibrary.isUpdateCheckerEnabled()) {
|
||||
add(HeaderSetting(R.string.app_settings))
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -54,6 +57,8 @@ class SettingsViewModel : ViewModel() {
|
||||
private val _shouldShowResetInputDialog = MutableStateFlow(false)
|
||||
val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow()
|
||||
|
||||
private val _shouldRecreateForLanguageChange = MutableStateFlow(false)
|
||||
val shouldRecreateForLanguageChange = _shouldRecreateForLanguageChange.asStateFlow()
|
||||
fun setShouldRecreate(value: Boolean) {
|
||||
_shouldRecreate.value = value
|
||||
}
|
||||
@@ -103,6 +108,10 @@ class SettingsViewModel : ViewModel() {
|
||||
_shouldShowResetInputDialog.value = value
|
||||
}
|
||||
|
||||
fun setShouldRecreateForLanguageChange(value: Boolean) {
|
||||
_shouldRecreateForLanguageChange.value = value
|
||||
}
|
||||
|
||||
fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage =
|
||||
try {
|
||||
InputHandler.registeredControllers[currentDevice]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package org.yuzu.yuzu_emu.ui.main
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
@@ -53,6 +54,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import kotlin.text.compareTo
|
||||
import androidx.core.net.toUri
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
|
||||
class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
@@ -68,6 +70,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
private val CHECKED_DECRYPTION = "CheckedDecryption"
|
||||
private var checkedDecryption = false
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace AndroidSettings {
|
||||
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
||||
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
|
||||
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::Category::Android};
|
||||
|
||||
|
||||
@@ -391,6 +391,61 @@
|
||||
<item>2</item>
|
||||
</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">
|
||||
<item>@string/auto</item>
|
||||
<item>@string/oboe</item>
|
||||
|
||||
@@ -1028,6 +1028,35 @@
|
||||
<string name="use_black_backgrounds">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 -->
|
||||
<string name="static_theme_color">Theme Color</string>
|
||||
<string name="eden_theme">Eden (Default)</string>
|
||||
|
||||
Reference in New Issue
Block a user