Jak zmienić język aplikacji, gdy użytkownik wybierze język?

106

Chcę, aby moja aplikacja obsługiwała trzy języki: hiszpański, portugalski i angielski. I daj opcję wyboru języka w aplikacji

1) 3 foldery do rysowania drawable-es, drawable-pt, drawable.

2) Folder z 3 wartościami wartości-es, wartości-pt, wartości Zmień wartości String.xml według języków.

Mam imageView, aby wybrać język, po kliknięciu go otworzy się menu zawierające opcje angielski, hiszpański, portugalski.

Ustawiłem Locale wewnątrz aplikacji na wybór opcji za pomocą tego kodu

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.en:
             Locale locale = new Locale("en"); 
             Locale.setDefault(locale);
             Configuration config = new Configuration();
             config.locale = locale;
             getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
             Toast.makeText(this, "Locale in English !", Toast.LENGTH_LONG).show();
             break;

        case R.id.pt:
             Locale locale2 = new Locale("pt"); 
             Locale.setDefault(locale2);
             Configuration config2 = new Configuration();
             config2.locale = locale2;
             getBaseContext().getResources().updateConfiguration(config2, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Portugal !", Toast.LENGTH_LONG).show();
             break;

        case R.id.es:
             Locale locale3 = new Locale("es"); 
             Locale.setDefault(locale3);
             Configuration config3 = new Configuration();
             config3.locale = locale3;
             getBaseContext().getResources().updateConfiguration(config3, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Spain !", Toast.LENGTH_LONG).show();
             break;     
    }
    return super.onOptionsItemSelected(item);
}

Zadeklarowałem w Manifest- android: configChanges = "locale"

Działa, ale ma pewien problem.

Problem:-

1) Po wybraniu języka ekran zawierający obraz wyboru języka nie zmienia się, ale zmieniają się inne ekrany.

2) Po zmianie orientacji przywróć język aplikacji zgodnie z lokalizacją telefonu.

mukesh
źródło
1
W przypadku drugiego problemu spróbuj dodać: android:configChanges="locale"dla swojej aktywności w pliku AndroidManifest.xml
Parth Doshi
Dodałem już w każdym działaniu w moim manifeście.
mukesh
Możesz skorzystać z 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

Odpowiedzi:

172

To fragment strony internetowej: http://android.programmerguru.com/android-localization-at-runtime/

Zmiana języka aplikacji jest prosta, gdy użytkownik wybierze ją z listy języków. Miej metodę podobną do poniższej, która akceptuje ustawienia regionalne jako ciąg (np. „En” dla angielskiego, „hi” dla hindi), skonfiguruj ustawienia regionalne dla swojej aplikacji i odśwież swoją bieżącą aktywność, aby odzwierciedlić zmianę języka. Zastosowane ustawienia regionalne nie zostaną zmienione, dopóki nie zmienisz ich ręcznie ponownie.

public void setLocale(String lang) { 
    Locale 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); 
    finish();
    startActivity(refresh); 
} 

Upewnij się, że zaimportowałeś następujące pakiety:

import java.util.Locale; 
import android.os.Bundle; 
import android.app.Activity; 
import android.content.Intent; 
import android.content.res.Configuration; 
import android.content.res.Resources; 
import android.util.DisplayMetrics; 

dodaj w manifeście do działania android: configChanges = "lokalizacja | orientacja"

Udhay
źródło
2
Jasne. Mogę podać fragment strony internetowej. Jeśli muszę to podać, daj mi znać. Dzięki.
Udhay
3
Pamiętaj, aby dodać finish (), aby nie mieć dwóch kopii swojej aktywności w stosie nawigacyjnym.
Joel Teply
6
finish()należy wcześniej zadzwonić startActivity(refresh). W przeciwnym razie aplikacja może zostać zamknięta zamiast ponownego uruchamiania działania.
Mohammed Ali
10
Cześć, zrobiłem to, działa, ale po ponownym uruchomieniu aplikacji wraca do domyślnego języka.
Sofiane Hassaini
5
Konfiguracja config = nowa Konfiguracja (newConfig); config.locale = locale; W moim przypadku otrzymuję tę wiadomość. Ustawienia regionalne wycofane na poziomie API 25
Milon
9

Dobre rozwiązania wyjaśniono tutaj całkiem dobrze. Ale oto jeszcze jeden.

Utwórz własną CustomContextWrapperrozszerzającą klasę ContextWrapperi użyj jej do zmiany ustawień regionalnych dla całej aplikacji. Oto GIST z użyciem.

Następnie wywołaj CustomContextWrapperz zapisanym identyfikatorem ustawień regionalnych, np. 'hi'Dla języka hindi w metodzie cyklu życia działania attachBaseContext. Użycie tutaj:

@Override
protected void attachBaseContext(Context newBase) {
    // fetch from shared preference also save the same when applying. Default here is en = English
    String language = MyPreferenceUtil.getInstance().getString("saved_locale", "en");
    super.attachBaseContext(MyContextWrapper.wrap(newBase, language));
}
sud007
źródło
Dzięki za link to działa, ale nie rozumiem kilku rzeczy, po prostu nazywa MyContextWrapper.warpsię onAttachod jednego fragmentu mojego app ale język został zmieniony dla całej aplikacji, ale tytuły działalności nie uległy zmianie, myślę, że wynika z tego, że tytuły manifestu mają pierwszeństwo, ale jeśli wywołam tę samą metodę w onAttachBaseContexmojej podklasie aplikacji, tytuły działań również zmienią się na wybrany język, ale wtedy zmiany zostaną zastosowane tylko do fragmentu, który wywołałem w metodzie warp, dlaczego tak jest ?
Abhinav Chauhan
@AbhinavChauhan Nie jestem pewien, czy to prawda. Muszę to sprawdzić. Nigdy nie spotkałem się z tym problemem, wdrażając to rozwiązanie. Jednak minęło dużo czasu i mogą pojawić się pewne zmiany w implementacji Androida dla nowszych wersji. Alternatywnie wypróbuj najnowsze odpowiedzi w tym poście.
sud007
próbowałem wielu rozwiązań, ale żadne z nich nie działało, a może zaimplementowałem je nieprawidłowo, może twoja klasa działa dobrze z działaniami, używam jej warpmetody w onAttachfragmencie, wcześniej powiedziałem, że muszę to zrobić z fragmentem mainactivity i zmienionym językiem cała aplikacja to prawda, ale dla wszystkich innych fragmentów język zmienia się na angielski przy zmianie konfiguracji, więc muszę wstawić onattachwszystkie fragmenty i zamiast manifestu ustawić tytuły paska akcji w kodzie, teraz aplikacja działa zgodnie z oczekiwaniami. dzięki
Abhinav Chauhan
W porządku! Jestem pewien, że nie musisz tego robić na każdym ekranie, tylko przy pierwszym uruchomieniu i tylko wewnątrz attachBaseContextfunkcji. I to dotyczy wszystkich ekranów. Czy utworzyłeś „BaseActivity” dla wszystkich działań w swojej aplikacji?
sud007
Nie próbowałem to zrobić w mojej podklasie aplikacji myśląc, że będzie to zastosowane do całej aplikacji, potem we wszystkich fragmentach, ale okazuje się, że wrap()kod musi być wykonywany przy każdej zmianie konfiguracji, więc umieściłem go w Działalność abstrakcyjna, z której wszystkie inne działania się rozciągają, teraz działa
Abhinav Chauhan
6

Należy albo usunąć android:configChanges="locale"z manifestu, co spowoduje ponowne załadowanie działania, albo nadpisać onConfigurationChangedmetodę:

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
    // your code here, you can use newConfig.locale if you need to check the language
    // or just re-set all the labels to desired string resource
}
Frane Poljak
źródło
Usunięcie android: configChanges = "locale" z manifestu nie zapobiega ponownemu uruchomieniu aplikacji. Uruchomi się ponownie niezależnie od tego, czy zostanie to dodane do manifestu, czy nie.
portfoliobuilder
Nie mówię, że usunięcie android: configChanges = "locale" z manifestu uniemożliwia ponowne uruchomienie aplikacji, mówię dokładnie odwrotnie. Teraz, w przypadku, gdy w manifeście mamy android: configChanges = "locale", to uniemożliwiało to ponowne załadowanie aplikacji w czasie, gdy pisałem tę odpowiedź, nie mogę powiedzieć na pewno, że tak jest teraz.
Frane Poljak,
6

cały powyższy kod @ Uday jest doskonały, ale brakuje tylko jednej rzeczy (domyślna konfiguracja w build.gradle)

public void setLocale(String lang) { 
Locale 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); 
finish();
startActivity(refresh); 

}

Mój nie działał tylko dlatego, że języki nie były wymienione w pliku konfiguracyjnym (build.gradle)

 defaultConfig {
    resConfigs "en", "hi", "kn"
}

potem wszystkie języki zaczęły działać

Lokesh Tiwari
źródło
3
TO NIE DZIAŁA
Krunal Shah
Czy to naprawdę potrzebne?
JCarlosR
1
@JCarlosR yes. kiedy dodałem języki w pliku konfiguracyjnym, kod Udhaya zaczął działać
Lokesh Tiwari
3

Ci, którzy mają problem z wersją, wypróbuj ten kod.

public static void switchLocal(Context context, String lcode, Activity activity) {
        if (lcode.equalsIgnoreCase(""))
            return;
        Resources resources = context.getResources();
        Locale locale = new Locale(lcode);
        Locale.setDefault(locale);
        android.content.res.Configuration config = new 
        android.content.res.Configuration();
        config.locale = locale;
        resources.updateConfiguration(config, resources.getDisplayMetrics());
        //restart base activity 
        activity.finish();
        activity.startActivity(activity.getIntent());
    }
Wahab Khan Jadon
źródło
2

Przykładowy kod Udhay działa dobrze. Z wyjątkiem kwestii Sofiane Hassaini i Chiraga Solanki, w przypadku ponownego wejścia to nie działa. Próbuję wywołać kod Udhaya bez ponownego uruchamiania działania w onCreate (), przed super.onCreate (saveInstanceState) ;. Wtedy jest OK! Tylko mały problem, ciągi menu nadal nie zmieniły się na ustawione Locale.

    public void setLocale(String lang) { //call this in onCreate()
      Locale 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); 
      //finish();
    } 
Rybak
źródło
ten sam problem z ciągami menu. Czy rozwiązujesz problem?
AlexS
@AlexS, nie znalazłem sposobu, aby rozwiązać problem w ciągu menu. Ale okazało się, że opuszcza aplikację, a następnie ponownie wprowadza, ciągi menu można normalnie zmienić na nowe ustawienia regionalne.
Fisher
masz na myśli Intent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?
AlexS
2
@AlexS, nie! dodanie nowych Intent () i startActivity () może spowodować, że powrócą do języka domyślnego po ponownym uruchomieniu aplikacji. Chodzi mi o to, że jeśli użytkownicy wyjdą z aplikacji i ponownie wejdą do aplikacji, ciągi menu można zmienić na nowe ustawienia regionalne.
Fisher