This tutorial will explain you how to change your application language at run time (programatically).
In certain cases your Android Application is supposed to support multiple languages for example English, Arabic, French. This concept is known as Localization.
Developer design app layout in such a way that layout support Right to Left (rtl) support and Left to Right (ltr) support.
By default all Android apps support LTR Layouts.
We will be using Kotlin Programming Language. Which most of other articles are not using 🙂
<resources> <string name="meter_number">Meter Number</string> <string name="meter_type">Meter Type</string> <string name="howto_read_meter"><u>How do I read my meter?</u></string> <string name="meter_last_reading_date">Last Reading Date</string> <string name="meter_last_reading_count">Last Reading</string> </resources>
<string name="meter_number">رقم المرفق</string> <string name="meter_type">نوع العداد</string> <string name="howto_read_meter">كيف اقرا العداد الخاص بي ؟</string> <string name="meter_last_reading_date">تاريخ اخر قراءة</string> <string name="meter_last_reading_count">اخر قراءة</string>
Add this flag in manifest under Application Tag.
android:supportsRtl="true"
// MANIFEST.XML <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.developine.translation"> <application android:allowBackup="true" android:name=".Home" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
Create a new File in your project and name PreferenceHelper
// PreferenceHelper.kt import android.content.Context import android.content.SharedPreferences import android.preference.PreferenceManager object PreferenceHelper { fun defaultPrefs(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) fun customPrefs(context: Context, name: String): SharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE) inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) { val editor = this.edit() operation(editor) editor.apply() } /** * puts a key value pair in shared prefs if doesn't exists, otherwise updates value on given [key] */ operator fun SharedPreferences.set(key: String?, value: Any?) { when (value) { is String? -> edit({ it.putString(key, value) }) is Int -> edit({ it.putInt(key, value) }) is Boolean -> edit({ it.putBoolean(key, value) }) is Float -> edit({ it.putFloat(key, value) }) is Long -> edit({ it.putLong(key, value) }) else -> throw UnsupportedOperationException("Not yet implemented") } } /** * finds value on given key. * [T] is the type of value * @param defaultValue optional default value - will take null for strings, false for bool and -1 for numeric values if [defaultValue] is not specified */ operator inline fun <reified T : Any> SharedPreferences.get(key: String?, defaultValue: T? = null): T? { return when (T::class) { String::class -> getString(key, defaultValue as? String) as T? Int::class -> getInt(key, defaultValue as? Int ?: -1) as T? Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T? Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T? Long::class -> getLong(key, defaultValue as? Long ?: -1) as T? else -> throw UnsupportedOperationException("Not yet implemented") } } }
We will be using Configuration, Resources and Locale Classes.
Configuration will have desired Locale and Resources will have updated Configuration.
import android.content.Context import android.content.SharedPreferences import android.content.res.Configuration import android.os.Build import PreferenceHelper import PreferenceHelper.get import PreferenceHelper.set import java.util.* object LocaleManagerMew { val SELECTED_LANGUAGE = "MEW_CURRENT_-- USER_LANGUAGE" var mSharedPreference: SharedPreferences? = null var mEnglishFlag = "en" var mArabicFlag = "ar" fun setLocale(context: Context?): Context { return updateResources(context!!, getCurrentLanguage(context)!!) } inline fun setNewLocale(context: Context, language: String) { persistLanguagePreference(context, language) updateResources(context, language) } inline fun getCurrentLanguage(context: Context?): String? { var mCurrentLanguage: String? if (mSharedPreference == null) mSharedPreference = PreferenceHelper.defaultPrefs(context!!) mCurrentLanguage = mSharedPreference!![SELECTED_LANGUAGE] return mCurrentLanguage } fun persistLanguagePreference(context: Context, language: String) { if (mSharedPreference == null) mSharedPreference = PreferenceHelper.defaultPrefs(context) mSharedPreference!![SELECTED_LANGUAGE] = language } fun updateResources(context: Context, language: String): Context { var contextFun = context var locale = Locale(language) Locale.setDefault(locale) var resources = context.resources var configuration = Configuration(resources.configuration) if (Build.VERSION.SDK_INT >= 17) { configuration.setLocale(locale) contextFun = context.createConfigurationContext(configuration) } else { configuration.locale = locale resources.updateConfiguration(configuration, resources.getDisplayMetrics()) } return contextFun } }
// ApplicationClass.kt open class ApplicationClass : Application() { init { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); } override fun attachBaseContext(base: Context?) { super.attachBaseContext(LocaleManager.setLocale(base)) MultiDex.install(base) } override fun onCreate() { super.onCreate() } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) LocaleManagerMew.setLocale(this) Log.d(MewConstants.mewLogs, "onConfigurationChanged: " + newConfig.locale.getLanguage()) } }
abstract class BaseActivity : AppCompatActivity(){ override fun attachBaseContext(base: Context?) { super.attachBaseContext(LocaleManagerMew.setLocale(base)) } }
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="24dp" tools:context=".ui.login.LoginActivity"> <ImageView android:id="@+id/switchLanguage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/eng" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/txtLoginLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/login" android:textAllCaps="true" android:textColor="@android:color/black" android:textSize="16sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/switchLanguage" /> <ImageView android:id="@+id/imgLoginLogo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:src="@drawable/login_logo" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/txtLoginLabel" /> <TextView android:id="@+id/txtCustomer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="6dp" android:layout_marginStart="6dp" android:layout_marginTop="30dp" android:text="@string/customer" android:textAllCaps="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imgLoginLogo" /> <ImageView android:id="@+id/imgSwipeLeft" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="@id/txtCustomer" app:layout_constraintEnd_toStartOf="@id/txtCustomer" app:layout_constraintTop_toTopOf="@+id/txtCustomer" app:srcCompat="@drawable/ic_back" /> <EditText android:id="@+id/etCivilID" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:gravity="start" android:hint="@string/civil_id" android:inputType="number" android:maxLength="20" android:textAllCaps="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/txtCustomer" /> <android.support.v7.widget.AppCompatSpinner android:id="@+id/spinner_choose_account_login" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:background="@drawable/bg_dropdown" android:gravity="start" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/etCivilID" /> <EditText android:id="@+id/etPremiseNumber" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:gravity="start" android:hint="@string/premise_number" android:inputType="number" android:maxLength="20" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/spinner_choose_account_login" /> <TextView android:id="@+id/txtForgotPassword" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Forgot password?" android:textSize="14sp" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/etPremiseNumber" /> <Button android:id="@+id/btnLogin" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="6dp" android:background="@drawable/bg_drawable_orange" android:padding="6dp" android:text="@string/login" android:textColor="@android:color/white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/btnCreateAccount" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/btnCreateAccount" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="6dp" android:background="@drawable/rectangle_orange_boarder_btn_bg" android:padding="6dp" android:text="@string/create_account" android:textColor="@color/colorPrimaryDark" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/btnLogin" /> </android.support.constraint.ConstraintLayout>
Here we will first get current language from shared preferences.
If current language saved in shared preferences is arabic we will update language to english.
If current language saved in shared preferences is null, we will assume that user has not updated language dynamically so we will assume current language is english, and we will update current app language to arabic.
override fun onClick(p0: View?) { when (p0?.id) { R.id.switchLanguage -> { //LocaleManagerMew.setLocale([email protected]?.applicationContext) var mCurrentLanguage = LocaleManagerMew.getCurrentLanguage([email protected]?.applicationContext) if (mCurrentLanguage == LocaleManagerMew.mArabicFlag) { LocaleManagerMew.setNewLocale([email protected]!!, LocaleManagerMew.mEnglishFlag) } else if (mCurrentLanguage == LocaleManagerMew.mEnglishFlag) { LocaleManagerMew.setNewLocale([email protected]!!, LocaleManagerMew.mArabicFlag) } activity?.recreate() } } }
If you have not missed any part of the code. hopefully everything will be working fine.
If you face any issue you can write in comments sections.
copyright: http://developine.com/