As you, a developer, would know, Android application have to support multiple languages. Yeah! It’s very easy for android to handle it for you. It is done through “String Resource.” The only thing that you must do is simply preparing texts in different languages. The rest is handled by android system.

However, it is too smart. String Resource is automatically adjusted to the current device’s language. We cannot easily switch language on-the-fly.

So I created a new library specifically to handle android application language switching. It called “Localization”.

Demo


You can watch a short demo from YouTube or try it from Google Play

Features


* On-the-fly language switching.
* Auto setup when activity was created.
* Current language configuration will be saved to SharedPreference automatically.
* Easy.

Usage


Add a dependency to your build.gradle

compile 'com.akexorcist:localizationactivity:1.2.2'


Use custom application class in your project and add the LocalizationApplicationDelegate class like this.

import android.app.Application; import android.content.Context; import android.content.res.Configuration; import com.akexorcist.localizationactivity.core.LocalizationApplicationDelegate; public class CustomApplication extends Application { LocalizationApplicationDelegate localizationDelegate = new LocalizationApplicationDelegate(this); @Override protected void attachBaseContext(Context base) { super.attachBaseContext(localizationDelegate.attachBaseContext(base)); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); localizationDelegate.onConfigurationChanged(this); } @Override public Context getApplicationContext() { return localizationDelegate.getApplicationContext(super.getApplicationContext()); } }


This is an example for your activity class.

import android.os.Bundle; import android.view.View; import com.akexorcist.localizationactivity.ui.LocalizationActivity; public class MainActivity extends LocalizationActivity implements View.OnClickListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple); findViewById(R.id.btn_th).setOnClickListener(this); findViewById(R.id.btn_en).setOnClickListener(this); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.btn_en) { setLanguage("en"); } else if (id == R.id.btn_th) { setLanguage("th"); } } }


In the example above, when the button is clicked , language will be switched accordingly either Thai or English. That’s It!

Then, you just add String Resources for English and Thai in the values and values-th.

Completed! Now your application supports multiple languages without much sweat.

Extend from AppCompatActivity


LocalizationActivity is extended from AppCompatActivity class. If you already use methods from AppCompatActivity. You do not have to refactor your codes!

Public Methods


The only big adjustment on your codes is the following 3 public methods.

void setLanguage(String language) void setLanguage(String language, String country) String getLanguage() void setDefaultLanguage(String language) void setDefaultLanguage(String language, String country)


setLanguage Set the language that you needs to switch. The given string value will be used to setup Locale class later.

setLanguage("th") // Language : Thailand setLanguage("th", "TH") // Language : Thailand, Country : Thai setLanguage("en") // Language : English setLanguage("en", "GB") // Language : English, Country : Great Britain setLanguage("en", "US") // Language : English, Country : United States setLanguage(Locale.KOREA) // Language : Korean, Country : Korea setLanguage(Locale.KOREAN) // Language : Korean setLanguage(Locale.CANADA_FRENCH) // Language : French, Country : Canada


So you must determine the correct language for Locale class

getLanguage Get current language. (Return to string locale)

setDefaultLanguage Set default language if there is no language configuration. This interface is called only once in the first activity. It will be called before super.onCreate

@Override public void onCreate(Bundle savedInstanceState) { setDefaultLanguage(Locale.JAPAN.toString()); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... }


and 2 optional override methods.

void onBeforeLocaleChanged() void onAfterLocaleChanged()


This override method will be called then activity language was changed. If you need to know when language has change, just override these methods.

Change the language on every activity. Although already created.


You can switch languages in all activities, regardless of whether those activities were in the backstack.

Normal activity behavior has troubles with language switching.

If you switch language in the third activity, the previous two activities wouldn’t switch language to be the same as the third activity.

You will find no such problems with LocalizationActivity. All activities in backstack will get the just switched language, too.

You must handle your data through the instance state


When language was switched. Your activity will be recreated. If you have any data object, you should handle your data by save/restore instance state to retain your data or it will be lost. (Still, this is what you must do when your app supports portrait and landscape orientation.)

Therefore, you have to override onSaveInstance and onRestoreInstance and handle it.

import android.os.Bundle; import android.view.View; import com.akexorcist.localizationactivity.ui.LocalizationActivity; public class MainActivity extends LocalizationActivity implements View.OnClickListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // TODO Initial view and widget here if (savedInstanceState == null) { // TODO Activity first created } else { // TODO Activity recreated from screen orientation or change language } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // TODO Save instance here } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // TODO Restore instance here super.onRestoreInstanceState(savedInstanceState); } }


Your fragment is affected as well.


Fragment language configuration depends on its hosted activity. If activity language was changed and recreated. Fragment will do so. You have to handle your data to Instance State on fragment just like the hosted activity.

About Save/Restore Instance State. Read more on The Real Best Practices to Save/Restore Activity’s and Fragment’s state.

Activity Blinking Problem


It’s normal that the activity is blinking because it was recreated. I already fixed this problem by inserting a dummy activity to fade in/out transition while the language is switching in the latest version.

Don’t like AppCompat v7? Try the delegate way.


Sometimes your app doesn’t use AppCompatActivity from AppCompat v7 library. But you want to support multiple languages. You can create your own activity class and use LocalizationDelegate to make your activity class.

import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.os.Bundle; import com.akexorcist.localizationactivity.core.LocalizationActivityDelegate; import com.akexorcist.localizationactivity.core.OnLocaleChangedListener; import java.util.Locale; public abstract class CustomActivity extends Activity implements OnLocaleChangedListener { private LocalizationActivityDelegate localizationDelegate = new LocalizationActivityDelegate(this); @Override public void onCreate(Bundle savedInstanceState) { localizationDelegate.addOnLocaleChangedListener(this); localizationDelegate.onCreate(savedInstanceState); super.onCreate(savedInstanceState); } @Override public void onResume() { super.onResume(); localizationDelegate.onResume(this); } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(localizationDelegate.attachBaseContext(newBase)); } @Override public Context getApplicationContext() { return localizationDelegate.getApplicationContext(super.getApplicationContext()); } @Override public Resources getResources() { return localizationDelegate.getResources(super.getResources()); } public final void setLanguage(String language) { localizationDelegate.setLanguage(this, language); } public final void setLanguage(Locale locale) { localizationDelegate.setLanguage(this, locale); } public final void setDefaultLanguage(String language) { localizationDelegate.setDefaultLanguage(language); } public final void setDefaultLanguage(Locale locale) { localizationDelegate.setDefaultLanguage(locale); } public final Locale getCurrentLanguage() { return localizationDelegate.getLanguage(this); } // Just override method locale change event @Override public void onBeforeLocaleChanged() { } @Override public void onAfterLocaleChanged() { } }


And don’t forget to exclude AppCompat v7 dependency from this library in build.gradle to reduce total method count.

compile ('com.akexorcist:localizationactivity:+') { exclude module: 'appcompat-v7' }


Examples


If you don’t understand how to use it. I have built an example project that contains 3 example codes and this library is open source. Hopefully it will help you understand it. See at Localization [GitHub]

About 6 example codes. It consists of

* Simple Activity
* Simple Activity that extends from Custom Localization Activity
* Simple Activity with Change Language Activity
* Activity + Fragment
* Activity + Nested Fragment
* Activity + View Pager

All three examples will handleSave/Restore Instance State. It supports the portrait/landscape orientation as well. (Layout is for demonstration only, it won’t be beautiful.)

Feel free to give any advice


It would be great if you can help me improve my English. Feel free to criticize my wrong grammar.