While developing your awesome application, sometimes you are required to add a feature to change the language of your app on the fly. However, Android OS does not directly support this behaviour. And therefore, you need to solve this situation in some other ways.
Android by default uses the locale of the device to select the appropriate language dependent resources. And most of the time this behaviour is enough for common applications.
However, sometimes there is some business requirements that you need to implement. To do that I will outline the details of changing the language of your application programmatically on the fly.
Here is the appropriate way of changing the locale of the application:
There are some difficulties which you have to overcome to change the language programmatically.
Your application will not remember your language change after it is closed or recreated during the configuration change.
You should update currently visible UI properly according to the selected language.
Solution
“LocaleHelper” is the solution all you need. You just have to initialize locale on your application’s main class. After that all your language changes will persist.
After the recent changes in Android API Version 24(Nougat) we need to override attachBaseContext to reflect changes.
LocaleHelper.javA
if you call onAttach(Context context) constructor it will just set default locale of your device as the default locale of your application.
if you call onAttach(Context context, String defaultLanguage) constructor it will set the given language as the default language of your application for the first time that your application opens. After that you can change your locale by using the buttons or any other method that you provide to your users through your layout.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
You need to override attachBaseContext and call LocaleHelper.onAttach() to initialize the locale settings in your application.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Here you can find an example activity which has two buttons and three textviews on it to change the locale of the textviews on the fly.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In your activity override attachBaseContext and call LocaleHelper.onAttach(). After that you just need to take care of the activity or fragment which includes the language change buttons. Other activities will not require any modifications at all.
You have two options to update currently visible layout:
First, you can just update the text or any other language dependent resources one by one.
Second, you can call activity.recreate() to restart currently loaded activity. Then the activity will reload the resources with the correct locale. However, if you select this option your users will notice the affect because it will close your application and you get black screen for a very small amount of time and then recreate your activity again in meanwhile.
If you have any question regarding to change locale of your android application, feel free to ask.
Update for new App Bundle Format
Google introduced a new App Bundle format to split apk files in smaller sizes when they’re being installed on the client devices. However, this means that we cannot have dynamic language changes in our applications.
To prevent that split we need to add extra lines in our build.gradle file inside the app folder like below.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
It is not possible to do that because the virtual keyboard itself is another system application. You can redirect your user to the settings page to let him/her to change the keyboard language by themselves.
Please check that your device is supported Hindu language by going “Settings -> Language & Input”.
If it is not the problem then you need to create a folder called “values-hi” in your “res” folder.
Then you have to add strings.xml into values-hi folder.
And then you can apply the codes that i shared here without any problem.
Note that using “Configuration configuration = resources.getConfiguration(); configuration.locale = locale” is wrong, because according to documentation “the returned Configuration object should be treated as read-only”. So you should do “Configuration configuration = new Configuration(resources.getConfiguration());”, i.e. copy it instead.
Hello Günhan, I am using your code to change the language setting in my app but somehow the NavigationView does not get rewritten. Do you have any idea why?
Thanks 🙂
I see your problem, it is because you couldn’t update the navigation view itself.
As i mentioned you can force the activity to recreate itself by using the correct locale however it has a very poor user experience and maybe thats why you didn’t implement that way.
What you have to do is, you need to find the menu items in your navigationview manually by using the ids that you provided in your menu.xml
And then you have to reassign textview texts.
Also another option is, remove the navigationview from the drawer, and then create a new one assign it to the drawer again.
Or another option is, it is a little bit tricky solution but, just dont use navigationview’s menu, just set your custom headerview, and in that view you manually manage your list of items. And to do that you have to create a recyclerview in which you can easily update the list of items or any other view very easily.
Thus, i mentioned also in the post the problem is you have to manually update the current view because activity cannot update itself.
Hi, I used you LocaleHelper and it works only when we manually update each views’ text after changing language. But it doesn’t work when I used activity.recreate. Locale.getDefault is still correct though, but the string that was received from getResource is wrong.
Dil seçimini ayarlar activity de yapıyorum bir çok activity bulunuyor uygulamamda kullandığım kodda iç içe activity leri yenilemekle uğraşmamak için, dil değişikliğinden sonra uygulamayı yeniden başlatıyorum. Uygulama kill olmadığı için yeniden başladığında mainapplication kısmı tekrardan çalışmıyor ve dil değişikliği gerçekleşmiyor. Uygulamayı kill ettiğimde bir sonraki açılışta problem kalmıyor. Sorunun çözümü olarak yeniden başlatmadan evvel system.exit(0) komutunu kullandığımda uygulama sonlandığı için sorun oluşmuyor. Sizin tavsiye edebileceğiniz çözüm nedir? teşekkürler.
Backstack’de bulunan activity’ler resourcelarını önceden yüklediği için bu sorunla karşılaşmanız normal.
İlk ve en temiz önerim eğer yapabiliyorsanız dil değişim özelliğini uygulamanızın açılış activity’si üzerinde yapmanız. Böylece bir sonra açılacak activity hali hazırda bu değişimden yararlanacaktır.
İkinci önerim ayarlar activity’niz kapatılırken setResul() ile dil değişliği yapıldığını simgeleyecek bir resultCode set edebilirsiniz. Ve akabinde backstack2den gelecek activitylerin onActivityResult() methodu içerisinde gelen resultCode’u değerlendirip eğer dil değişimi yapmanız gerekiyorsa yine activity.recreate() yapabilirsiniz veya updateViews ile ekran üzerinde çok view bulunmuyorsa bu işlemi manuel gerçekleştirebilirsiniz.
Uygulama çalışıyorken dil değişikliği yapılması aslında önerilen bir özellik değil ve bir çok uygulamada bu özellik bulunmuyor. Bu sebeple kullanıcı dili değiştirdiğinde uygulamayı kill etmeniz önermeyeceğim bir çözüm olsa da kullanıcıların anlayışla karşılayacağını düşünüyorum.
After i call method LocalHelper.setLocal() in my application the activity title (on top of the screen) doesn’t change. Other content is changed OK. If i completly close the apllication and then open it again the title is set correctly. Can you help me fix this problem so that the title will get changed on the fly?
When Phone rotates the language shifts back to default one, As we know when phone rotates, onConfigurationChanged is called.
Hence best thing to do is:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LocaleHelper.onAttach(getBaseContext());
//update locale and resources, configuration on each config change
}
Also you don’t need to override this in each activity just do it in Application class and all done.
Yes, you have to do it for all your activities.
It is better for you to have a BaseActivity class that you can extend your other activities. And you can do that implementation on your BaseActivity.
Hey i found the issue. Actually i had to call LocaleHelper.onAttach() in all of my activities inside attachBaseContext method.
thanks a lot..it’s working fine now.
One thing that i’m confused about is Location Helper is a static class. Then why do i need to call onAttach again in all of my Activities. I’m sorta confused here. It will be great if you could explain what’s happening here exactly and why do i need to call onAttach in all of my Activities???
LocaleHelper is kind of a factory. It returns a new Context based on your locale changes previously. Therefore, without using the newly created (localized) Context. It won’t work. So you need to attach those new context to your activities. It wasn’t like that in the previous version of Android though.
Thanks a lot for the description. I wonder if we can directly set the locale for whole application instead of calling it every time in all activities. Maybe we could use applicationContext instead of baseContext… :/
You should avoid using application context inside your activities because it would have cost you potential memory leaks.
Just create a BaseActivity and extend your activities from that BaseActivity. And implement this logic on it.
Take advantage of inheritance right?
Tarun Chauhan
Yeah….exactly….i totally forgot this…this will make it much more easier.. thanks pal ^_^
Ashish Tiwari
I have multiple activities and I am setting data statically and dynamically (from API). I used your code it works good, but sometimes it doesn’t work. It does not change the selected languge. I am restarting only one activity where I am clicking to change the language. Rest activities are setting resources automatically. I only have override attacheBaseContext
I have already recreated the activity but it is not changing the layout direction.
When I switch between English and Urdu multiple times it is not changing the direction as expected. I am trying it on device having android 7.1.1
@disqus_YnYOiZn2ls:disqus I answered on Stackoverflow. Please take a look, I believe it will solve your issue.
Maninder Singh
@gunhansancar:disqus sorry for the late response. I have tried your solution and it is working fine. Thanks for your help.
Please update your post with some generic solution for RTL issue. Thanks again.
Joao Neto
Hi Gunhan, I’m sorry to add another voice to the chorus but I can’t get your solution to work either on Nougat 7.1. I’ve done everything like you posted but instead o changing the labels I do a recreate of my activity. When reloading the activity goes through the attachBaseContext method with the super.attachBaseContext(LocaleHelper.onAttach(base)); but it keeps showing the default labels. Have you tested your solution with the recreate?
@Phearun Hi,
The locale changes are done manually, so you can define a string in strings.xml and your language strings.xml then you can achieve it that way.
Thank for quick reply.
In this case, I want to change calendar number language to khmer language as I do SimpleDateFormat (“dd/MMM/yyyy HH:mm:ss a”).
Ex: 21/Jun/2017 4:05 PM to khmer ២១/មិថុនា/២០១៧ ៤:០៥ ព្រឹក. Hope you understand my purpose. thanks
Could you describe what is not working? I’d like to reproduce your issue. Is it not updating the UI? Is it not saving the latest selected version? Did you apply as in the article? Do you mean by Left-To-Right or Right-To-Left layout issue? It is too generic to say it is not working.
I did the same as in the article, the view alignment goes from LEFT-TO-RIGHT as required for Persian(Iran), but the language displaying is in English not in PERSIAN for Lower versions(<N) only. I have included string.xml files for both English and Persian (Iran).
For RTL LTR issue, I had already given an answer on stackoverflow. Can you check that if it is the same issue and apply the given solution and let us know
Thanks for immediate help Gunhan, but issue is the language as I trying to set Persian (fa), the language doesn’t set it is showing English only for lower devices.
Hi I just tried for you and it seems working fine. I tested on API level 16 emulator. the important part is you should have a folder inside “res” directory “res/values-fa/strings.xml” for Persian”res/values/strings.xml” for english. You might be updated the files in wrong place or you forget to change button click event to “updateViews(“fa”);” And also please apply solution for RTL LTR as well at the end.
SACHIN MASKE
Thanks Gunhan I really appreciate your help, I was trying to implement PERSIAN language specifically for IRAN , so I just forget to add country code for IRAN in locale
@mayur_prasad:disqus Yes, indeed. Though just create a BaseActivity and do this inside of it then extend other activities using BaseActivity which makes your life easier.
Hey @siddarthg:disqus, it seems you’ve already solved your problem. Some of the view components from the core android doesn’t follow the expected localisation rules. So it’s better to invalidate them in a way and rebind again.
Hi Gunhan,
I followed the steps completely. but cant achieve the result. is there anything else i need to config with app or studio? i have already added locale|orientation in activity.
I’m doing this on a click of a view.
LocaleHelper.setLocale(this, “ta”);
this.recreate();
with attachbsecontext in the application class as well as acitivity is already done.
You need to have a folder called “values-ta” folder inside src/main/res folder and place your strings.xml there.
If you share the project on Github or Bitbucket I can take a look at the problem, otherwise you need to figure out what you’re missing.
For example can you confirm that with other languages it is working fine? So we can know that “ta” language is not the problem.
Arjun
No help with other languages also. Is values package addition need to be done manually for every language or the system is supposed to automatically convert my textview’s strings?
So when you set the new language normally system will pick that up for the next activity creation. But if you restart the activity or reload the textview manually after the change you can observe the changes without restarting.
I suggest you to download the sample app from github(the link is at the end of the article) and try to add your “ta” language files there to see if it is working. Then gradually move the code to your project source without missing any steps.
Arjun
I had tried with your code and neither my language nor few other languages had worked. I think i need to include “values” folder like yours or install some repository for lang change!
From your comment it seems that you even don’t have the values folder for your language placed. you need to create a folder on “path-to-your-project/app/src/main/res/values-ta/” then in that folder you need to create and xml file called “strings.xml”.
You can also do that directly from “Android Studio” click “strings.xml” file then on the right hand side there is a button called “Open editor” then click the “Earth Icon” and select your fancy language.
After that place your localized strings there.
Then everything gonna work.
p.s: You last sentence kind of bad however maybe some other people might find it useful that’s why I’m trying to help you to find your missing part.
Arjun
Hey Gunhan, Its not to offend you. i was just referring to yours as yours code. Hope i din hurt you if not, sorry for that.
None has mentioned the need to create values strings, that’s why queried whether i need to do it myself.
So, i need to add my strings on my own. Ok. Thank you man. Your help is highly appreciated. btw, its not just a fancy language its earth’s first language.
It’s all good. Glad it helped 🙂 I just checked throughly and couldn’t find “ta” code on Android Studio, that’s why I wrote it like that. I’m now checking on Google. Oh it says it’s Tamil. My knowledge about other languages is very limited though.
Sarfaraz Raj
Hi,
Recreating the activity does not work for me. I am writing my code in Xamarin but it is exact replica of the above code. Can you help me?
Hi @Sarfaraz Raj, I’m not using Xamarin so I don’t know what might be the reason but If you could give some more details like which Android version, which part of the UI e.g. Toolbar, nav menu etc. or just a regular textview? If I can replicate it on native Android app I’d like to help you out.
You should update your Application class with the given above. Then you need to have a BaseActivity class that all other activities inherit from. On BaseActivity apply the codes for Activity.
I am trying to implement language change by using your code, but when i go back from current activity its not reflecting the changes in onResume() of already opened activities. I am using the BaseActivity which is extends by all other activities.
For already opened Activities, you have to manually update(TextFields, Images etc like calling updateViews() in the example), or restart, or finish them. Otherwise they are not aware of the fact that BaseContext is changed. You have to tell them one by one that the language is changed and update your views. So it becomes very complex. I think the easiest solution is use an Intent to clear all of the previously opened activities (like using a flag called FLAG_ACTIVITY_CLEAR_TOP). And that way your users would end up on the home screen with a brand new locale.
Ok, I will try to convince the client to close the app on language change. Thanks Gunhan!!!
Zara
Hi, I want to change language for whole application. I followed the steps but my app has fragments and don’t work on that way. Could you please help me?
I have class BaseActivity which extend Activity and it has attachBaseContext(Context base) overriding.
In MaineApplication which extend AppCompatActivity I have override attachBaseContext(Context base).
And in fragment I have updateViews(String language).
All my activity extend BaseActivity or have attachBaseContext overriding.
When I put this.recreate() in all activity in onCreate() my app crash.
Do I need put something in fragments or don’t? How to change language in app with activity and fragment. Which part of code I need put in activity and which part in fragment?
If that’s not the issue then please provide your logs and some kind of sample project on github so that I can understand the problem because without seeing what you’ve done, It is extremely difficult to understand your issue.
Hi @disqus_wXlkw7HQP8:disqus, I used API 26 Oreo Pixel 2 emulator and it’s working fine. Did you applied everything stated? If so then can you provide some kind of sample code so that I can see what’s missing?
Leave a Reply