Android

Android Multi Language Support Best Practices

Welcome, Buddy… In this android tutorials we demonstrate, Build a multi-language support in the android application. As per Android best practice, Application should be kept culture-specific resource. So that resource to be translated to the language based on current locale. In android term, it is called Internationalization and Localization

Localization is play very important role for app reach and user experience (especially GUI). Multi-language support increases your audience reach and provides a better user interface based on locale. Let’s make your Android app more usable and comfortable so more and more audience can use it

How do Internationalization and Localization work in android?

In, Android you can specify resources to the culture of the targeted audience. All content related resource is held in drawable and value folder in Android Project. In this tutorials as will give support of 3 languages Spanish, Hindi (hi_IN)and English(en_US)

1. Let’s build a sample app in 4 step

1.1 Create New Project with following details

In Android Studio, Go to File Menu -> New Project -> Fill some essential details like Application Name and Company Domain like com.androidwave -> Select target SDK -> Select BasicActivity template -> Finish

In Android Studio, following all step the complete project structure seems like below figure.

how to create string locale resource

1.2 Add new resource file strings.xml for the Hindi language

Go to value res folder and right click on go to the value resource file.
Select locale from available qualifier clicks the right arrow. Select language and specific region (the region is not mandatory). Check below figure

Multi language support app in Android


Similarly, create the file for Spanish and English locale. So you have to create three locale file for Hindi, English, and Spanish languages

Create a string entry for English locale

<resources>
    <string name="app_name">Multi Language App</string>
    <string name="navigation_drawer_open">Open navigation drawer</string>
    <string name="navigation_drawer_close">Close navigation drawer</string>
    <string name="nav_header_title">Android Wave</string>
    <string name="nav_header_subtitle">androidwave.com</string>
    <string name="nav_header_desc">Android &amp; iOS Developer Blog</string>
    <string name="action_settings">Settings</string>
    <string name="description_androidwave">We demonstrate android &amp; iOS app development tutorials for Firebase, Camera2 API, Exo Player, Youtube API, Dagger2, RxJava, MVVM, MVP, Realm, and more.</string>
    <string name="text_hindi" translatable="false">हिंदी</string>
    <string name="text_english" translatable="false">English</string>
    <string name="text_spanish" translatable="false">" Español"</string>

    <!-- Navigation Menu-->
    <string name="title_import">Import</string>
    <string name="title_gallery">Gallery</string>
    <string name="title_slideshow">Slideshow</string>
    <string name="title_tools">Tools</string>
    <string name="title_communication">Communicate</string>
    <string name="title_share">Share</string>
    <string name="title_send">Send</string>
</resources>

The same key should be in Hindi locale

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">बहु भाषा ऐप</string>
    <string name="navigation_drawer_open">नेविगेशन ड्रावर को खोले</string>
    <string name="navigation_drawer_close">नेविगेशन ड्रावर को बंद करें </string>
    <string name="nav_header_title">एंड्रॉइड वेव</string>
    <string name="nav_header_subtitle">androidwave.com</string>
    <string name="nav_header_desc">एंड्रॉइड और आईओएस डेवलपर ब्लॉग</string>
    <string name="action_settings">सेटिंग</string>
    <string name="description_androidwave">हम फायरबेस, कैमरा 2 एपीआई, एक्सो प्लेयर, यूट्यूब एपीआई, डैगर 2, आरएक्सजेवा, एमवीवीएम, एमवीपी, दायरे, आदि के लिए एंड्रॉइड और आईओएस ऐप डेवलपमेंट ट्यूटोरियल का प्रदर्शन करते हैं।</string>
    <!-- Navigation Menu-->
    <string name="title_import">आयात</string>
    <string name="title_gallery">गैलरी</string>
    <string name="title_slideshow">स्लाइड शो</string>
    <string name="title_tools">उपकरण</string>
    <string name="title_communication">संवाद</string>
    <string name="title_share">शेयर</string>
    <string name="title_send">भेजना</string>
</resources>

Furthermore have to for Spanish

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Aplicación multi idioma</string>
    <string name="navigation_drawer_open">Cajón de navegación abierto.</string>
    <string name="navigation_drawer_close">Cerrar el cajon de navegacion</string>
    <string name="nav_header_title">Android Wave</string>
    <string name="nav_header_subtitle">androidwave.com</string>
    <string name="nav_header_desc">Android &amp; Blog del desarrollador de iOS</string>
    <string name="action_settings">Ajustes</string>
    <string name="description_androidwave">Demostramos android &amp; Tutoriales de desarrollo de aplicaciones iOS para Firebase, Camera2 API, Exo Player, Youtube API, Dagger2, RxJava, MVVM, MVP, Realm y más</string>
    <!-- Navigation Menu-->
    <string name="title_import">Importar</string>
    <string name="title_gallery">Galería</string>
    <string name="title_slideshow">Diapositivas</string>
    <string name="title_tools">Herramientas</string>
    <string name="title_communication">Comunicar</string>
    <string name="title_share">Compartir</string>
    <string name="title_send">Enviar</string>
</resources>
The complete project hierarchy looks like this figure
how to locale work in android

3. Now build LocalManager.java utilities.

3.1. Define some specific constant key
 /**
     * For english locale
     */
    public static final String LANGUAGE_KEY_ENGLISH = "en";
    /**
     * for hindi locale
     */
    public static final String LANGUAGE_KEY_HINDI = "hi";
    /***
     * // for spanish locale
     */

    public static final String LANGUAGE_KEY_SPANISH = "es";
    /**
     *  SharedPreferences Key
     */
    private static final String LANGUAGE_KEY = "language_key";
3.2. Save locale preference in PreferenceManager

Build Getter and Setter of local, It’s Setter responsible for persisting data in SharedPreferences and Getter is responsible for pulling data from SharedPreferences.

 /**
     * set current pref locale
     * @param mContext
     * @return
     */
    public static Context setLocale(Context mContext) {
        return updateResources(mContext, getLanguagePref(mContext));
    }

    /**
     * Set new Locale with context
     * @param mContext
     * @param mLocaleKey
     * @return
     */
    public static Context setNewLocale(Context mContext, String mLocaleKey) {
        setLanguagePref(mContext, mLocaleKey);
        return updateResources(mContext, mLocaleKey);
    }

    /**
     * Get saved Locale from SharedPreferences
     * @param mContext current context
     * @return current locale key by default return english locale
     */
    public static String getLanguagePref(Context mContext) {
        SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        return mPreferences.getString(LANGUAGE_KEY, LANGUAGE_KEY_ENGLISH);
    }

    /**
     *  set pref key
      * @param mContext
     * @param localeKey
     */
    private static void setLanguagePref(Context mContext, String localeKey) {
        SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        mPreferences.edit().putString(LANGUAGE_KEY, localeKey).commit();
    }
Now set locale and update the resource
  /**
     * update resource
     * @param context
     * @param language
     * @return
     */
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        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;
    }

Finally the complete utilites class looks like below

package com.androidwave.multilanguage;

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;

public class LocaleManager {
    /**
     * For english locale
     */
    public static final String LANGUAGE_KEY_ENGLISH = "en";
    /**
     * for hindi locale
     */
    public static final String LANGUAGE_KEY_HINDI = "hi";
    /***
     * // for spanish locale
     */

    public static final String LANGUAGE_KEY_SPANISH = "es";
    /**
     *  SharedPreferences Key
     */
    private static final String LANGUAGE_KEY = "language_key";

    /**
     * set current pref locale
     * @param mContext
     * @return
     */
    public static Context setLocale(Context mContext) {
        return updateResources(mContext, getLanguagePref(mContext));
    }

    /**
     * Set new Locale with context
     * @param mContext
     * @param mLocaleKey
     * @return
     */
    public static Context setNewLocale(Context mContext, String mLocaleKey) {
        setLanguagePref(mContext, mLocaleKey);
        return updateResources(mContext, mLocaleKey);
    }

    /**
     * Get saved Locale from SharedPreferences
     * @param mContext current context
     * @return current locale key by default return english locale
     */
    public static String getLanguagePref(Context mContext) {
        SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        return mPreferences.getString(LANGUAGE_KEY, LANGUAGE_KEY_ENGLISH);
    }

    /**
     *  set pref key
      * @param mContext
     * @param localeKey
     */
    private static void setLanguagePref(Context mContext, String localeKey) {
        SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        mPreferences.edit().putString(LANGUAGE_KEY, localeKey).commit();
    }

    /**
     * update resource
     * @param context
     * @param language
     * @return
     */
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        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;
    }

    /**
     * get current locale
     * @param res
     * @return
     */
    public static Locale getLocale(Resources res) {
        Configuration config = res.getConfiguration();
        return Build.VERSION.SDK_INT >= 24 ? config.getLocales().get(0) : config.locale;
    }
}

5. Locale Configration

Few minor configration have to need in activity and application class.

package com.androidwave.multilanguage;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

import static android.content.pm.PackageManager.GET_META_DATA;

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        resetTitles();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleManager.setLocale(base));
    }

    protected void resetTitles() {
        try {
            ActivityInfo info = getPackageManager().getActivityInfo(getComponentName(), GET_META_DATA);
            if (info.labelRes != 0) {
                setTitle(info.labelRes);
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

}

6. Implement Locale Configration in Application class

package com.androidwave.multilanguage;

import android.app.Application;
import android.content.Context;
import android.util.Log;

public class MultiLanguageApp extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleManager.setLocale(base));
    }

    @Override
    public void onConfigurationChanged(android.content.res.Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocaleManager.setLocale(this);
    }
}

Above all locale configration is complete and LocaleManager utilities is ready to use. In conclusion, just wrtie a single line code for change locale of application

// For English 
LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_ENGLISH);
// For Hindi
 LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_HINDI);
// For Spanish
LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_SPANISH);              

For instance, for simple utities uses example.

Download Sample Project- Android Multi Language Support Best Practices
package com.androidwave.multilanguage;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class MainActivity extends BaseActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
    }


    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case R.id.local_english:
                LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_ENGLISH);
                recreate();
                return true;
            case R.id.local_hindi:
                LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_HINDI);
                recreate();
                return true;

            case R.id.local_spanish:
                LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_SPANISH);
                recreate();
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();
        switch (id) {
            case R.id.nav_camera:
                break;
            case R.id.nav_gallery:
                break;
            case R.id.nav_slideshow:
                break;
            case R.id.nav_manage:
                break;
            case R.id.nav_share:
                break;
            case R.id.nav_send:
                break;

            default:
                break;
        }
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

}

Finally, Run project and switch locale the complete view will change in selected language. If you have any query, feel free to connect us.

Author

2 Comments

    • admin Reply

      AJ, You have to extend BaseActivity instance ofAppCompectActivity and change language like below
      // For English
      LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_ENGLISH);
      // For Hindi
      LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_HINDI);
      // For Spanish
      LocaleManager.setNewLocale(this, LocaleManager.LANGUAGE_KEY_SPANISH);

Write A Comment