Change Locale in runtime

 Android supports multi-language. During Android apps development, we put the locale-specific text in different String.xml files. Android apps will load the corresponding text defined in String.xml according to the system locale setting at startup. However, in some case, we may want to switch the locale in the app differently to the system setting. We can change the Locale in Activity or Fragment.

Change Locale

We access Context -> Resource -> Configuration and set Locale
Configuration configuration = getResources().getConfiguration();
configuration.setLocale(selectedLanguage);
getResources().updateConfiguration(configuration, getResources().getDisplayMetrics());

  • Change the Locale inside Activity and restart Activity:
Configuration configuration = getResources().getConfiguration();
configuration.locale = selectedLanguage;
getResources().updateConfiguration(configuration, getResources().getDisplayMetrics());

getActivity().recreate();

  • Change Locale inside a Fragment and navigate up immediately:
Configuration configuration = getResources().getConfiguration();
configuration.locale = selectedLanguage;
getResources().updateConfiguration(configuration, getResources().getDisplayMetrics());

Navigation.findNavController(v).navigateUp();

Problems

However, I have met below problems:
  1. If the app is currently connected to devices, bluetooth devices for example, it will disconnect once you restart Activity.

  2. When the Activity restarts and the fragment(in which recreated() is called ) is popped up. The title of the toolbar(if there is) becomes the name of the app. When I navigate to another fragment, the title of the toolbar resumes normal text with the new Locale. Similar problem happened when I change locale inside Fragment.

  3. After setting a new Locale, the text(whole apop) changes back to the previous Locale form when I first navigate to a fragment containing the UI component WebView.


Solutions
Here is the solution I used:
  1. To restart Activity, the Android system must first destroy the existing Activity. The connection between the devices is lost when the existing Activity is destroyed . There we change the locale inside a fragment, instead of restarting Activity. The existing Activity keeps alive.
  2. We set the title of ActionBar in each Fragment ‘s onViewCreated() method. Therefore, each Fragment must update the title according to new Locale when it is created.
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState){
       super.onViewCreated(view, savedInstanceState);
    
       ActionBar bar = ((AppCompatActivity) getActivity()).getSupportActionBar();
       bar.setTitle(R.string.actionBarTitle);
       bar.show();
    .......
    
  3. WebView is the system module and is running in a sandbox. It is not bound by the app Locale but the system Locale. Therefore, we need to store the app Locale before inflating the layout which contains WebView.
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                            Bundle savedInstanceState) {
    
       if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
           displayedLocale = getResources().getConfiguration().getLocales().get(0);
       else
           displayedLocale = getResources().getConfiguration().locale;
      
       return inflater.inflate(R.layout.fragment_sample, container, false);
    }
    
    Then we set the Locale again after inflating the layout.
    @Override
    public void onViewCreated(View view, Bundle saveInstanceState){
       super.onViewCreated(view, saveInstanceState);
    
       Resources res = getResources();
       Configuration configuration = res.getConfiguration();
     
       configuration.setLocale(displayedLocale);
       getResources().updateConfiguration(configuration, res.getDisplayMetrics());
    
       WebView mWebView = (WebView) view.findViewById(R.id.my_webview);
    .........
    
    Now WebView can load the content with correct content and do not affect app Locale.

留言

此網誌的熱門文章

Use okhttp to download file and show progress bar

Download File into app specific storage with Retrofit

Unzipp file with Zip4j library