2

My app supports two languages(English and Spanish). When I change the locale from English(en) to Spanish(es) it succeeds (Locale get changed). But, resources are not getting updated. I am recreating the activity after updated the Locale.

I have debugged the app on Splash screen after changing the Locale. and check the current Locale (returned 'es'). but still, the strings are not getting updated. The Spanish string file is put under the values-es package.

Also tried running the same localization code by creating a new application and it worked.

Following is the code:

VerifiApp.kt:

class VerifiApp : Application(), HasActivityInjector {

@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

override fun onCreate() {
    super.onCreate()

    if (BuildConfig.DEBUG) {
        Timber.plant(Timber.DebugTree())
    }

    AppInjector.init(this)
}

override fun attachBaseContext(base: Context?) {
    super.attachBaseContext(LocaleHelper.onAttach(base!!, "en"))
}

override fun activityInjector() = dispatchingAndroidInjector
}

SelectLanguageActivity.kt:

class SelectLanguageActivity : BaseActivity<SelectLanguageViewModel>() {

private var languageCode = ""

@Inject
lateinit var appDataManager: AppDataManager

@Inject
lateinit var appViewModelFactory: AppViewModelFactory

private lateinit var selectLanguageViewModel: SelectLanguageViewModel

private lateinit var languageAdapter: ArrayAdapter<Language>

private var languageList = ArrayList<Language>()

override fun getViewModel(): SelectLanguageViewModel {
    selectLanguageViewModel = ViewModelProviders.of(this@SelectLanguageActivity, appViewModelFactory)
        .get(SelectLanguageViewModel::class.java)
    return selectLanguageViewModel
}


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_select_language)

    languageList.add(Language("English", "en"))
    languageList.add(Language("Spanish", "es"))

    languageAdapter = ArrayAdapter(this, R.layout.item_spinner_dropdown, languageList)
    spinnerLanguage.adapter = languageAdapter

    spinnerLanguage.apply {
        onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onNothingSelected(parent: AdapterView<*>?) {
            }

            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                languageCode = languageList[position].languageCode
            }
        }
    }

    btnUpdate.setOnClickListener {

        val context = LocaleHelper.setLocale(this, languageCode)
        val resources = context.resources

        val bundle = Bundle()
        bundle.putString("language_code", languageCode)
        val intent = Intent(applicationContext, AuthActivity::class.java)
        intent.putExtras(bundle)
        startActivity(intent)
    }
}
}

BaseActivity.kt:

abstract class BaseActivity<out V : ViewModel> : AppCompatActivity(), BaseFragment.Callback {

private lateinit var mViewModel: V
private lateinit var progressDialog: Dialog

override fun onCreate(savedInstanceState: Bundle?) {
    performDependencyInjection()
    super.onCreate(savedInstanceState)
    initializeProgressLoader()
}

private fun initializeProgressLoader() {
    progressDialog = Dialog(this)
    progressDialog.setCancelable(false)
    progressDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
    progressDialog.window.setBackgroundDrawableResource(android.R.color.transparent)
    progressDialog.setContentView(R.layout.dialog_progress)
}

fun setProgressVisibility(visible: Boolean) {
    if (visible) {
        progressDialog.show()
    } else {
        progressDialog.dismiss()
    }
}

private fun performDependencyInjection() {
    AndroidInjection.inject(this)
    mViewModel = getViewModel()
}

override fun onFragmentAttached() {

}

override fun onFragmentDetached(tag: String) {

}


fun isNetworkConnected(): Boolean {
    val flag = NetworkUtils.isNetworkConnected(applicationContext)
    if (!flag) {
        showErrorToast("Internet not connected!")
    }
    return flag
}

fun hideKeyboard() {
    val view: View? = this.currentFocus
    val inputMethodManager: InputMethodManager =
        getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0)
}

fun showErrorToast(message: String) {
    ColorToast.makeText(this, message, ColorToast.LENGTH_SHORT, ColorToast.ERROR, false).show()
}

fun showInfoToast(message: String) {
    ColorToast.makeText(this, message, ColorToast.LENGTH_SHORT, ColorToast.INFO, false).show()
}

fun showSuccessToast(message: String) {
    ColorToast.makeText(this, message, ColorToast.LENGTH_SHORT, ColorToast.SUCCESS, false).show()
}


/**
 * Override for set view model
 *
 * @return ViewModel instance
 * */
abstract fun getViewModel(): V

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(LocaleHelper.onAttach(newBase!!))
}
}

LocaleHelper.java

 public class LocaleHelper {

private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";

public static Context onAttach(Context context) {
    String lang = getPersistedData(context, Locale.getDefault().getLanguage());
    return setLocale(context, lang);
}

public static Context onAttach(Context context, String defaultLanguage) {
    String lang = getPersistedData(context, defaultLanguage);
    return setLocale(context, lang);
}

public static String getLanguage(Context context) {
    return getPersistedData(context, Locale.getDefault().getLanguage());
}

public static Context setLocale(Context context, String language) {
    persist(context, language);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, language);
    }

    return updateResourcesLegacy(context, language);
}

private static String getPersistedData(Context context, String defaultLanguage) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
}

private static void persist(Context context, String language) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();

    editor.putString(SELECTED_LANGUAGE, language);
    editor.apply();
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Resources resources = context.getResources();

    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        configuration.setLayoutDirection(locale);
    }

    resources.updateConfiguration(configuration, resources.getDisplayMetrics());

    return context;
}
}

Help would be really appreciated. Thanks.

Ankit Mehta
  • 4,251
  • 4
  • 19
  • 27
  • https://stackoverflow.com/a/52270630/7666442 – AskNilesh Apr 05 '19 at 10:40
  • @NileshRathod as I mentioned the same code is working in a newly created project. Anyway, there are two methods here for changing the locale(createConfigurationContext(configuration)) and updateResources(context, language). – Ankit Mehta Apr 05 '19 at 10:43
  • Try to kill your app and relaunch it. When you run your app on a device, it loads every resources from the locale directory at launch and don't reload it when it comes back from background. – Robert LaFondue Apr 05 '19 at 12:29
  • @RobertLaFondue I have tried this too. the default locale is set to 'es' but strings are still from 'en' – Ankit Mehta Apr 05 '19 at 12:32
  • What is your exact purpose ? As I understand from your code, you want to change the language only in your app, and not on the whole device am I right ? Can you show us how you organized your values directory to handle your en/es resources? – Robert LaFondue Apr 05 '19 at 13:50
  • @RobertLaFondue yes, the language to be changed in the app only. – Ankit Mehta Apr 05 '19 at 14:02
  • @AnkitMehta have you read [this question](https://stackoverflow.com/questions/2900023/change-app-language-programmatically-in-android) and [this one] (https://stackoverflow.com/questions/31945463/change-app-language-in-android-5-0-doesnt-work/33079919#33079919) about changing locale in-app ? – Robert LaFondue Apr 08 '19 at 07:31
  • Were you able to find reason @AnkitMehta? Same here, in a new project it works but on the existing project same implementation is not working :) – togikan Dec 28 '19 at 14:07
  • @togikan, I clearly forgot how it get fixed. as far as i remember it worked after updating the android studio to the latest. – Ankit Mehta Dec 29 '19 at 11:21

1 Answers1

-1

I have the same issue and spent a lot of time trying to find an actual error. ultimately found a solution.

Do a new project and copy all the files to the new project it will solve the error.

Chirag Thummar
  • 665
  • 6
  • 16