In this blog, we will explore how to implement multilingual support in an Android application providing step-by-step implementation with code snippets.
What is Locale?
Before diving into the code, let's understand the term "Locale."
A Locale represents a specific geographical, or cultural region. It is used to customize the app's content, such as language, date formats, currency, etc., to match the user's preferences. For example: Locale for English: en
, Locale for Hindi: hi
, Locale for French: fr
By setting the appropriate Locale in your app, we can ensure that users experience the application in their preferred language.
Here's what we aim to achieve:
- Allow users to select their preferred language.
- Save the selected language preference.
- Apply the selected language throughout the app.
Step 1: Setting Up the Language Manager
We will create a LanguageManager
object to handle saving, retrieving, and applying the selected language.
object LanguageManager {
private const val LANGUAGE_KEY = "language_key"
private const val DEFAULT_LANGUAGE = "en"
fun saveLanguage(context: Context, language: String) {
val sharedPreferences = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
sharedPreferences.edit().putString(LANGUAGE_KEY, language).apply()
}
fun getLanguage(context: Context): String {
val sharedPreferences = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
return sharedPreferences.getString(LANGUAGE_KEY, DEFAULT_LANGUAGE) ?: DEFAULT_LANGUAGE
}
fun setLocale(context: Context, language: String): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val config = Configuration(context.resources.configuration)
config.setLocale(locale)
return context.createConfigurationContext(config)
}
}
Explanation:
-
saveLanguage(): Saves the selected language to
SharedPreferences
so it persists across app restarts. - getLanguage(): Retrieves the saved language, defaulting to English (en) if none is set.
- setLocale(): Updates the app's Locale to reflect the selected language and ensures the app's resources are reloaded accordingly. This function is responsible for setting the Locale for the context, ensuring that any resource fetched from the context is based on the updated Locale.
Step 2: Updating the Base Context
To ensure the selected language is applied throughout the app, we override the attachBaseContext
method in a BaseActivity
class. All other activities will inherit from this base class.
abstract class BaseActivity : ComponentActivity() {
override fun attachBaseContext(newBase: Context) {
val language = LanguageManager.getLanguage(newBase)
val context = LanguageManager.setLocale(newBase, language)
super.attachBaseContext(context)
}
}
How It Works:
- When an activity is created, the
attachBaseContext
method is called (beforeonCreate
). - We fetch the saved language using
LanguageManager.getLanguage()
. - We then apply the saved language by calling
LanguageManager.setLocale()
. - The updated context ensures that the selected language is used for all resources.
Step 3: Creating the Sample Screen
We create the MainActivity
class inherits from BaseActivity
. It serves as the entry point of our app and provides users with the option to select a language.
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MultiLanguageTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
MainScreen(
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
The MainScreen composable provides a simple UI for users to select their preferred language.
@Composable
fun MainScreen(
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
Column(
modifier = modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// Welcome Text
Text(
text = context.resources.getString(R.string.welcome_text),
modifier = Modifier.padding(bottom = 16.dp)
)
// Language Selection
Text(
text = context.resources.getString(R.string.select_language),
modifier = Modifier.padding(bottom = 8.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Button(onClick = { changeLocale(context, "en") }) {
Text(text = "English")
}
Button(onClick = { changeLocale(context, "hi") }) {
Text(text = "हिंदी")
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Button(onClick = { changeLocale(context, "fr") }) {
Text(text = "Français")
}
Button(onClick = { changeLocale(context, "es") }) {
Text(text = "Español")
}
}
}
// Flag Image
Image(
painter = painterResource(id = R.drawable.flag),
contentDescription = null,
modifier = Modifier
.padding(top = 32.dp)
.size(200.dp)
)
}
}
Step 4: Changing the Language Dynamically
When a user selects a language, we need to update the Locale and restart the app.
fun changeLocale(context: Context, language: String) {
LanguageManager.saveLanguage(context, language)
LanguageManager.setLocale(context, language)
restartApp(context)
}
fun restartApp(context: Context) {
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
context.startActivity(intent)
if (context is Activity) {
context.finish()
}
}
Step 5: Adding Language Resources
To support multiple languages, create separate values
folders for each language in the res
directory:
- res/values/strings.xml (default English):
<resources>
<string name="app_name">MultiLanguage</string>
<string name="welcome_text">Welcome to the MultiLingual App!</string>
<string name="select_language">Select Language:</string>
</resources>
- res/values-hi/strings.xml (Hindi):
<resources>
<string name="app_name">MultiLanguage</string>
<string name="welcome_text">मल्टीलिंगुअल ऐप में आपका स्वागत है!</string>
<string name="select_language">भाषा चुने:</string>
</resources>
Similarly for other language as well,
res/values-fr/strings.xml
(French),res/values-es/strings.xml
(Spanish)For changing images based on locale, similar to values folder, create drawable folder for each language like
drawable
,drawable-hi
,drawable-fr
,drawable-es
and add the image with the same name in all the folder.
Sample app
Source Code: GitHub
Contact Me: LinkedIn | Twitter
Happy coding! ✌️
Top comments (0)