Come cambiare la lingua dell'app quando l'utente seleziona la lingua?


106

Voglio che la mia app supporti tre lingue spagnolo, portoghese e inglese. E dai la possibilità di selezionare la lingua nell'app

1) 3 cartelle disegnabili drawable-es, drawable-pt, drawable.

2) 3 valori cartella valori-es, valori-pt, valori.Cambia i valori String.xml in base alle lingue.

Ho imageView per selezionare la lingua. Quando si fa clic su di esso si apre il menu che consiste nell'opzione inglese, spagnolo, portoghese.

Ho impostato le impostazioni locali all'interno dell'app sulla selezione delle opzioni con questo codice

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);
}

Ho dichiarato in Manifest- android: configChanges = "locale"

Funziona ma ha qualche problema.

Problema:-

1) Quando si seleziona la lingua, la schermata che consiste nell'immagine della selezione della lingua non cambia, ma cambiano le altre schermate.

2) Dopo la modifica dell'orientamento, l'app ripristina la lingua in base alle impostazioni locali del telefono.


1
Per il secondo problema prova ad aggiungere: android:configChanges="locale"per la tua attività all'interno di AndroidManifest.xml
Parth Doshi

ho già aggiunto ogni attività nel mio manifest.
mukesh

Puoi utilizzare la seguente libreria, che fornisce l'elenco delle lingue, la preferenza per la schermata delle impostazioni e sovrascrive la lingua nella tua applicazione: github.com/delight-im/Android-Languages
caw

Risposte:


172

È un estratto per la pagina web: http://android.programmerguru.com/android-localization-at-runtime/

È semplice cambiare la lingua della tua app dopo che l'utente la seleziona dall'elenco delle lingue. Avere un metodo come di seguito che accetti la lingua come stringa (come "en" per l'inglese, "ciao" per l'hindi), configurare la lingua per la tua app e aggiornare la tua attività corrente per riflettere il cambio di lingua. Le impostazioni internazionali applicate non verranno modificate finché non verranno nuovamente modificate manualmente.

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); 
} 

Assicurati di aver importato i seguenti pacchetti:

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; 

aggiungi nel manifesto all'attività android: configChanges = "locale | orientamento"


2
Si certo. Posso fornire l'estratto della pagina web. Dove devo fornire, per favore fatemelo sapere. Grazie.
Udhay

3
Assicurati di aggiungere finish () in modo da non avere due copie della tua attività nello stack di navigazione.
Joel Teply

6
finish()deve essere chiamato prima startActivity(refresh). In caso contrario, l'app potrebbe uscire invece di riavviare l'attività.
Mohammed Ali

10
Ciao, l'ho fatto, funziona, ma quando riavvio l'app torna alla lingua predefinita ..
Sofiane Hassaini

5
Configurazione config = nuova configurazione (newConfig); config.locale = locale; Nel mio caso ricevendo questo messaggio. locale deprecato nel livello API 25
Milon

9

Le buone soluzioni spiegate abbastanza bene qui. Ma eccone un'altra.

Crea la tua CustomContextWrapperestensione di classe ContextWrappere usala per modificare le impostazioni locali per l'applicazione completa. Ecco un GIST con l'utilizzo.

E quindi chiamare CustomContextWrappercon l'identificatore delle impostazioni locali salvato, ad esempio 'hi'per la lingua hindi nel metodo del ciclo di vita delle attività attachBaseContext. Utilizzo qui:

@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));
}

Grazie per il link si sta lavorando, ma non ho capito alcune cose, ho appena chiamato l' MyContextWrapper.warpin onAttachdi un solo frammento di mia app, ma la lingua è stato modificato per l'intera applicazione, ma i titoli di attività non sono state modificate, penso che è perché i titoli manifest hanno la precedenza, ma se chiamo lo stesso metodo nella onAttachBaseContexmia sottoclasse di applicazione anche i titoli delle attività cambiano nella lingua selezionata, ma poi le modifiche vengono applicate solo al frammento che ho chiamato nel metodo warp, perché è così ?
Abhinav Chauhan

@ AbhinavChauhan Non sono sicuro che questo sia vero. Devo controllare quello. Non ho mai affrontato questo problema quando ho implementato questa soluzione. Tuttavia, è passato molto tempo e potrebbero esserci alcuni cambiamenti nell'implementazione di Android per le versioni più recenti. In alternativa, prova alcune risposte più recenti su questo post.
sud007

Ho provato molte soluzioni ma nessuna di esse ha funzionato o forse le ho implementate in modo errato, che la tua classe funzioni bene con le attività, lo sto usando come warpmetodo nel onAttachframmento, in precedenza ho detto che dovevo solo farlo con il frammento di attività principale e la lingua cambiata in l'intera app è vera, ma per tutti gli altri frammenti la lingua cambia in inglese al cambio di configurazione, quindi onattachdevo inserire tutti i frammenti e invece di manifest ho impostato i titoli della barra delle azioni nel codice, ora l'app funziona come previsto. grazie
Abhinav Chauhan

Va bene! Sono sicuro che non devi farlo per ogni schermata, solo per la prima attività che viene avviata e solo all'interno della attachBaseContextfunzione. E questo lo fa per tutti gli schermi. Hai creato una "BaseActivity" per tutte le attività nella tua app?
sud007

No, stavo cercando di farlo nella mia sottoclasse di applicazioni pensando che verrà applicato all'intera applicazione, quindi a tutti i frammenti, ma risulta che il wrap()codice deve essere eseguito ad ogni modifica della configurazione, quindi l'ho inserito nel Attività astratta da cui si estendono tutte le altre attività, ora sta funzionando
Abhinav Chauhan

6

Dovresti rimuovere android:configChanges="locale"dal manifest, che causerà il ricaricamento dell'attività, o sostituire il onConfigurationChangedmetodo:

@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
}

La rimozione di android: configChanges = "locale" dal manifest non impedisce il riavvio dell'app. Verrà riavviato indipendentemente dal fatto che venga aggiunto o meno al manifest.
portfoliobuilder

Non sto dicendo che la rimozione di android: configChanges = "locale" da manifest impedisce il riavvio dell'app, sto dicendo esattamente il contrario. Ora, nel caso in cui abbiamo android: configChanges = "locale" nel manifest, era usato per impedire il ricaricamento dell'app nel momento in cui ho scritto questa risposta, non posso dire con certezza che sia il caso ora.
Frane Poljak

6

tutto il codice di @ Uday sopra è perfetto ma manca solo una cosa (configurazione predefinita in 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); 

}

Il mio non funzionava solo perché le lingue non erano menzionate nel file di configurazione (build.gradle)

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

dopo di che, tutte le lingue hanno iniziato a funzionare


3
NON FUNZIONA
Krunal Shah

È davvero necessario?
JCarlosR

1
@JCarlosR sì. quando ho aggiunto le lingue nel file di configurazione, il codice di Udhay ha iniziato a funzionare
Lokesh Tiwari

3

Coloro che ottengono il problema della versione provano questo codice ..

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());
    }

2

Il codice di esempio di Udhay funziona bene. Tranne la questione di Sofiane Hassaini e Chirag SolankI, per il rientro non funziona. Provo a chiamare il codice di Udhay senza riavviare l'attività in onCreate (), prima di super.onCreate (savedInstanceState) ;. Allora va bene! Solo un piccolo problema, le stringhe del menu non sono ancora cambiate nelle impostazioni internazionali.

    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();
    } 

stesso problema con le stringhe di menu. Risolvi il problema?
AlexS

@ AlexS, non ho trovato modi per risolvere il problema nella stringa del menu. Ma trovato per uscire dall'app e quindi rientrare, le stringhe del menu possono essere normalmente modificate nelle nuove impostazioni internazionali.
Fisher

intendi Intent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?
AlexS

2
@AlexS, No! aggiungendo il nuovo Intent () e startActivity () potrebbe tornare alla lingua predefinita quando si riavvia l'app. Quello che voglio dire è che se gli utenti escono dall'app e rientrano nell'app, le stringhe del menu possono essere modificate nella nuova Locale.
Fisher
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.