DEV Community

Cover image for Supporting Multiple Languages in Your Android Application
Khush Panchal
Khush Panchal

Posted on • Originally published at Medium

Supporting Multiple Languages in Your Android Application

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

How It Works:

  • When an activity is created, the attachBaseContext method is called (before onCreate).
  • 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)
                    )
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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)
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

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()
    }
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
  • res/values-hi/strings.xml (Hindi):
<resources>
    <string name="app_name">MultiLanguage</string>
    <string name="welcome_text">मल्टीलिंगुअल ऐप में आपका स्वागत है!</string>
    <string name="select_language">भाषा चुने:</string>
</resources>
Enter fullscreen mode Exit fullscreen mode
  • 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

Gif

Source Code: GitHub
Contact Me: LinkedIn | Twitter
Happy coding! ✌️

Top comments (0)