Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why my app gets wrong strings from resources for localization?

Tags:

android

I have created three files for localisation: "en","ru","uk" and I saw problem app can get some strings right and some string wrong. What it means? For example one layout during its working can contain several locales instead one single and it is wrong. I saw that some users solved this problem via adding some lines of code to buil.gradle but maybe we have another solution and why did it worked well several weeks ago when my project was in Java. I'm sure that it can't be caused by moving from one language to another. At recyclerView I can see similar problem. At activity I can set my current language like this:

sp = this.getSharedPreferences("app_data", 0)
        val lang = sp!!.getString("language", Locale.getDefault().language)
        val locale = Locale(lang)
        Locale.setDefault(locale)
        val config = Configuration()
        config.setLocale(locale)

        resources.updateConfiguration(
                config, resources.displayMetrics
        )

but updateConfiguration is deprecated and I looked for some new variants which will work. Then I found this question but it didn't help me. I need to set language at RV items, activities and fragments, but I can't do it. Why does it happen and how I can solve this problem?

like image 295
Andrew Avatar asked Mar 03 '23 22:03

Andrew


1 Answers

I actually JUST had to do this myself. Its a pain, especially for newer devices.

First, you need a locale helper:

package za.co.overtake.onlinetrucks.utils;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;

import java.util.Locale;

/**
 * This class is used to change your application locale and persist this change for the next time
 * that your app is going to be used.
 * <p/>
 * You can also change the locale of your application on the fly by using the setLocale method.
 * <p/>
 * Created by gunhansancar on 07/10/15.
 */
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;
}
}

This takes care of switching the language as well as using the deprecated or non-deprecated method.

THEN in each activity, you need to override this method ( I suggest you just make a base activity that each activity extends):

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(LocaleHelper.onAttach(base));
}

This should take care of MOST cases. However, I use ViewModels, and for some reason when I do getApplication.getResources().getString() it would sometimes return the wrong string. In such a case, I made a Utility method to take care of this issue:

public static Resources getResources(Context context) {
    return LocaleHelper.onAttach(context).getResources();
}

So now I can use this method instead of the usual getResources().

It's a REAL pain, but it's the only way I could get translations to work on both devices higher than android 8 AND lower than android8.

I will post the links to some of this in a bit...

EDIT: Also, like previous answers stated, you need to recreate the activity from which you had changed the language.

Links: https://proandroiddev.com/change-language-programmatically-at-runtime-on-android-5e6bc15c758

https://gunhansancar.com/change-language-programmatically-in-android/

like image 60
Zee Avatar answered Apr 01 '23 00:04

Zee