Zmień język aplikacji programowo w systemie Android

448

Czy można programowo zmienić język aplikacji, nadal korzystając z zasobów Androida?

Jeśli nie, to czy można poprosić o zasób w określonym języku?

Chciałbym umożliwić użytkownikowi zmianę języka aplikacji z aplikacji.

hpique
źródło
4
Możesz użyć następującej biblioteki, która zawiera listę języków, preferencje ekranu ustawień i zastępuje język w aplikacji: github.com/delight-im/Android-Languages
caw
@MarcoW. Czy wiesz, czy Android-Languages ​​współpracuje z Androidem 5.0 Lollipop?
neu242
1
@ neu242 Tak, działa na Androidzie 5.0 bez żadnych problemów.
caw
1
Możesz użyć następującej biblioteki: github.com/zeugma-solutions/locale-helper-android
josue.0
1
@ josue.0, że biblioteka jest naprawdę najczystszym rozwiązaniem tego
problemu

Odpowiedzi:

376

To jest możliwe. Możesz ustawić ustawienia regionalne. Jednak nie poleciłbym tego. Wypróbowaliśmy to na wczesnych etapach, w zasadzie walczy z systemem.

Mamy ten sam wymóg zmiany języka, ale postanowiliśmy zgodzić się na fakt, że interfejs użytkownika powinien być taki sam jak interfejs telefonu. Działało przez ustawienie regionalne, ale było zbyt błędne. I musisz to ustawić za każdym razem, gdy wprowadzasz aktywność (każdą aktywność) z mojego doświadczenia. oto kod, jeśli nadal go potrzebujesz (ponownie, nie polecam tego)

Resources res = context.getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.setLocale(new Locale(language_code.toLowerCase())); // API 17+ only.
// Use conf.locale = new Locale(...) if targeting lower versions
res.updateConfiguration(conf, dm);

Jeśli masz treści specyficzne dla języka - możesz zmienić tę bazę w zależności od ustawienia.


aktualizacja 26 marca 2020 r

public static void setLocale(Activitycontext) {
        Locale locale;
        Sessions session = new Sessions(context);
        //Log.e("Lan",session.getLanguage());
            locale = new Locale(langCode);
        Configuration config = new Configuration(context.getResources().getConfiguration());
        Locale.setDefault(locale);
        config.setLocale(locale);

       context.getBaseContext().getResources().updateConfiguration(config,
              context.getBaseContext().getResources().getDisplayMetrics());
    }
Alex Volovoy
źródło
329
Nie mogę uwierzyć, że Android tak to utrudnia. Naprawdę nie rozumiem, dlaczego między ustawieniami telefonu a aplikacjami powinna istnieć Powiązanie STRICT. Zawsze mam telefon w języku angielskim, chociaż nie jestem rodzimym językiem angielskim. Powodem jest to, że przetłumaczone pół-techniczne słowa stają się zbyt dziwne w moim własnym języku, więc angielski jest o wiele łatwiejszy. Ułatwia mi także postępowanie zgodnie z radami z sieci. Ale to nie znaczy, że chcę, aby KAŻDA aplikacja na moim telefonie używała języka angielskiego (chociaż jest to całkowicie OK, jest to ustawienie domyślne). Chcę mieć możliwość wyboru !!!
peterh
9
Wygląda na to, że wprowadzono interfejs API na poziomie 17 Context.createConfigurationContext(), którego można użyć do zawinięcia domyślnego kontekstu konfiguracją specyficzną dla ustawień regionalnych, a następnie wywołania getResourcesgo bez konieczności aktualizacji konfiguracji samych obiektów zasobów.
JAB
8
Musisz umieścić to w funkcji onCreate () każdej aktywności. W przeciwnym razie system może zostać zastąpiony przez system - na przykład, gdy zmienisz urządzenie w poziomą, a aktywność zostanie odtworzona z nową konfiguracją (pod warunkiem, że jest to system).
Zsolt Safrany
14
Jeśli ustawisz ustawienia regionalne RTL, takie jak „ar” i chcesz, aby foldery zasobów -ldrtl również działały, to również wywołaj conf.setLayoutDirection (ustawienia narodowe);
Zsolt Safrany
3
@ZsoltSafrany - Zamiast dodawania wywołanie conf.setLayoutDirection(locale), można zastąpić conf.locale = new Locale(...))z conf.setLocale(new Locale(...)). Zadzwoni wewnętrznie setLayoutDirection.
Ted Hopp,
180

Ten kod naprawdę działa:

fa = perski, en = angielski

Wpisz swój kod języka w languageToLoadzmiennej:

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;

public class Main extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String languageToLoad  = "fa"; // your language
    Locale locale = new Locale(languageToLoad); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config, 
      getBaseContext().getResources().getDisplayMetrics());
    this.setContentView(R.layout.main);
  }
}
AliSh
źródło
2
Chcę zmienić ustawienia regionalne w czasie wykonywania, w kodzie wstawiasz kod przed metodą setContentView (). Więc twój kod nie jest dla mnie przydatny, Więc Jak zmienić język w czasie wykonywania, W mojej aplikacji są dwa przyciski radiowe, włączony dla angielskiego i drugi dla arabskiego,
Dwivedi Ji
2
@ Buffalo, to tylko drugi argument dla Resources.updateConfigurationmetody. Wciłem kod, aby był bardziej przejrzysty.
Czechnology
5
Działa to dobrze dla wszystkich działań po ustawieniu w działaniu uruchamiającym. Ale tytuł paska akcji wydaje się niezmieniony i nadal wyświetla domyślny język. Masz pojęcie, co mogłem przeoczyć?
AndroidMechanic - Viral Patel
8
Config.locale jest przestarzałe
Zoe
2
zamiast „config.locale = locale;” use "if (Build.VERSION.SDK_INT> = 17) {config.setLocale (locale);} else {config.locale = locale;}
roghayeh hosseini 25.08.18
36

Szukałem sposobu programowej zmiany języka systemu. Chociaż w pełni rozumiem, że normalna aplikacja nigdy nie powinna tego robić i zamiast tego albo:

  • użytkownik powinien zostać wskazany (przez zamiar) do ustawień systemu, aby zmienić go ręcznie
  • aplikacja powinna sama obsługiwać swoją lokalizację, tak jak opisano w odpowiedzi Alexa

istniała potrzeba naprawdę programowej zmiany języka systemu.

Jest to nieudokumentowane API i dlatego nie powinno się go stosować w aplikacjach rynkowych / końcowych!

W każdym razie oto rozwiązanie, które znalazłem:

  Locale locale = new Locale(targetLocaleAsString);

  Class amnClass = Class.forName("android.app.ActivityManagerNative");
  Object amn = null;
  Configuration config = null;

  // amn = ActivityManagerNative.getDefault();
  Method methodGetDefault = amnClass.getMethod("getDefault");
  methodGetDefault.setAccessible(true);
  amn = methodGetDefault.invoke(amnClass);

  // config = amn.getConfiguration();
  Method methodGetConfiguration = amnClass.getMethod("getConfiguration");
  methodGetConfiguration.setAccessible(true);
  config = (Configuration) methodGetConfiguration.invoke(amn);

  // config.userSetLocale = true;
  Class configClass = config.getClass();
  Field f = configClass.getField("userSetLocale");
  f.setBoolean(config, true);

  // set the locale to the new value
  config.locale = locale;

  // amn.updateConfiguration(config);
  Method methodUpdateConfiguration = amnClass.getMethod("updateConfiguration", Configuration.class);
  methodUpdateConfiguration.setAccessible(true);
  methodUpdateConfiguration.invoke(amn, config);
icyerasor
źródło
2
podaj wyjątek invocationtarget wyjątek
Ravi
1
Cóż, zależy od tego, gdzie zostanie zgłoszony wyjątek invocationTargetException. Następnie powinieneś znać klasę, która została zmieniona.
icyerasor
1
@ Rat-a-tat-a-tat Ratatouille, począwszy od Androida 4.2, android.permission.CHANGE_CONFIGURATIONmoże być przyznany tylko przez aplikację podpisaną kluczem perform.
Yeung
3
Umieszczam moją aplikację w / system / priv-app, aby obejść problem z Androidem 6.0. Szczegóły tutaj .
weiyin
1
@Ravi musiałem przenieść swoją aplikację z / system / app do / system / priv-app, aby działała
alexislg
31

Jeśli chcesz zachować zmieniony język w całej aplikacji, musisz zrobić dwie rzeczy.

Najpierw utwórz podstawową aktywność i spraw, aby wszystkie Twoje działania obejmowały:

public class BaseActivity extends AppCompatActivity {

    private Locale mCurrentLocale;

    @Override
    protected void onStart() {
        super.onStart();

        mCurrentLocale = getResources().getConfiguration().locale;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Locale locale = getLocale(this);

        if (!locale.equals(mCurrentLocale)) {

            mCurrentLocale = locale;
            recreate();
        }
    }

    public static Locale getLocale(Context context){
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        String lang = sharedPreferences.getString("language", "en");
        switch (lang) {
            case "English":
                lang = "en";
                break;
            case "Spanish":
                lang = "es";
                break;
        }
        return new Locale(lang);
    }
}

Pamiętaj, że zapisuję nowy język we wspólnej preferencji.

Po drugie, utwórz rozszerzenie aplikacji w ten sposób:

    public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        setLocale();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        setLocale();
    }

    private void setLocale() {

        final Resources resources = getResources();
        final Configuration configuration = resources.getConfiguration();
        final Locale locale = getLocale(this);
        if (!configuration.locale.equals(locale)) {
            configuration.setLocale(locale);
            resources.updateConfiguration(configuration, null);
        }
    }
}

Zauważ, że getLocale () jest taki sam jak powyżej.

To wszystko! Mam nadzieję, że to może komuś pomóc.

Daniel S.
źródło
Aktywność aplikacji to podstawowa czynność, taka jak MainActivity? na przykład mogę rozwiązać to w setLocale () w mojej metodzie onCreate ()?
Morozow
Aplikacja jest rozszerzeniem aplikacji, nie jest działaniem. Przepraszam, nie rozumiem, czego potrzebujesz. Może możesz spróbować wyjaśnić mi jeszcze raz :)
Daniel S.
1
dla tych noobów z Androidem, takich jak ja, przyjdź tutaj, aby dowiedzieć się, co to Applicationjest i jak korzystać. mobomo.com/2011/05/how-to-use-application-object-of-android
Siwei Shen 申思维
2
configuration.locatejest przestarzałe, setLocale wymaga API 17+ i updateConfiguration jest przestarzałe
Zoe
19

Zgodnie z tym artykułem . Będziesz musiał pobrać LocaleHelper.javaodnośniki w tym artykule.

  1. Utwórz MyApplicationklasę, która będzie rozszerzanaApplication
  2. Zastąp, attachBaseContext()aby zaktualizować język.
  3. Zarejestruj tę klasę w manifeście.

    public class MyApplication extends Application {
       @Override
       protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
       }
    }
    
    <application
         android:name="com.package.MyApplication"
         .../>
  4. Utwórz BaseActivityi zastąp, onAttach()aby zaktualizować język. Potrzebny do Androida 6+

    public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
  5. Spraw, by wszystkie działania związane z Twoją aplikacją były rozszerzone BaseActivity.

    public class LocaleHelper {
    
    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
    
    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }
    
    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }
    
    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }
    
    public static Context setLocale(Context context, String language) {
        persist(context, language);
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }
    
        return updateResourcesLegacy(context, language);
    }
    
    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }
    
    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();
    
        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }
    
    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);
    
        return context.createConfigurationContext(configuration);
    }
    
    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Resources resources = context.getResources();
    
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }
    
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    
        return context;
    }
    }
Khaled Lela
źródło
nie mogę użyć super.attachBaseContext (LocaleHelper.onAttach (newBase)), ponieważ już korzystam z super.attachBaseContext (CalligraphyContextWrapper.wrap (newBase))
Rasel
1
możesz owinąć się nawzajem. super.attachBaseContext (CalligraphyContextWrapper.wrap (LocaleHelper.onAttach (newBase)))
Yeahia2508
15

Właśnie dodałem dodatkowy kawałek, który mnie potknął.

Podczas gdy inne odpowiedzi działają na przykład dobrze z „de”

String lang = "de";
Locale locale = new Locale(lang); 
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
    getBaseContext().getResources().getDisplayMetrics());

Powyższe nie będzie działać na przykład z "fr_BE"ustawieniami regionalnymi, więc użyje values-fr-rBEfolderu lub podobnego.

Wymaga następującej niewielkiej zmiany do pracy "fr_BE"

String lang = "fr";

//create a string for country
String country = "BE";
//use constructor with country
Locale locale = new Locale(lang, country);

Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
    getBaseContext().getResources().getDisplayMetrics());
wyzwala
źródło
1
jeśli chcesz zastosować zmianę ustawień regionalnych do bieżącej otwartej aktywności, zadzwońactivity.recreate()
Do Kra
Wiem, że spóźniłem się na przyjęcie, ale nowe ustawienia regionalne (język, kraj) były wszystkim, czego potrzebowałem!
Jacob Holloway
activity.recreate () jak to działa lub jeśli to obliczymy, String lang = "fr"; String country = "BE"; nigdy nie zastąpi tego, jak upłynie czas
Amitsharma
Co powiesz na używanie android.content.res.Configuration conf = res.getConfiguration();zamiast tworzenia nowej Configurationinstancji? Czy jest jakaś korzyść z używania nowej?
Bianca Daniciuc
14

Zostałem zmieniony na język niemiecki, ponieważ moja aplikacja sama się uruchamia.

Oto mój poprawny kod. Każdy chce użyć tego samego dla mnie .. (Jak programowo zmienić język w Androidzie)

mój kod:

Configuration config ; // variable declaration in globally

// this part is given inside onCreate Method starting and before setContentView()

public void onCreate(Bundle icic) 
{
    super.onCreate(icic);
    config = new Configuration(getResources().getConfiguration());
    config.locale = Locale.GERMAN ;
    getResources().updateConfiguration(config,getResources().getDisplayMetrics());

    setContentView(R.layout.newdesign);
}
harikrishnan
źródło
1
@harikrishnan To nie działa dla mnie, a klawiatura nie zmienia się na określony język. Jak zadeklarowałeś aktywność w manifeście?
Avadhani Y
13

Wiem, że jest późno na odpowiedź, ale znalazłem ten artykuł tutaj . Co bardzo dobrze wyjaśnia cały proces i zapewnia dobrze ustrukturyzowany kod.

Klasa pomocnika ustawień regionalnych:

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;

import java.util.Locale;

/**
 * This class is used to change your application locale and persist this change for the next time
 * that your app is going to be used.
 * <p/>
 * You can also change the locale of your application on the fly by using the setLocale method.
 * <p/>
 * Created by gunhansancar on 07/10/15.
 */
public class LocaleHelper {

    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";

    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }

    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }

    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }

    public static Context setLocale(Context context, String language) {
        persist(context, language);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }

        return updateResourcesLegacy(context, language);
    }

    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }

    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();

        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);

        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Resources resources = context.getResources();

        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }

        resources.updateConfiguration(configuration, resources.getDisplayMetrics());

        return context;
    }
}

Musisz przesłonić attachBaseContext i wywołać LocaleHelper.onAttach (), aby zainicjować ustawienia regionalne w aplikacji.

import android.app.Application;
import android.content.Context;

import com.gunhansancar.changelanguageexample.helper.LocaleHelper;

public class MainApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
    }
}

Wszystko, co musisz zrobić, to dodać

LocaleHelper.onCreate(this, "en");

gdziekolwiek chcesz zmienić ustawienia regionalne.

Anirudh Sharma
źródło
LocaleHelper to klasa z artykułu. Wszelkie linki mogą zostać usunięte. Dodaj kod do swojej odpowiedzi.
Zoe
Nie chcę ponownie uruchamiać aplikacji, ponieważ aplikacja wykonuje jakieś zadania, takie jak ekran nagrywania. więc bez ponownego uruchamiania aplikacji istnieje jakieś rozwiązanie dla Androida 7.0
PriyankaChauhan
1
@PriyankaChauhan Myślę, że artykuł dotyczy tego przypadku: Masz dwie opcje aktualizacji obecnie widocznego układu: Po pierwsze , możesz po prostu zaktualizować tekst lub inne zasoby zależne od języka jeden po drugim.
Maksim Turaev
dzięki za dodanie nowego createConfigurationContext , który był pomocny
jacoballenwood
1
onCreate czy onAttach to call?
vanste25
12

Utwórz klasę Rozszerza Applicationi tworzy metodę statyczną. Następnie możesz wywołać tę metodę we wszystkich czynnościach wcześniej setContentView().

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
}

public static void setLocaleFa (Context context){
    Locale locale = new Locale("fa"); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    context.getApplicationContext().getResources().updateConfiguration(config, null);
}

public static void setLocaleEn (Context context){
    Locale locale = new Locale("en_US"); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    context.getApplicationContext().getResources().updateConfiguration(config, null);
}

}

Zastosowanie w działaniach:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyApp.setLocaleFa(MainActivity.this);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
}
Behzad Taghipour
źródło
10

W przypadku Androida 7.0 Nougat (i niższych wersji) postępuj zgodnie z tym artykułem:

Programowo zmieniaj język w systemie Android

Stara odpowiedź
Obejmuje to obsługę RTL / LTR:

public static void changeLocale(Context context, Locale locale) {
    Configuration conf = context.getResources().getConfiguration();
    conf.locale = locale;
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
       conf.setLayoutDirection(conf.locale);
    }

    context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());
}
Duda
źródło
1
updateConfiguracja jest przestarzała. Link jest przydatny, dodaj go do swojej odpowiedzi. (Odpowiedzi tylko na link nie są dobre, ponieważ link może zostać usunięty. Jeśli tak się stanie, ta odpowiedź jest bezużyteczna)
Zoe
8

Jedynym rozwiązaniem, które w pełni działa dla mnie, jest połączenie kodu Alexa Volovoya z mechanizmem ponownego uruchamiania aplikacji:

void restartApplication() {
    Intent i = new Intent(MainTabActivity.context, MagicAppRestart.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MainTabActivity.context.startActivity(i);
}


/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        finish();
    }

    protected void onResume() {
        super.onResume();
        startActivityForResult(new Intent(this, MainTabActivity.class), 0);         
    }
}
Misza
źródło
2
po zmianie ustawień regionalnych możesz także zadzwonićactivity.recreate()
Do Kra
1
Nie chcę ponownie uruchamiać aplikacji, ponieważ aplikacja wykonuje jakieś zadania, takie jak ekran nagrywania. więc bez ponownego uruchamiania aplikacji istnieje jakieś rozwiązanie dla Androida 7.0
PriyankaChauhan
7

Miałem do czynienia z tym samym problemem. Na GitHub znalazłem bibliotekę Android-LocalizationActivity .

Ta biblioteka ułatwia zmianę języka aplikacji w czasie wykonywania, co widać na poniższym przykładzie kodu. Przykładowy projekt zawierający poniższy przykładowy kod i więcej informacji można znaleźć na stronie github.

LocalizationActivity rozszerza AppCompatActivity, dzięki czemu można go również używać podczas korzystania z fragmentów.

public class MainActivity extends LocalizationActivity implements View.OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);

        findViewById(R.id.btn_th).setOnClickListener(this);
        findViewById(R.id.btn_en).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.btn_en) {
            setLanguage("en");
        } else if (id == R.id.btn_th) {
            setLanguage("th");
        }
    }
}
Rockney
źródło
7

Czas na odpowiednią aktualizację.

Po pierwsze, przestarzała lista z interfejsem API, w którym została wycofana:

  • configuration.locale (API 17)
  • updateConfiguration(configuration, displaymetrics) (API 17)

Rzeczą, na którą ostatnio nie udzielono odpowiedzi, jest zastosowanie nowej metody .

createConfigurationContext to nowa metoda updateConfiguration.

Niektórzy używali go jako samodzielnego:

Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
createConfigurationContext(overrideConfiguration);

... ale to nie działa. Dlaczego? Metoda zwraca kontekst, który jest następnie używany do obsługi tłumaczeń Strings.xml i innych zlokalizowanych zasobów (obrazów, układów, cokolwiek).

Prawidłowe użycie wygląda następująco:

Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
//the configuration can be used for other stuff as well
Context context  = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();

Jeśli właśnie skopiowałeś to do swojego IDE, możesz zobaczyć ostrzeżenie, że API wymaga kierowania na API 17 lub nowszy. Można to obejść, wprowadzając metodę i dodając adnotację@TargetApi(17)

Ale poczekaj. Co ze starszymi interfejsami API?

Musisz utworzyć inną metodę za pomocą updateConfiguration bez adnotacji TargetApi.

Resources res = YourApplication.getInstance().getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale("th");
res.updateConfiguration(conf, dm);

Nie musisz tutaj zwracać kontekstu.

Teraz zarządzanie nimi może być trudne. W API 17+ potrzebujesz utworzonego kontekstu (lub zasobów z utworzonego kontekstu), aby uzyskać odpowiednie zasoby w oparciu o lokalizację. Jak sobie z tym poradzisz?

Tak to robię:

/**
 * Full locale list: /programming/7973023/what-is-the-list-of-supported-languages-locales-on-android
 * @param lang language code (e.g. en_US)
 * @return the context
 * PLEASE READ: This method can be changed for usage outside an Activity. Simply add a COntext to the arguments
 */
public Context setLanguage(String lang/*, Context c*/){
    Context c = AndroidLauncher.this;//remove if the context argument is passed. This is a utility line, can be removed totally by replacing calls to c with the activity (if argument Context isn't passed)
    int API = Build.VERSION.SDK_INT;
    if(API >= 17){
        return setLanguage17(lang, c);
    }else{
        return setLanguageLegacy(lang, c);
    }
}

/**
 * Set language for API 17
 * @param lang
 * @param c
 * @return
 */
@TargetApi(17)
public Context setLanguage17(String lang, Context c){
    Configuration overrideConfiguration = c.getResources().getConfiguration();
    Locale locale = new Locale(lang);
    Locale.setDefault(locale);
    overrideConfiguration.setLocale(locale);
    //the configuration can be used for other stuff as well
    Context context  = createConfigurationContext(overrideConfiguration);//"local variable is redundant" if the below line is uncommented, it is needed
    //Resources resources = context.getResources();//If you want to pass the resources instead of a Context, uncomment this line and put it somewhere useful
    return context;
}

public Context setLanguageLegacy(String lang, Context c){
    Resources res = c.getResources();
    // Change locale settings in the app.
    DisplayMetrics dm = res.getDisplayMetrics();//Utility line
    android.content.res.Configuration conf = res.getConfiguration();

    conf.locale = new Locale(lang);//setLocale requires API 17+ - just like createConfigurationContext
    Locale.setDefault(conf.locale);
    res.updateConfiguration(conf, dm);

    //Using this method you don't need to modify the Context itself. Setting it at the start of the app is enough. As you
    //target both API's though, you want to return the context as you have no clue what is called. Now you can use the Context
    //supplied for both things
    return c;
}

Ten kod działa, ponieważ ma jedną metodę, która wywołuje odpowiednią metodę na podstawie interfejsu API. Zrobiłem to z wieloma przestarzałymi wywołaniami (w tym Html.fromHtml). Masz jedną metodę, która pobiera potrzebne argumenty, która następnie dzieli ją na jedną z dwóch (lub trzech lub więcej) metod i zwraca odpowiedni wynik na podstawie poziomu API. Jest elastyczny, ponieważ nie musisz sprawdzać wiele razy, metoda „wejścia” robi to za Ciebie. Oto metoda wprowadzaniasetLanguage

PROSZĘ PRZECZYTAĆ TO PRZED ROZPOCZĘCIEM UŻYCIA

Musisz użyć kontekstu zwróconego po otrzymaniu zasobów. Dlaczego? Widziałem tutaj inne odpowiedzi, które używają createConfigurationContext i nie używają kontekstu, który zwraca. Aby to działało, należy wywołać updateConfiguration. Które jest przestarzałe. Użyj kontekstu zwróconego przez metodę, aby uzyskać zasoby.

Przykładowe użycie :

Konstruktor lub coś podobnego:

ctx = getLanguage(lang);//lang is loaded or generated. How you get the String lang is not something this answer handles (nor will handle in the future)

A potem, gdziekolwiek chcesz zdobyć zasoby, które robisz:

String fromResources = ctx.getString(R.string.helloworld);

Użycie dowolnego innego kontekstu (teoretycznie) to złamie.

AFAIK nadal musisz używać kontekstu aktywności do wyświetlania okien dialogowych lub Toastów. w tym celu możesz użyć instancji działania (jeśli jesteś na zewnątrz)


I na koniec użyj recreate()tego działania, aby odświeżyć zawartość. Skrót, aby nie tworzyć zamiaru odświeżenia.

Zoe
źródło
1
Niektórzy mogą się zastanawiać, czy utworzony kontekst będzie kosztował twoją pamięć. Jednak zgodnie z oficjalną dokumentacją Androida: „Każde wywołanie tej metody zwraca nową instancję obiektu Context; Obiekty Context nie są współużytkowane, jednak stan wspólny (ClassLoader, inne zasoby dla tej samej konfiguracji) może być taki, że sam kontekst może być dość lekki ”. Sądzę więc, że Android oczekuje, że użyjesz osobnego obiektu kontekstu dla ustawień regionalnych.
Sira Lam
7

Jeśli napiszesz

android:configChanges="locale"

W każdej aktywności (w pliku manifestu) nie ma potrzeby ustawiania jej przy każdym wejściu Activity.

Brijesh Masrani
źródło
11
Jeśli jest to w manifeście, w jaki sposób stanowi to zmianę w czasie wykonywania, która wydawała się być tym, czego chciał PO?
user316117,
1
@ user316117 Wskazuje systemowi Android, że aplikacja zajmie się wewnętrznie wszystkimi kwestiami dotyczącymi konfiguracji ustawień regionalnych, a nie, że ustawienia regionalne są statyczne. Nie jestem jednak pewien, czy uniemożliwiłoby to Androidowi ustawienie ustawień regionalnych podczas zmiany między Aktywnościami, ponieważ widziałem, że służyłem tylko configChangesdo hakowania, aby zachować stan Aktywności podczas rotacji / etc.
JAB
jak ustawić język tylko na angielski?
Kaveesh Kanwal
1
... dopóki Android nie zabije twojej aktywności, ponieważ potrzebuje więcej pamięci RAM
Louis CAD
@Brijesh Jeśli zmienimy język aplikacji, to jeśli mamy jakąś opcję wyszukiwania w aplikacji, a jeśli to przeszukamy, to w jaki sposób aplikacja wyświetli dane, czy powinniśmy opracować inną bazę danych dla każdego języka lub jakieś ustawienie kodu Androida, więc ta aplikacja może wyświetlać dane według wyszukiwania?
Vishwa Pratap
5
Locale locale = new Locale("en");
Locale.setDefault(locale);

Configuration config = context.getResources().getConfiguration();
config.setLocale(locale);
context.createConfigurationContext(config);

Ważna aktualizacja:

context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());

Zauważ, że w SDK> = 21 musisz wywołać „Resources.updateConfiguration ()” , w przeciwnym razie zasoby nie zostaną zaktualizowane.

Максим Петлюк
źródło
updateConfiguracja jest przestarzała. AFAIK używasz createConfigurationContext i stosujesz do niego kontekst ( Context ctx = createConfigurationContext(args);i otrzymujesz z tego zasoby
Zoe
Wiem, że jest przestarzałe. Ale w każdym razie nie znam żadnego rozwiązania, które mogłoby działać na Androidzie 5 i nowszych.
Максим Петлюк
Wtedy wyraźnie nie sprawdziłeś javadoc. wywołujesz kontekst utworzony z createConfigurationContext
Zoe
Ok, ale i tak powinniśmy wywołać updateConfiguration (), prawda?
Максим Петлюк
1
Nie używaj przestarzałego połączenia. Oznacza brak aktualizacji połączeń Konfiguracja
Zoe
4
/*change language at Run-time*/
//use method like that:
//setLocale("en");
 public void setLocale(String lang) { 
  myLocale = new Locale(lang);         
  Resources res = getResources();         
  DisplayMetrics dm = res.getDisplayMetrics();         
  Configuration conf = res.getConfiguration();         
  conf.locale = myLocale;         
  res.updateConfiguration(conf, dm);         
  Intent refresh = new Intent(this, AndroidLocalize.class);         
  startActivity(refresh); 
 }
Altan Yuksel
źródło
5
nie ma potrzeby rozpoczynania nowej działalności, wystarczy odświeżyć aktualną activity.recreate()
wersję
4

Locale configurationnależy ustawić w każdym activityprzed ustawieniem treści -this.setContentView(R.layout.main);

cheskapac
źródło
Ale co jeśli chcesz przełączać go w locie, po wywołaniu setContentView ()?
IgorGanapolsky
2
po zmianie ustawień regionalnych możesz także zadzwonićactivity.recreate()
Do Kra
4

Najpierw utwórz plik multi string.xml dla różnych języków; następnie użyj tego bloku kodu w onCreate()metodzie:

super.onCreate(savedInstanceState);
String languageToLoad  = "fr"; // change your language here
Locale locale = new Locale(languageToLoad); 
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
  getBaseContext().getResources().getDisplayMetrics());
this.setContentView(R.layout.main);
Mohsen mokhtari
źródło
Dziękuję, ten kod działa świetnie, przetestowałem na Androidzie 5.xi 6.x bez żadnych problemów
innovaciones
4

Oto kod, który działa dla mnie:

public class  MainActivity extends AppCompatActivity {
    public static String storeLang;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        SharedPreferences shp = PreferenceManager.getDefaultSharedPreferences(this);
        storeLang = shp.getString(getString(R.string.key_lang), "");

        // Create a new Locale object
        Locale locale = new Locale(storeLang);

        // Create a new configuration object
        Configuration config = new Configuration();
        // Set the locale of the new configuration
        config.locale = locale;
        // Update the configuration of the Accplication context
        getResources().updateConfiguration(
                config,
                getResources().getDisplayMetrics()
        );

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Źródło: tutaj

Til Schweiger
źródło
3

Żadne z wymienionych tutaj rozwiązań nie pomogło mi.

Język nie włącza się w Androidzie> = 7.0, jeśli AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE_NIGHT_YES)

To LocaleUtils działa dobrze: https://gist.github.com/GigigoGreenLabs/7d555c762ba2d3a810fe

LocaleUtils

public class LocaleUtils {

public static final String LAN_SPANISH      = "es";
public static final String LAN_PORTUGUESE   = "pt";
public static final String LAN_ENGLISH      = "en";

private static Locale sLocale;

public static void setLocale(Locale locale) {
    sLocale = locale;
    if(sLocale != null) {
        Locale.setDefault(sLocale);
    }
}

public static void updateConfig(ContextThemeWrapper wrapper) {
    if(sLocale != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Configuration configuration = new Configuration();
        configuration.setLocale(sLocale);
        wrapper.applyOverrideConfiguration(configuration);
    }
}

public static void updateConfig(Application app, Configuration configuration) {
    if(sLocale != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        //Wrapping the configuration to avoid Activity endless loop
        Configuration config = new Configuration(configuration);
        config.locale = sLocale;
        Resources res = app.getBaseContext().getResources();
        res.updateConfiguration(config, res.getDisplayMetrics());
    }
}
}

Dodano ten kod do aplikacji

public class App extends Application {
public void onCreate(){
    super.onCreate();

    LocaleUtils.setLocale(new Locale("iw"));
    LocaleUtils.updateConfig(this, getBaseContext().getResources().getConfiguration());
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    LocaleUtils.updateConfig(this, newConfig);
}
}

Kod w działaniu

public class BaseActivity extends AppCompatActivity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}
Pavel Shirokov
źródło
2

Odpowiedź Alex Volovoy działa tylko dla mnie, jeśli jest w metodzie onCreate działania.

Odpowiedź, która działa we wszystkich metodach, znajduje się w innym wątku

Zmień język programowo w Androidzie

Oto adaptacja kodu



    Resources standardResources = getBaseContext().getResources();

    AssetManager assets = standardResources.getAssets();

    DisplayMetrics metrics = standardResources.getDisplayMetrics();

    Configuration config = new Configuration(standardResources.getConfiguration());

    config.locale = new Locale(languageToLoad);

    Resources defaultResources = new Resources(assets, metrics, config);

Mam nadzieję, że to pomaga.

gmauri21
źródło
19
Powiedziałeś „Odpowiedź, która działa we wszystkich metodach, jest w innym wątku”, ale twój link wskazuje na TYM wątku! ”
user316117,
1
config.locale jest przestarzałe
Zoe
2
odpowiedź rekurencyjna, możliwe StackOverflow
tamtom
2

Należy pamiętać, że korzystanie z tego rozwiązania updateConfiguration nie będzie już działać z wydaniem Androida M za kilka tygodni. Nowym sposobem na to jest teraz użycie applyOverrideConfigurationmetody z ContextThemeWrapper patrz dokumentacja API

Możesz znaleźć moje pełne rozwiązanie tutaj, ponieważ sam napotkałem problem: https://stackoverflow.com/a/31787201/2776572

Eric Labelle
źródło
Próbuję kodu updateConfiguration na Androidzie 6.0.1 i działa dobrze, nie wiem czy Google to naprawiło, ale mogę go używać bez problemów
innovaciones
1
Nieaktualne metody @innovaciones są już dostępne. W końcu zostanie usunięty. Zajmuje to dużo czasu, ale najlepiej jak najszybciej przejść do nowych interfejsów API, aby uniknąć problemów na późniejszym etapie
Zoe
1

Jest kilka kroków, które powinieneś wdrożyć

Najpierw musisz zmienić ustawienia regionalne swojej konfiguracji

Resources resources = context.getResources();

Configuration configuration = resources.getConfiguration();
configuration.locale = new Locale(language);

resources.updateConfiguration(configuration, resources.getDisplayMetrics());

Po drugie, jeśli chcesz, aby zmiany miały zastosowanie bezpośrednio do widocznego układu, możesz albo zaktualizować widoki bezpośrednio, albo po prostu wywołać activity.recreate (), aby zrestartować bieżącą aktywność.

Musisz także zachować zmiany, ponieważ po zamknięciu aplikacji przez użytkownika stracisz zmianę języka.

Bardziej szczegółowe rozwiązanie wyjaśniłem na moim blogu Zmień programowo język w systemie Android

Zasadniczo wystarczy wywołać funkcję LocaleHelper.onCreate () w klasie aplikacji, a jeśli chcesz zmienić ustawienia lokalne w locie, możesz wywołać funkcję LocaleHelper.setLocale ()

Gunhan
źródło
@LunarWatcher Tak, jeśli faktycznie sprawdzasz kod na github lub gist, jest on już obsługiwany.
Gunhan
1

Działa to, gdy naciskam przycisk, aby zmienić język tekstu w TextView. (Strings.xml w folderze wartości)

String languageToLoad = "de"; // your language
Configuration config = getBaseContext().getResources().getConfiguration();
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
recreate();
ashishdhiman2007
źródło
1

Dodaj klasę LocaleHelper

public class LocaleHelper{ 
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
public static Context onAttach(Context context) {
    String lang = getPersistedData(context, Locale.getDefault().getLanguage());
    return setLocale(context, lang);
}

public static Context onAttach(Context context, String defaultLanguage) {
    String lang = getPersistedData(context, defaultLanguage);
    return setLocale(context, lang);
}

public static String getLanguage(Context context) {
    return getPersistedData(context, Locale.getDefault().getLanguage());
}
public static Context setLocale(Context context, String language) {
    persist(context, language);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, language);
    }

    return updateResourcesLegacy(context, language);
}

private static String getPersistedData(Context context, String defaultLanguage) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
}

private static void persist(Context context, String language) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();

    editor.putString(SELECTED_LANGUAGE, language);
    editor.apply();
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Resources resources = context.getResources();

    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        configuration.setLayoutDirection(locale);
    }

    resources.updateConfiguration(configuration, resources.getDisplayMetrics());

    return context;
}
}

W działaniu lub fragmencie

Context context = LocaleHelper.setLocale(this, App.getSharedPre().getLanguage());
Resource resources = context.getResources();

Teraz SetText na każdym tekście

TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));
Baljinder Maan
źródło
0

podobna do przyjętej wersji z odpowiedzią, ale z 2017 r. i dodanego restartu (bez restartu, czasami następna czynność nadal wyświetla angielski):

// Inside some activity...
private void changeDisplayLanguage(String langCode) {
// Step 1. Change the locale in the app's configuration
    Resources res = getResources();
    android.content.res.Configuration conf = res.getConfiguration();
    conf.setLocale(currentLocale);
    createConfigurationContext(conf);
// Step 2. IMPORTANT! you must restart the app to make sure it works 100%
    restart();
}
private void restart() {
    PackageManager packageManager = getPackageManager();
    Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
    ComponentName componentName = intent.getComponent();
    Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
    mainIntent.putExtra("app_restarting", true);
    PrefUtils.putBoolean("app_restarting", true);
    startActivity(mainIntent);
    System.exit(0);
}
ericn
źródło
1) użyj Finish () zamiast 2), aby ponownie uruchomić aplikację, której możesz użyć activity.recreate()3) zwrócony kontekst Myślę, że należy użyć, aby uzyskać zasoby
Zoe
Nie chcę ponownie uruchamiać aplikacji, ponieważ aplikacja wykonuje jakieś zadania, takie jak ekran nagrywania. więc bez ponownego uruchamiania aplikacji istnieje jakieś rozwiązanie dla Androida 7.0
PriyankaChauhan
0

Najpierw tworzysz wartości nazw katalogów - „Nazwa języka” jak hindi niż piszesz „cześć” i kopiujesz w tym katalogu nazwę pliku z ciągiem, a wartość nie zmienia parametru po ustawieniu poniżej kodu w akcji, takiej jak przycisk itp.

Locale myLocale = new Locale("hi");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
Intent refresh = new Intent(Home.this, Home.class);
startActivity(refresh);
finish(); 
Dhaval Shingala
źródło
1
conf.localejest przestarzałe
Zoe
0
private void setLanguage(String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        config.setLocale(locale);
    } else {
        config.locale = locale;
    }
    getResources().updateConfiguration(config,
            getResources().getDisplayMetrics());

}
Adeeb Karim
źródło
1
Nie chcę ponownie uruchamiać aplikacji, ponieważ aplikacja wykonuje jakieś zadania, takie jak ekran nagrywania. więc bez ponownego uruchamiania aplikacji istnieje jakieś rozwiązanie dla Androida 7.0
PriyankaChauhan
tak na 6.0 działa dla mnie dobrze, bez restartowania aplikacji, zmieniony język, ale nie testowałem na 7.0
Adeeb karim
0

W przykładzie ustawiamy język angielski:

 Configuration config = GetBaseContext().getResources().getConfiguration();
 Locale locale = new Locale("en");
 Locale.setDefault(locale);
 config.locale = locale;
 GetBaseContext().getResources().updateConfiguration(config, 
            GetBaseContext().getResources().getDisplayMetrics());

Pamiętaj, że działa to tylko wtedy, gdy język znajduje się również w systemie urządzeń, nie tylko w aplikacji

Pavel Pekki
źródło
0

Do obsługi języka arabskiego / RTL

  1. Musisz zaktualizować ustawienia języka za pomocą - attachBaseContext ()
  2. W przypadku Androida w wersji N i nowszej musisz użyć createConfigurationContext () i updateConfiguration () - w przeciwnym razie układ RTL nie będzie działał poprawnie

 @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(updateBaseContextLocale(newBase));
    }

    public Context updateBaseContextLocale(Context context) {
        String language = SharedPreference.getInstance().getValue(context, "lan");//it return "en", "ar" like this
        if (language == null || language.isEmpty()) {
            //when first time enter into app (get the device language and set it
            language = Locale.getDefault().getLanguage();
            if (language.equals("ar")) {
                SharedPreference.getInstance().save(mContext, "lan", "ar");
            }
        }
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            updateResourcesLocale(context, locale);
            return  updateResourcesLocaleLegacy(context, locale);
        }

        return updateResourcesLocaleLegacy(context, locale);
    }

    @TargetApi(Build.VERSION_CODES.N)
    private Context updateResourcesLocale(Context context, Locale locale) {
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private Context updateResourcesLocaleLegacy(Context context, Locale locale) {
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
        return context;
    }

Ranjith Kumar
źródło