Localization not working after app restart - android

I'm including localization to translate my app intro three different languages, after setting up the translated strings of each language, I go to preference settings and I check a checkbox and and the translation works fine, the problem is that when I restart the app , localization even though I have saved the chosen language in sharedpreference and retreiving it in mainactivity
*This is how I'm setting the languages
var sharedPreferences = requireContext().getSharedPreferences("prefs",
Context.MODE_PRIVATE)
var editor = sharedPreferences.edit()
spanishCheckBox.setOnPreferenceChangeListener(object : Preference.OnPreferenceChangeListener{
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
var isSpanishChecked = newValue as Boolean
if(isSpanishChecked){
var Lang = "es"
editor.putString("key",Lang)
editor.apply()
var local = Locale(Lang)
var configuration = Configuration()
configuration.locale = local
resources.updateConfiguration(configuration,resources.displayMetrics)
englishCheckBox.isChecked = false
frenchCheckBox.isChecked = false
Intent(requireContext(),MainActivity::class.java).also {
it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(it)
}
}
return true
}
})
This is how i m retreiving data in mainactivity
fun LoadLanguageConfiguration(){
var sharedpreferences = getSharedPreferences("prefs", Context.MODE_PRIVATE)
var langCode = sharedpreferences.getString("key","")
var local = Locale(langCode)
var configuration = Configuration()
configuration.locale = local
baseContext.createConfigurationContext(configuration)
}
The translation only works when I set the language in the app, but when I restart the app, it goes back to default language which is English.

The problem is that I was not starting my language loading method at the start and before everything, so I put it as first method in my oncreate and everything works as supposed to.

Related

Changing the App Language not working correctly (Kotlin)

I have a Splash screen in my kotlin app, where I do some stuff like loading data. Currently it is only in german and I wanted to add english as additional language.
I've create the strings resources and so on.
Now I have added a bit of code to the Splash-Screen, where it checks, if the user already set a preferenced language (saved in sharedPreferences).
When there is nothing saved, a simple alertdialog pops up asking the user for his preference and sets everything accordingly.
Then the splashscreen is reloaded. When I choose english on my device (system language is german), the splash screen gets the correct string resources (english).
But when it changes to the MainActivity, it is german again. Only after restarting the app, everything is in english.
Here is how I change the language on my splashscreen:
private lateinit var mainIntent : Intent
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
var localeToSet: String? = prefs.getString("language", "")
if(localeToSet == null || localeToSet.equals("")){
val languages = arrayOf("Deutsch", "English")
val langSelectorBuilder = AlertDialog.Builder(this)
langSelectorBuilder.setTitle(R.string.selectLanguageText)
langSelectorBuilder.setCancelable(false)
langSelectorBuilder.setSingleChoiceItems(languages, -1) { dialog, selection ->
when(selection) {
0 -> {
localeToSet = "de"
setLocale("de")
}
1 -> {
localeToSet = "en"
setLocale("en")
}
}
recreate()
dialog.dismiss()
}.setOnDismissListener {
Handler().postDelayed({
startActivity(mainIntent)
finish()
}, SPLASH_TIME_OUT)
}
langSelectorBuilder.create().show()
}
else{
setLocale(localeToSet!!)
Handler().postDelayed({
startActivity(mainIntent)
finish()
}, SPLASH_TIME_OUT)
}
setContentView(R.layout.activity_splash_screen)
}
private fun createIntent(localeToSet: String){
mainIntent = Intent(this#SplashScreenActivity, MainActivity::class.java).apply {
//Do stuff and pass data to mainactivity
}
private fun setLocale(localeToSet: String) {
createIntent(localeToSet)
val config = resources.configuration
val locale = Locale(localeToSet)
Locale.setDefault(locale)
config.locale = locale
resources.updateConfiguration(config, resources.displayMetrics)
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val editor: SharedPreferences.Editor = prefs.edit()
editor.putString("language", localeToSet)
editor.apply()
}
Nevermind, found the issue:
val langSelectorBuilder = AlertDialog.Builder(this)
langSelectorBuilder.setTitle(R.string.selectLanguageText)
langSelectorBuilder.setCancelable(false)
langSelectorBuilder.setSingleChoiceItems(languages, -1) { dialog, selection ->
when(selection) {
0 -> {
localeToSet = "de"
setLocale("de")
}
1 -> {
localeToSet = "en"
setLocale("en")
}
}
recreate()
dialog.dismiss()
}.setOnDismissListener {
finish()
}
langSelectorBuilder.create().show()
Without starting the MainActivity here, it works like it should

setting language before setContentView results in unending loop

I have a fragment with settings of an app that saves the user selected mode and language
( a bit of code:
binding.languageButton.setOnClickListener{
builder = AlertDialog.Builder(requireContext())
builder.setTitle(getString(R.string.setLanguage))
builder.setItems(langArray) { _, which ->
val sharedPref = requireActivity().getSharedPreferences("Settings", Context.MODE_PRIVATE).edit()
sharedPref.putString("LANGUAGE", langArray[which]).apply()
checkUserPreferences()
changeLanguage(langArray[which])
binding.languageButton.text = langArray[which]
}
builder.create()
builder.show()
}
}
private fun changeLanguage(language: String) {
if(language != binding.languageButton.text.toString()){
val local = Locale(language)
val dm = resources.displayMetrics
val con = resources.configuration
con.locale = local
resources.updateConfiguration(con, dm)
val refresh = Intent(
requireContext(),
MainActivity::class.java
)
refresh.putExtra(binding.languageButton.text.toString(), language)
startActivity(refresh)
}
}
and that part (as mentioned) saves mode and selected language to sharedPreferences that I later want to use in mainActivity and other fragments, and I've put in MainActivity:
private fun loadPreferences(){
val preferences = getSharedPreferences("Settings", Activity.MODE_PRIVATE)
Log.i(TAG, preferences.getString("LANGUAGE", "eng").toString())
Log.i(TAG, preferences.getInt("MODE", 1).toString())
val local = Locale(preferences.getString("LANGUAGE", "eng").toString())
val dm = resources.displayMetrics
val con = resources.configuration
con.locale = local
resources.updateConfiguration(con, dm)
val refresh = Intent(
this.baseContext,
MainActivity::class.java
)
refresh.putExtra(preferences.getString("LANGUAGE", "eng").toString(),
preferences.getString("LANGUAGE", "eng"))
startActivity(refresh)
}
and this is referenced in:
class MainActivity : AppCompatActivity() {
// TODO: IT'S THE ONE
companion object {
private const val TAG = "MainActivity"
private const val CHANNEL_ID = "plantz_app_channel_01"
private const val notificationId = 909
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadPreferences()
setContentView(R.layout.activity_main)
// ...
and after running the app It only shows the app logo and logs sharedPreferences but the app doesn't go any further, I've tried to tweak with it for a bit but It hasn't done much, any ideas what should I change to make it work?
Thanks in advance :)
This infinity loop happens because when the MainActivity is going to be opened you call loadPreferences() in onCreate method where you open a new instance of MainActivity from there.
So the infinity loop goes like below:
onCreate() method of MainActivity is called
loadPreferences() method is called
in loadPreferences() after you have set the language from SharedPreferences you start a new instance of your MainActivity which redirects you back to step 1.
To avoid this infinity loop remove the below lines from your loadPreferences() method:
val refresh = Intent(this.baseContext,MainActivity::class.java)
refresh.putExtra(preferences.getString("LANGUAGE", "eng").toString(), preferences.getString("LANGUAGE", "eng"))
startActivity(refresh)

How to add new object in Kotlin SharedPreferences

I have this preference manager
class JournalManager {
lateinit var pref: SharedPreferences
lateinit var editor: SharedPreferences.Editor
lateinit var con: Context
var PRIVATE_MODE: Int = 0
constructor(con: Context?) {
if (con != null) {
this.con = con
}
if (con != null) {
pref = con.getSharedPreferences(PREF_NAME,PRIVATE_MODE)
}
editor = pref.edit()
}
companion object {
val PREF_NAME: String = "Journal"
val KEY_TEXT: String = "text"
}
fun createJournalSession(
text: EditText,
) {
editor.putString(KEY_TEXT, text.toString())
editor.commit()
}
fun getJournalDetails(): Map<String, String>
{
var journal: Map<String, String> = HashMap<String, String>()
pref.getString(KEY_TEXT,null)?.let { (journal as HashMap).put(KEY_TEXT, it) }
return journal
}
fun DeleteJournal() {
editor.clear()
editor.commit()
var i: Intent = Intent(con, JournalActivity::class.java)
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
con.startActivity(i)
}
}
And I'm looking for solution to add objects in it but my app is crashing, here is a sample of how I try to add object
lateinit var journalSession: JournalManager
override fun onCreate(savedInstanceState: Bundle?) {...}
fun openDialog() {
val dialog = MaterialDialog(this)
.noAutoDismiss()
.customView(R.layout.layout_new_journal)
//set initial preferences
dialog.findViewById<Button>(R.id.save_btn).setOnClickListener{
val note = dialog.findViewById<EditText>(R.id.new_journal_input)
//add to preference
journalSession.createJournalSession(
note
)
dialog.dismiss()
}
dialog.findViewById<Button>(R.id.cancel_btn).setOnClickListener {
dialog.dismiss()
}
dialog.show()
}
Any suggestion?
Update
Let me make it clear what I'm looking for:
At the beginning I do not have any data, nor shared preference in device (shared preference will create when user saves it's first journal).
2.When user adds new journal it suppose to be stored (as of sample) like this
journal [{
note="this was user first note"
}]
Then when next time user adds new journal, it suppose to be stored (as of sample) like this
journal [{
note="this was user first note"
},
{note="this was user second note"
}]
and so on...
PS So far all videos, articles anything else I've found on web was with same logic: (they've had a List and then store that list into preferences!), my case is not like that, I do not have any list to store my list will be created one by one, during the time just like any real world apps.
Now, any idea how to make it happen, and what should I change in my code?
SharedPreferences saves primitive type data and Srting. For saving object like List you can use GSON library (by Google) to convert the object into JSON String.
1. Import Dependency:
implementation 'com.google.code.gson:gson:2.8.6'
2. Basic Usage:
val studentJsonString = Gson().toJson(student) //object -> String
val student = Gson().fromJson(studentJsonString, Student.class) //String -> object
3. For List:
val typeToken = TypeToken<List<Student>>(){}
val students = Gson().fromJson(studentsJsonString, typeToken.getType())

check value exists or not using EncryptedSharedPreferences android

I use the EncryptedSharedPreferences to store value while login...i want to change text in navigation drawer of home activity
so when user is loggedin it will show logout else it will show login navigation drawer
Loginactivity:--------
sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
baseContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
) as EncryptedSharedPreferences
while login im doing this
val editor = sharedPreferences.edit()
editor.putString("EmailId", edtEmailId)
editor.putString("password", edtPassword)
editor.apply()
checking in Homeactivity:---------
val menu: Menu = bind.navRightView.getMenu()
val nav_connection: MenuItem = menu.findItem(R.id.nav_login)
val sharedPreference =
applicationContext.getSharedPreferences("secret_shared_prefs", Context.MODE_PRIVATE)
val value: String = sharedPreference.getString("EmailId", null).toString()
if(!sharedPreference.contains(value))
{
nav_connection.title = "Loginn"
}
else{
nav_connection.title = "Logout"
}
well output of this code is always having a title as loginn that means it detecting value as null
need help for EncryptedSharedPreferences thanks
You are adding the values but not saving them to SharedPreferences.
You should be using commit() or apply().
Do this:
val editor = sharedPreferences.edit()
editor.putString("EmailId", edtEmailId)
editor.putString("password", edtPassword)
editor.apply() // Important
I also see that you are calling
val sharedPreference = applicationContext.getSharedPreferences("secret_shared_prefs", Context.MODE_PRIVATE)`
which gives you the normal SharedPreference, I guess.
You should be using:
val sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
baseContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
) as EncryptedSharedPreferences
Then check if the email address is empty or not.
if(!sharedPreference.contains("EmailId")
nav_connection.title = "Loginn"
else
nav_connection.title = "Logout"

How to change language in kotlin (locale)

I have 2 string files "en" and "tr". When I change my telephone's language string files change automatically(I didn't write extra code for this result and I don't know how this happen). I want change string files with programmatically.
I used this code. I get Toast message but language doesn't change.WHY? I used these code before for another application which I write with java not Kotlin and these code work fine. Please don't say duplicate because I read a lot of questions. I try a lot of things until now 4 hours.
override fun onResume() {
buttonDate()
changeLanguage()
super.onResume()
}
fun changeLanguage(){
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
val language = sharedPreferences.getString("language","bak")
Toast.makeText(applicationContext,language,Toast.LENGTH_SHORT).show()
if(language=="English"){
Toast.makeText(applicationContext,"English",Toast.LENGTH_SHORT).show()
language("")
}else if(language=="Turkish"){
Toast.makeText(applicationContext,"Turkish",Toast.LENGTH_SHORT).show()
language("tr")
}
}
fun language(language: String){
val locale = Locale(language)
Locale.setDefault(locale)
val resources = getResources()
val configuration = resources.getConfiguration()
configuration.locale = locale
resources.updateConfiguration(configuration, resources.getDisplayMetrics())
}
You need to update configuration even before onCreate is called. To do that
create a BaseActivity class like this
open class BaseActivity : AppCompatActivity() {
companion object {
public var dLocale: Locale? = null
}
init {
updateConfig(this)
}
fun updateConfig(wrapper: ContextThemeWrapper) {
if(dLocale==Locale("") ) // Do nothing if dLocale is null
return
Locale.setDefault(dLocale)
val configuration = Configuration()
configuration.setLocale(dLocale)
wrapper.applyOverrideConfiguration(configuration)
}
}
Extend you activities from this class.
Set dLocale in you App class like this:
class App : Application() {
override fun onCreate() {
super.onCreate()
var change = ""
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val language = sharedPreferences.getString("language", "bak")
if (language == "Turkish") {
change="tr"
} else if (language=="English" ) {
change = "en"
}else {
change =""
}
BaseActivity.dLocale = Locale(change) //set any locale you want here
}
}
You will also need to set App class in your manifest file like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
//..
<application
android:name=".App"
//..>
</application>
</manifest>
Note: We should set dLocale only in App onCreate to ensure that all activities have same language.

Categories

Resources