Cambia la lingua dell'app a livello di programmazione su Android


448

È possibile cambiare la lingua di un'app a livello di codice mentre si utilizzano ancora le risorse Android?

In caso contrario, è possibile richiedere una risorsa in una lingua specifica?

Vorrei consentire all'utente di cambiare la lingua dell'app dall'app.


4
È possibile utilizzare la seguente libreria, che fornisce l'elenco delle lingue, le preferenze per la schermata delle impostazioni e sovrascrive la lingua nell'applicazione: github.com/delight-im/Android-Languages
caw

@MarcoW. Sai se Android-Languages ​​funziona con Android 5.0 Lollipop?
neu242,

1
@ neu242 Sì, funziona su Android 5.0 senza problemi.
Caw

1
È possibile utilizzare la seguente libreria: github.com/zeugma-solutions/locale-helper-android
josue.0

1
@ josue.0 quella libreria è davvero la soluzione più pulita in circolazione per questo
amitavk,

Risposte:


376

È possibile. È possibile impostare le impostazioni internazionali. Tuttavia, non lo consiglierei. L'abbiamo provato nelle prime fasi, fondamentalmente sta combattendo il sistema.

Abbiamo lo stesso requisito per cambiare la lingua ma abbiamo deciso di accontentarci del fatto che l'interfaccia utente dovrebbe essere uguale all'interfaccia del telefono. Funzionava tramite l'impostazione delle impostazioni locali ma era troppo difettoso. E devi impostarlo ogni volta che entri in attività (ogni attività) dalla mia esperienza. ecco un codice se hai ancora bisogno di questo (di nuovo, non lo consiglio)

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

Se si dispone di contenuti specifici della lingua, è possibile modificare tale base sull'impostazione.


aggiornamento il 26 marzo 2020

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

329
Non riesco a credere che Android lo renda così difficile. Non vedo davvero perché ci dovrebbe essere un'associazione STRICT tra le impostazioni internazionali del telefono e quelle dell'applicazione. Ho sempre il mio telefono usando la lingua inglese anche se non sono un madrelingua inglese. Il motivo è che le parole semi-tecniche tradotte diventano troppo strane nella mia lingua, quindi l'inglese è molto più semplice. Mi rende anche più facile seguire i consigli della Rete. Ma ciò non significa che voglio che OGNI app sul mio telefono usi l'inglese (anche se è perfettamente ok che è l'impostazione predefinita). Voglio poter scegliere !!!
Pietro,

9
Oh, sembra che sia stato introdotto il livello API 17 Context.createConfigurationContext(), che può essere utilizzato per avvolgere il contesto predefinito con una configurazione specifica della locale e quindi richiamarlo getResourcessenza dover aggiornare la configurazione sugli oggetti risorse stessi.
JAB

8
Devi inserirlo in onCreate () di ogni attività. In caso contrario, potrebbe essere ignorato dal sistema, ad esempio quando si trasforma il dispositivo in orizzontale e l'attività viene ricreata con una nuova configurazione (fornita dal sistema).
Zsolt Safrany,

14
Nel caso in cui imposti una locale RTL come "ar" e desideri che anche le tue cartelle di risorse -ldrtl funzionino, allora chiama anche conf.setLayoutDirection (locale);
Zsolt Safrany,

3
@ZsoltSafrany - Invece di aggiungere una chiamata a conf.setLayoutDirection(locale), puoi sostituirla conf.locale = new Locale(...))con conf.setLocale(new Locale(...)). Chiamerà internamente setLayoutDirection.
Ted Hopp,

180

Questo codice funziona davvero:

fa = persiano, en = inglese

Inserisci il tuo codice lingua in languageToLoadvariabile:

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

2
Voglio cambiare le impostazioni locali in fase di esecuzione, nel tuo codice, hai inserito il codice prima del metodo setContentView (). Quindi il tuo codice non è utile per me, quindi Come cambiare la lingua in fase di esecuzione, Nella mia applicazione, ci sono due pulsanti di
opzione

2
@Buffalo, è solo il secondo argomento per il Resources.updateConfigurationmetodo. Ho indentato il codice per renderlo più chiaro.
Cecologia

5
Questo funziona bene per tutte le attività dopo aver impostato l'attività di lancio. Tuttavia, il titolo della barra delle azioni sembra inalterato e continua a mostrare la lingua predefinita. Qualche idea su cosa avrei potuto perdere?
AndroidMechanic - Viral Patel,

8
Config.locale è obsoleto
Zoe

2
anziché "config.locale = locale;" usa "if (Build.VERSION.SDK_INT> = 17) {config.setLocale (locale);} else {config.locale = locale;}
roghayeh hosseini

36

Stavo cercando un modo per cambiare la lingua del sistema a livello di codice. Mentre comprendo appieno che un'applicazione normale non dovrebbe mai farlo e invece:

  • l'utente dovrebbe essere puntato (attraverso un intento) alle impostazioni di sistema per modificarlo manualmente
  • l'applicazione dovrebbe gestire la sua localizzazione da sola, proprio come descritto nella risposta di Alex

c'era la necessità di cambiare davvero la lingua del sistema in modo programmatico.

Questa è un'API non documentata e pertanto non deve essere utilizzata per applicazioni di mercato / utenti finali!

Comunque ecco la soluzione che ho trovato:

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

2
dare eccezione invocazione target eccezione
Ravi

1
Bene dipende da dove viene lanciata invocationTargetException. Quindi dovresti conoscere la classe che è stata modificata.
Icyerasor,

1
@ Rat-a-tat-a-tat Ratatouille, a partire da Android 4.2, android.permission.CHANGE_CONFIGURATIONpuò essere concesso solo dall'app firmata con la chiave di esecuzione.
Yeung,

3
Ho inserito la mia app in / system / priv-app per aggirare il problema di Android 6.0. Dettagli qui .
weiyin

1
@Ravi Ho dovuto spostare la mia app da / system / app a / system / priv-app per farlo funzionare
alexislg

31

Se vuoi mantenere la lingua cambiata su tutta la tua app devi fare due cose.

Innanzitutto, crea un'attività di base e estendi tutte le tue attività da questo:

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

Si noti che salvo la nuova lingua in un riferimento condiviso.

In secondo luogo, crea un'estensione dell'applicazione come questa:

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

Nota che getLocale () è lo stesso di cui sopra.

È tutto! Spero che questo possa aiutare qualcuno.


L'attività dell'app è un'attività primaria, come una MainActivity? per esempio posso risolverlo in setLocale () nel mio metodo onCreate ()?
Morozov,

L'app è un'estensione dell'applicazione, non è un'attività. Non capisco di cosa hai bisogno, scusa. Forse puoi provare a spiegarmi di nuovo :)
Daniel S.

1
per quei rumori Android come me, vieni qui per sapere cos'è Applicatione come si usa. mobomo.com/2011/05/how-to-use-application-object-of-android
Siwei Shen 申思维

2
configuration.locateè deprecato, setLocale richiede API 17+ e updateConfiguration è deprecato
Zoe

19

Secondo questo articolo . Dovrai scaricare il LocaleHelper.javariferimento in quell'articolo.

  1. Crea una MyApplicationclasse che si estenderàApplication
  2. Sostituisci attachBaseContext()per aggiornare la lingua.
  3. Registra questa classe in manifest.

    public class MyApplication extends Application {
       @Override
       protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
       }
    }
    
    <application
         android:name="com.package.MyApplication"
         .../>
  4. Crea BaseActivitye sostituisci onAttach()per aggiornare la lingua. Necessario per Android 6+

    public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
  5. Fai estendere tutte le attività sulla tua app 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;
    }
    }

non riesco a utilizzare super.attachBaseContext (LocaleHelper.onAttach (newBase)) perché sto già utilizzando super.attachBaseContext (CalligraphyContextWrapper.wrap (newBase))
Rasel

1
puoi avvolgerne uno con l'altro. super.attachBaseContext (CalligraphyContextWrapper.wrap (LocaleHelper.onAttach (newBase)))
Yeahia2508

15

Ho appena aggiunto un pezzo in più che mi ha fatto inciampare.

Mentre le altre risposte funzionano bene con "de" per esempio

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

Quanto sopra non funzionerà ad esempio con le "fr_BE"impostazioni locali, quindi userebbe la values-fr-rBEcartella o simili.

Per funzionare è necessario il seguente leggero cambiamento "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());

1
se si desidera applicare la modifica delle impostazioni locali alla chiamata di attività attualmente apertaactivity.recreate()
A Kra

So di essere in ritardo alla festa, ma il nuovo Locale (lang, country) era tutto ciò di cui avevo bisogno!
Jacob Holloway,

activity.recreate () come funziona o se lo chiamiamo allora String lang = "fr"; String country = "BE"; non sovrascriverà mai il tempo che
passerà

Che ne dici di usare android.content.res.Configuration conf = res.getConfiguration();invece di creare una nuova Configurationistanza? C'è qualche vantaggio nell'usarne uno nuovo?
Bianca Daniciuc,

14

Sono cambiato per la lingua tedesca per l'avvio della mia app stessa.

Ecco il mio codice corretto. Chiunque voglia usarlo per me .. (Come cambiare la lingua in Android a livello di codice)

il mio codice:

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

1
@harikrishnan Non funziona per me e la tastiera non cambia nella lingua specificata. Come hai dichiarato l'attività in manifest?
Avadhani,

13

So che è tardi per rispondere, ma ho trovato questo articolo qui . Il che spiega molto bene l'intero processo e ti fornisce un codice ben strutturato.

Classe di supporto locale:

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

È necessario sovrascrivere attachBaseContext e chiamare LocaleHelper.onAttach () per inizializzare le impostazioni locali nella propria applicazione.

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

Tutto quello che devi fare è aggiungere

LocaleHelper.onCreate(this, "en");

ovunque tu voglia cambiare le impostazioni locali.


LocaleHelper è una classe dall'articolo. Qualsiasi collegamento ha il rischio di essere rimosso. Aggiungi il codice nella tua risposta.
Zoe,

Non voglio riavviare la mia app perché l'app sta eseguendo attività come la schermata di registrazione. quindi senza riavviare l'app c'è una soluzione per Android 7.0
PriyankaChauhan

1
@PriyankaChauhan Penso che l'articolo tratta questo caso: hai due opzioni per aggiornare il layout attualmente visibile: in primo luogo , puoi semplicemente aggiornare il testo o qualsiasi altra risorsa dipendente dalla lingua una per una.
Maksim Turaev,

grazie per aver aggiunto il nuovo createConfigurationContext, che è stato utile
jacoballenwood

1
onCreate o onAttach da chiamare?
vanste25

12

Crea una classe Estende Applicatione crea un metodo statico. Quindi puoi chiamare questo metodo in tutte le attività prima 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);
}

}

Utilizzo nelle attività:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyApp.setLocaleFa(MainActivity.this);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
}

10

Per Android 7.0 Nougat (e versioni precedenti) segui questo articolo:

Cambia lingua a livello di programmazione su Android

Vecchia risposta
Include supporto 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());
}

1
updateConfiguration è obsoleto. Il link è utile, per favore aggiungilo nella tua risposta. (Solo le risposte al link non sono buone, poiché il link potrebbe essere rimosso. Se ciò accade, questa risposta è inutile)
Zoe

8

L'unica soluzione che funziona completamente per me è una combinazione del codice di Alex Volovoy con il meccanismo di riavvio dell'applicazione:

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

2
dopo il cambio di locale puoi anche chiamareactivity.recreate()
Per Kra

1
Non voglio riavviare la mia app perché l'app sta eseguendo attività come la schermata di registrazione. quindi senza riavviare l'app c'è una soluzione per Android 7.0
PriyankaChauhan

7

Stavo affrontando lo stesso problema. Su GitHub ho trovato la libreria Android-LocalizationActivity .

Questa libreria semplifica la modifica della lingua della tua app in fase di runtime, come puoi vedere nell'esempio di codice seguente. Un progetto di esempio che include il codice di esempio riportato di seguito e ulteriori informazioni sono disponibili nella pagina github.

LocalizationActivity estende AppCompatActivity, quindi puoi usarlo anche quando stai usando i frammenti.

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

7

Tempo per un aggiornamento dovuto.

Prima di tutto, l'elenco obsoleto con l'API in cui è stato deprecato:

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

La cosa a cui non è stata data risposta a una domanda recente è l'utilizzo del nuovo metodo .

createConfigurationContext è il nuovo metodo per updateConfiguration.

Alcuni l'hanno usato da solo in questo modo:

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

... ma non funziona. Perché? Il metodo restituisce un contesto, che viene quindi utilizzato per gestire le traduzioni di Strings.xml e altre risorse localizzate (immagini, layout, qualunque cosa).

L'uso corretto è così:

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

Se lo hai appena copiato e incollato nel tuo IDE, potresti visualizzare un avviso che l'API richiede il targeting dell'API 17 o successiva. Questo può essere aggirato inserendolo in un metodo e aggiungendo l'annotazione@TargetApi(17)

Ma aspetta. E le API più vecchie?

È necessario creare un altro metodo utilizzando updateConfiguration senza l'annotazione 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);

Non è necessario restituire un contesto qui.

Ora, gestirli può essere difficile. In API 17+ è necessario il contesto creato (o le risorse dal contesto creato) per ottenere le risorse appropriate in base alla localizzazione. come lo gestisci?

Bene, questo è il modo in cui lo faccio:

/**
 * 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;
}

Questo codice funziona con un metodo che effettua chiamate al metodo appropriato in base all'API. Questo è qualcosa che ho fatto con molte chiamate deprecate diverse (incluso Html.fromHtml). Hai un metodo che accetta gli argomenti necessari, che poi lo divide in uno dei due (o tre o più) metodi e restituisce il risultato appropriato in base al livello API. È flessibile poiché non è necessario controllare più volte, il metodo "entry" lo fa per te. Il metodo di immissione qui èsetLanguage

LEGGERE QUESTO PRIMA DI USARLO

È necessario utilizzare il contesto restituito quando si ottengono risorse. Perché? Ho visto altre risposte qui che usano createConfigurationContext e non usano il contesto che restituisce. Per farlo funzionare in questo modo, deve essere chiamato updateConfiguration. Che è deprecato. Utilizzare il contesto restituito dal metodo per ottenere risorse.

Esempio di utilizzo :

Costruttore o da qualche parte simile:

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)

E poi, ovunque tu voglia ottenere risorse che fai:

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

L'uso di qualsiasi altro contesto (in teoria) romperà questo.

AFAIK devi ancora utilizzare un contesto di attività per mostrare finestre di dialogo o Brindisi. per questo puoi usare un'istanza di un'attività (se sei fuori)


E infine, utilizzare recreate()l'attività per aggiornare il contenuto. Scorciatoia per non dover creare un intento di aggiornamento.


1
Alcuni potrebbero chiedersi se il contesto creato costerà la tua memoria. Tuttavia, secondo la documentazione ufficiale di Android: "Ogni chiamata a questo metodo restituisce una nuova istanza di un oggetto Context; gli oggetti Context non sono condivisi, tuttavia lo stato comune (ClassLoader, altre risorse per la stessa configurazione) può essere quindi il contesto stesso può essere equamente leggero ". Quindi penso che Android si aspetti che tu usi un oggetto di contesto separato per le cose locali.
Sira Lam,

7

Se scrivi

android:configChanges="locale"

In ogni attività (nel file manifest), non è necessario impostarlo ogni volta che si entra Activity.


11
Se è nel manifest, in che modo questo costituisce un cambiamento in fase di esecuzione, che sembrava essere ciò che l'OP voleva?
user316117

1
@ user316117 Indica ad Android che l'app gestirà internamente tutte le questioni relative alla configurazione della locale, non che la locale sia statica. Non sono sicuro se ciò impedirebbe ad Android di impostare le impostazioni locali quando si cambia tra le attività, poiché ho visto configChangesusato solo per un hack per preservare lo stato di attività su rotazioni / ecc.
JAB

come impostare la lingua solo in inglese specifico?
Kaveesh Kanwal,

1
... finché Android non uccide la tua attività perché ha bisogno di più RAM
Louis CAD

@Brijesh Se abbiamo cambiato la lingua dell'app allora se abbiamo qualche opzione di ricerca all'interno dell'app, e se cerchiamo in quella allora, come l'app mostrerà i dati, dovremmo sviluppare un database diverso per ogni lingua o qualche impostazione del codice Android è lì che app potrebbe mostrare i dati in base alla ricerca?
Vishwa Pratap,

5
Locale locale = new Locale("en");
Locale.setDefault(locale);

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

Aggiornamento importante:

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

Si noti che su SDK> = 21, è necessario chiamare "Resources.updateConfiguration ()" , altrimenti le risorse non verranno aggiornate.


updateConfiguration è obsoleto. AFAIK usi createConfigurationContext e applichi il contesto che hai ad esso ( Context ctx = createConfigurationContext(args);e ottieni risorse da quello
Zoe

So che è deprecato. Ma comunque non conosco alcuna soluzione che possa funzionare su Android 5 e versioni successive.
Максим Петлюк,

Quindi chiaramente non hai controllato il javadoc. chiami il contesto creato da createConfigurationContext
Zoe

Ok, comunque dovremmo chiamare updateConfiguration (), giusto?
Максим Петлюк,

1
Non utilizzare la chiamata obsoleta. Significa nessuna chiamata updateConfiguration
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); 
 }

5
non c'è bisogno di iniziare nuove attività, basta aggiornare effettivamenteactivity.recreate()
A Kra

4

Locale configurationdovrebbe essere impostato in ciascuno activityprima di impostare il contenuto -this.setContentView(R.layout.main);


Ma cosa succede se si desidera attivarlo al volo, dopo che setContentView () è stato chiamato?
IgorGanapolsky,

2
dopo il cambio di locale puoi anche chiamareactivity.recreate()
A Kra

4

Inizialmente creare multi string.xml per lingue diverse; quindi utilizzare questo blocco di codice nel onCreate()metodo:

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

Grazie, questo codice funziona alla grande, ho testato su Android 5.xe 6.x senza problemi
innovaciones

4

Ecco un po 'di codice che funziona per me:

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

Fonte: qui


3

Nessuna delle soluzioni elencate qui mi ha aiutato.

La lingua non è stata attivata su Android> = 7.0 se AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE_NIGHT_YES)

Questo LocaleUtils funziona bene: 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());
    }
}
}

Aggiunto questo codice all'applicazione

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

Codice in attività

public class BaseActivity extends AppCompatActivity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}

2

La risposta di Alex Volovoy funziona solo per me se è nel metodo onCreate dell'attività.

La risposta che funziona in tutti i metodi è in un altro thread

Cambia lingua a livello di programmazione su Android

Ecco l'adattamento del codice



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

Spero che sia d'aiuto.


19
Hai detto "La risposta che funziona in tutti i metodi è in un altro thread" ma il tuo link punta a QUESTO thread! "
user316117

1
config.locale è deprecato
Zoe

2
risposta ricorsiva, possibile di StackOverflow
tamtom

2

Tieni presente che questa soluzione updateConfiguration non funzionerà più con la versione Android M in arrivo tra qualche settimana. Il nuovo modo per farlo ora sta usando il applyOverrideConfigurationmetodo da ContextThemeWrapper vedi documento API

Puoi trovare la mia soluzione completa qui da quando ho affrontato il problema da solo: https://stackoverflow.com/a/31787201/2776572


Provo il codice updateConfiguration su Android 6.0.1 e funziona bene, non so se Google ha risolto questo problema, ma posso usarlo senza problemi
innovaciones

1
I metodi obsoleti di @innovaciones sono in circolazione da un po '. Alla fine, verrà rimosso. Ci vuole molto tempo, ma è meglio passare alle nuove API il più presto possibile per evitare problemi lungo la linea
Zoe

1

Ci sono alcuni passaggi che è necessario implementare

Innanzitutto, è necessario modificare le impostazioni internazionali della configurazione

Resources resources = context.getResources();

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

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

In secondo luogo, se si desidera che le modifiche vengano applicate direttamente al layout visibile, è possibile aggiornare direttamente le visualizzazioni oppure chiamare semplicemente activity.recreate () per riavviare l'attività corrente.

Inoltre, è necessario mantenere le modifiche perché dopo che l'utente ha chiuso l'applicazione, si perde la modifica della lingua.

Ho spiegato una soluzione più dettagliata sul mio post sul blog Cambia lingua a livello di codice in Android

Fondamentalmente, devi solo chiamare LocaleHelper.onCreate () sulla tua classe di applicazione e se vuoi cambiare le impostazioni locali al volo puoi chiamare LocaleHelper.setLocale ()


@LunarWatcher Sì, se si controlla effettivamente il codice su github o gist, è già gestito.
Gunhan,

1

Funziona quando premo il pulsante per cambiare la lingua del testo del mio TextView. (Strings.xml nella cartella valori-de)

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

1

Aggiungi la classe 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;
}
}

In attività o frammento

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

Ora SetText su ogni testo

TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));

0

simile alla risposta accettata ma alla versione 2017 e al riavvio aggiunto (senza riavvio, a volte l'attività successiva rende ancora l'inglese):

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

1) usa finish () invece 2) per riavviare l'app puoi usare activity.recreate()3) il contesto restituito penso che debba essere usato per ottenere le risorse
Zoe

Non voglio riavviare la mia app perché l'app sta eseguendo attività come la schermata di registrazione. quindi senza riavviare l'app c'è una soluzione per Android 7.0
PriyankaChauhan

0

Per prima cosa crei i valori del nome della directory- "Nome della lingua" come hindi che scrivi "ciao" e copia lo stesso nome del file di stringa in questa directory e modifica il valore non cambia il parametro dopo aver impostato il codice sotto nella tua azione come il pulsante ecc ....

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

1
conf.localeè deprecato
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());

}

1
Non voglio riavviare la mia app perché l'app sta eseguendo attività come la schermata di registrazione. quindi senza riavviare l'app c'è una soluzione per Android 7.0
PriyankaChauhan

sì, su 6.0 funziona bene per me, senza riavviare l'app, la lingua è cambiata, ma non ho testato su 7.0
Adeeb karim,

0

Nell'esempio impostiamo la lingua inglese:

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

Ricorda che funziona solo se la lingua si trova anche nel sistema del dispositivo, non solo nell'applicazione


0

Per il supporto arabo / RTL

  1. È necessario aggiornare le impostazioni della lingua tramite - attachBaseContext ()
  2. Per Android versione N e successive è necessario utilizzare createConfigurationContext () e updateConfiguration () - altrimenti il ​​layout RTL non funziona correttamente

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

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.