LocalizeMe is a lightweight Android library for managing app localization.
It allows you to easily switch languages at runtime, supports multiple locales, and works with
XML-based and compose resources.
- Features
- Supported Locales
- Demo
- Screenshots
- Installation
- Usage
- Currency
- Normalization
- Advantages
- Contributions
- Switch app language at runtime using
LanguageManager. - Supports 33+ Locales out of the box:
| Locale | Tag | Locale | Tag |
|---|---|---|---|
| Arabic (Egypt) | ar-EG | Urdu (Pakistan) | ur-PK |
| Arabic (Saudi Arabia) | ar-SA | French (France) | fr-FR |
| Arabic (Jordan) | ar-JO | Spanish (Spain) | es-ES |
| Arabic (Iraq) | ar-IQ | Italian (Italy) | it-IT |
| Arabic (Morocco) | ar-MA | Japanese (Japan) | ja-JP |
| Arabic (Libya) | ar-LY | Hindi (India) | hi-IN |
| Arabic (UAE) | ar-AE | Persian (Iran) | fa-IR |
| English (United States) | en-US | Bengali (Bangladesh) | bn-BD |
| English (Egypt) | en-EG | Malay (Malaysia) | ms-MY |
| English (United Kingdom) | en-UK | German (Germany) | de-DE |
| English (Iraq) | en-IQ | Chinese (China) | zh-CN |
| English (Morocco) | en-MA | Portuguese (Brazil) | pt-BR |
| English (Saudi Arabia) | en-SA | Turkish (Türkiye) | tr-TR |
| English (Libya) | en-LY | Korean (South Korea) | ko-KR |
| English (Jordan) | en-JO | Indonesian (Indonesia) | id-ID |
| English (UAE) | en-AE | Thai (Thailand) | th-TH |
| Russian (Russia) | ru-RU |
The demo shows how the app switches languages.
| Arabic Example | English Example | Russian Example | China Example |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}dependencies {
implementation("com.github.hassanwasfy:LocalizeMe:v${latest.version}")
}add in res/values/string.xml (any qualifer you target and we support)
dependencies {
implementation(project(":localize"))
}class MainApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(LocaleHelper.wrapContext(base))
}
}<application android:name=".MainApp"></application>import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.hwasfy.localize.api.LanguageManager
import com.hwasfy.localize.api.currentAppLocale
import com.hwasfy.localize.util.SupportedLocales
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val currentLocale = currentAppLocale()
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
TopAppBar(title = { Text("Language Demo") })
}
) { padding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(padding)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text("Current: ${currentLocale.name} (${currentLocale.locale.displayName})")
Button(
onClick = {
LanguageManager.setLanguage(
this@MainActivity,
SupportedLocales.EN_US
)
}
) { Text("Switch to English") }
Button(
onClick = {
LanguageManager.setLanguage(
this@MainActivity,
SupportedLocales.AR_EG
)
}
) { Text("التبديل إلى العربية") }
Button(
onClick = {
LanguageManager.setLanguage(
this@MainActivity,
SupportedLocales.FR_FR
)
}
) { Text("Passer en Français") }
}
}
}
}
}class SettingsRepository(private val context: Context) {
fun getCurrentLanguageCode(): String {
return LanguageManager.getCurrentLanguage(context) // "en", "ar", ...
}
fun getCurrentLocale(): SupportedLocales {
return LanguageManager.getCurrentLocale(context) // e.g., SupportedLocales.AR_EG
}
}@Composable
fun LanguageInfo() {
val code = currentAppLanguageCode()
val locale = currentResolvedLocale()
Column {
Text("Language Code: $code")
Text("Locale: ${locale.displayName}")
}
}Extension helpers to turn Long, Double, or Float values into a fully-localized currency string
based on the app’s current locale.
fun Long.toMoneyString(context: Context, fractionDigits: Int = 2): String =
this.formatAsCurrency(context, fractionDigits)
fun Double.toMoneyString(context: Context, fractionDigits: Int = 2): String =
this.formatAsCurrency(context, fractionDigits)
fun Float.toMoneyString(context: Context, fractionDigits: Int = 2): String =
this.toDouble().formatAsCurrency(context, fractionDigits)val amount: Long = 500
textView.text = amount.toMoneyString(context, fractionDigits = 2) //XML "EGP 500,00" or "$500.00"
Text(
amount.toMoneyString(
LocalContext.current,
fractionDigits = 2
)
) //Compose text with money formattedHelpers for converting Arabic-Indic or Eastern-Arabic digits to western ASCII digits.
fun String.toWesternDigits(): String {
val arabicIndicDigits = listOf('٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩')
val easternArabicDigits = listOf('۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹')
return this.map { char ->
when (char) {
in arabicIndicDigits -> arabicIndicDigits.indexOf(char).toString()[0]
in easternArabicDigits -> easternArabicDigits.indexOf(char).toString()[0]
else -> char
}
}.joinToString("")
}
fun String.normalizeDigits(): String {
val builder = StringBuilder()
for (ch in this) {
if (ch.isDigit()) {
val digit = Character.getNumericValue(ch) // works for Arabic, Hindi, etc.
builder.append(digit)
} else {
builder.append(ch)
}
}
return builder.toString()
}val mixed = "سعر ١٢٣٤"
val western = mixed.toWesternDigits() // "سعر 1234"
val normalized = mixed.normalizeDigits() // "سعر 1234"- No complex setup required.
- Works with XML-Compose resources.
- Can be used in any Android app, just add dependency.
- Lightweight and modular, ready for Jitpack.
- Fork the repository: Start by forking the
LocalizeMerepository to your own GitHub account. - Create a new branch: Create a new branch for your feature or bug fix. Use a descriptive name like
feature/add-new-localeorfix/crash-on-language-change. - Make your changes: Implement your changes and ensure the code follows the existing style and conventions.
- Create a pull request: Once your changes are ready, create a pull request (PR) from your forked repository to the main branch of the
original LocalizeMe repository. - Provide a clear description: In your PR, provide a detailed description of the changes you've made and the problem you're solving.
We appreciate your help in making this library even better!




