preface

Recently, internationalization was used in the project, so I studied the implementation method; First, let’s talk about the project requirements:

  • You can switch languages as the system switches languages. Unsupported languages are displayed by default
  • The user can select the language, and it will not be restored when the system changes the language or the application restarts

Although the demand is still very simple, but the implementation is still encountered a lot of trouble, first look at the renderings:

Old rule

Program source code

Implementation approach

  • In the application ofattachBaseContextSets the language of the current settingLocal
  • In the application ofonConfigurationChanged(called when system language changes) sets the current languageLocal
  • In the ActivityattachBaseContextSets the language of the current settingLocal, so it’s usually createBaseActivityTo facilitate uniform change
  • In the service ofattachBaseContextSets the language of the current settingLocal

The implementation code

It’s pretty clear how to do it,

  • The first step is definitely to create string.xml in the corresponding language. In the demo, I only implemented three languages: Chinese simplified, Chinese traditional, and English

  • Because of this we want to save the user’s chosen language, so here we create a singleton for SharedPreferences:

public class SPUtil {

    private final String SP_NAME = "language_setting";
    private final String TAG_LANGUAGE = "language_select";
    private static volatile SPUtil instance;

    private final SharedPreferences mSharedPreferences;

    public SPUtil(Context context) {
        mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
    }


    public void saveLanguage(int select) {
        SharedPreferences.Editor edit = mSharedPreferences.edit();
        edit.putInt(TAG_LANGUAGE, select);
        edit.commit();
    }

    public int getSelectLanguage() {
        return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
    }

    public static SPUtil getInstance(Context context) {
        if (instance == null) {
            synchronized (SPUtil.class) {
                if(instance == null) { instance = new SPUtil(context); }}}returninstance; }}Copy the code

Create Util for the management language

  • Create obtain the corresponding value based on user SettingsLocalMethods:
/** * get the selected language Settings ** @param context * @return
     */
    public static Locale getSetLanguageLocale(Context context) {

        switch (SPUtil.getInstance(context).getSelectLanguage()) {
            caseZero:return getSystemLocale(context);
            case 1:
                return Locale.CHINA;
            case 2:
                return Locale.TAIWAN;
            case 3:
            default:
                returnLocale.ENGLISH; }} /** * gets the system locale ** @return*/ public static Locale getSystemLocale(Context Context) {Locale Locale;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            locale = LocaleList.getDefault().get(0);
        } else {
            locale = Locale.getDefault();
        }
        return locale;
    }
Copy the code
  • To create changeLocalmethods
public static Context setLocal(Context context) {
        return updateResources(context, getSetLanguageLocale(context));
    }

    private static Context updateResources(Context context, Locale locale) {
        Locale.setDefault(locale);

        Resources res = context.getResources();
        Configuration config = new Configuration(res.getConfiguration());
        if (Build.VERSION.SDK_INT >= 17) {
            config.setLocale(locale);
            context = context.createConfigurationContext(config);
        } else {
            config.locale = locale;
            res.updateConfiguration(config, res.getDisplayMetrics());
        }
        return context;
    }
Copy the code
  • Called in the appropriate place
#Application
 @Override
    protected void attachBaseContext(Context base) {
       super.attachBaseContext(LocalManageUtil.setLocal(base));
    }

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocalManageUtil.setLocal(context);
    }
Copy the code
#BaseActivity
@Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(LocalManageUtil.setLocal(newBase));
    }
Copy the code
#service
@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocalManageUtil.setLocal(base));
    }
Copy the code
  • To switch between languages
private void selectLanguage(int select) { LocalManageUtil.saveSelectLanguage(this, select); Mainactivity. reStart(this); }Copy the code

Done,

Yes, it’s that simple.

But there’s always something you can’t think of

We all call context.getResource().getString() in our code. This code looks fine, but if you use applicationContext for your context, you get a problem. You’ll notice that the string set this way doesn’t change when you switch languages, so we need to change our code. The solution is to update your Application’s updateConfiguration after switching languages:

/** * Set the language */ public static voidsetApplicationLanguage(Context context) {
        Resources resources = context.getApplicationContext().getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        Configuration config = resources.getConfiguration();
        Locale locale = getSetLanguageLocale(context);
        config.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            LocaleList localeList = new LocaleList(locale);
            LocaleList.setDefault(localeList);
            config.setLocales(localeList);
            context.getApplicationContext().createConfigurationContext(config);
            Locale.setDefault(locale);
        }
        resources.updateConfiguration(config, dm);
    }
Copy the code
  • But when you call this code and you get the system selection language is the language you set, that’s not accurate, so what do you do? It’s very simple, we just save the actual system language.

  • We add the system Local variable to the SharedPreferences singleton:

*/ private Locale systemCurrentLocal = locale.english; public intgetSelectLanguage() {
        return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
    }


    public Locale getSystemCurrentLocal() {
        return systemCurrentLocal;
    }
Copy the code
  • The actual system Local is then retrieved and saved in the attachBaseContext and onConfigurationChanged sections of the application

  • Finally, change our original method of obtaining system Local:

/** * gets the system locale ** @returnPublic static Locale getSystemLocale(Context Context) {public static Locale getSystemLocale(Context Context) {return SPUtil.getInstance(context).getSystemCurrentLocal();
    }
Copy the code

This is really done, the specific code can be seen in the project source code here, if you feel helpful to you, welcome to click start