Localization — Best way to support several language
Discontinued
Since Google announced Android 13 with per-app language preferences supports. This feature also backport to older Android version with AndroidX. So there's no reason to contribute this library anymore. For more stability, compatibility, and longer supports from Google team, please migrate to AndroidX. See Migrate to AndroidX guide.
As a developer, would know that 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.
- English Article [Now Reading]
- Thai Article
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
implementation '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 back stack.
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.
For 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.
implementation ('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.