Core Android

Android Multiple Language Support Best Practices

Welcome, Buddy… In this tutorial, we demonstrate, How to Build multi-language support apps 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)

Multi Language Supported App in Android (Sample App)

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

1.1 Create New Project with the following details

In Android Studio, Go to File Menu -> New Project -> Fill some essential details like application name and choose androidx -> Select target SDK -> Select BasicActivity template -> Finish

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

how to add multiple language 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 implement localization in android

3. Now build LocalManager.java utilities.

3.1. Define some specific constant and define all support locale in LocaleDef annotated interface
  @Retention(RetentionPolicy.SOURCE)
  @StringDef({ ENGLISH, HINDI, SPANISH })
  public @interface LocaleDef {
    String[] SUPPORTED_LOCALES = { ENGLISH, HINDI, SPANISH };
  }

  static final String ENGLISH = "en";
  static final String HINDI = "hi";
  static final String SPANISH = "es";
3.2. Save locale preference in PreferenceManager

Write getter and setter for prefs, It’s setter responsible for persisting data in SharedPreferences and getter are responsible for pulling data from SharedPreferences.

  /**
   * 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, ENGLISH);
  }

  /**
   * set pref key
   */
  private static void setLanguagePref(Context mContext, String localeKey) {
    SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
    mPreferences.edit().putString(LANGUAGE_KEY, localeKey).apply();
  }
Now set locale and update the resource
/**
   * set current pref locale
   */
  public static Context setLocale(Context mContext) {
    return updateResources(mContext, getLanguagePref(mContext));
  }

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

  /**
   * update resource
   */
  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 LocaleManager 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 androidx.annotation.StringDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;

public class LocaleManager {

  @Retention(RetentionPolicy.SOURCE)
  @StringDef({ ENGLISH, HINDI, SPANISH })
  public @interface LocaleDef {
    String[] SUPPORTED_LOCALES = { ENGLISH, HINDI, SPANISH };
  }

  static final String ENGLISH = "en";
  static final String HINDI = "hi";
  static final String SPANISH = "es";

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

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

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

  /**
   * 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, ENGLISH);
  }

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

  /**
   * update resource
   */
  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
   */
  public static Locale getLocale(Resources res) {
    Configuration config = res.getConfiguration();
    return Build.VERSION.SDK_INT >= 24 ? config.getLocales().get(0) : config.locale;
  }
}

5. Locale Configuration

Few minor configurations have to need in every activity and application class. For that, I’m creating a base class named is BaseActivity. In this activity, I have written methods for activity title and updating the LocaleManager context.

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 abstract 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 Configuration in the Application class

Same things I have to in Application class. Let’s see below code, here we also settings locale on onConfigurationChanged and attachBaseContext.

package com.androidwave.multilanguage;

import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;

public class MultiLanguageApp extends Application {

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

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

Above all locale configuration is complete and LocaleManager utilities are ready to use. In conclusion, just call below method for change locale of the application

  private void setNewLocale(AppCompatActivity mContext, @LocaleManager.LocaleDef String language) {
    LocaleManager.setNewLocale(this, language);
    Intent intent = mContext.getIntent();
    startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK));
  }

Implement localization in your android application

Now open the Activity class where you want to change the app language of the app. In application is we mostly written in SettingActivity. But in this android app tutorial we writing in MainActvitiy. Let’s open MainActvitiy and paste below code

package com.androidwave.multilanguage;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;

public class MainActivity extends BaseActivity
    implements NavigationView.OnNavigationItemSelectedListener {
  DrawerLayout drawerLayout;

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

    FloatingActionButton fab = 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 = findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
        this, drawerLayout, toolbar, R.string.navigation_drawer_open,
        R.string.navigation_drawer_close);
    drawerLayout.addDrawerListener(toggle);
    toggle.syncState();

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

  @Override
  public void onBackPressed() {
    if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
      drawerLayout.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:
        setNewLocale(this, LocaleManager.ENGLISH);
        return true;
      case R.id.local_hindi:
        setNewLocale(this, LocaleManager.HINDI);
        return true;

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

    return super.onOptionsItemSelected(item);
  }

  private void setNewLocale(AppCompatActivity mContext, @LocaleManager.LocaleDef String language) {
    LocaleManager.setNewLocale(this, language);
    Intent intent = mContext.getIntent();
    startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK));
  }

  @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.closeDrawer(GravityCompat.START);
    return true;
  }
}

Finally, run the project and change your language. You will get the output as shown in the video.

Conclusion

Thank’s for reading, In this tutorial, we have learned implementation Android Multi Language App Example. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Keep in touch

If you have any query, feel free to connect us.

Download Sample Project- Android Multi Language App Example

9
Leave a Reply

2000
Zamar

This will change the language in the RecyclerView List view and Navigation items. But when an item on the list is clicked and goes to a view-pager that holds multiple fragments. changes wont apply. Can you please help with this?

sagar

Nice Tutorial I have implemented hind and english its working find but when uploaded in playstore HINDI not working ,Please help me???

Raju

Hi,
I have been following your tutorials but i have a question is there a way to change language without recreating activity.

AJ

How I can apply it to all other activities