¿Cómo cambiar el idioma de la aplicación cuando el usuario selecciona el idioma?

106

Quiero que mi aplicación admita tres idiomas: español, portugués e inglés. Y dar la opción de seleccionar el idioma en la aplicación.

1) 3 carpetas dibujables drawable-es, drawable-pt, drawable.

2) Carpeta de 3 valores valores-es, valores-pt, valores. Cambiar los valores String.xml según los idiomas.

Tengo imageView para seleccionar el idioma. Al hacer clic en él, se abre el menú que consta de la opción Inglés, español, portugués.

Configuré Locale dentro de la aplicación en la selección de opciones con este código

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

He declarado en Manifest- android: configChanges = "locale"

Funciona pero tiene algún problema.

Problema:-

1) Cuando se selecciona el idioma, la pantalla que consta de la imagen de la selección del idioma no cambia, pero sí cambian otras pantallas.

2) Después de cambiar la orientación, la aplicación restaura el idioma de acuerdo con la configuración regional del teléfono.

mukesh
fuente
1
Para el segundo problema, intente agregar: android:configChanges="locale"para su actividad dentro de AndroidManifest.xml
Parth Doshi
Ya agregué todas las actividades en mi manifiesto.
mukesh
Puede usar la siguiente biblioteca, que proporciona la lista de idiomas, la preferencia para la pantalla de configuración y anula el idioma en su aplicación: github.com/delight-im/Android-Languages
caw

Respuestas:

172

Es un extracto de la página web: http://android.programmerguru.com/android-localization-at-runtime/

Es simple cambiar el idioma de su aplicación cuando el usuario la selecciona de la lista de idiomas. Tenga un método como el siguiente que acepta la configuración regional como String (como 'en' para inglés, 'hola' para hindi), configure la configuración regional para su aplicación y actualice su actividad actual para reflejar el cambio en el idioma. La configuración regional que aplicó no se cambiará hasta que la vuelva a cambiar 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); 
} 

Asegúrese de haber importado los siguientes paquetes:

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; 

agregar en el manifiesto a la actividad android: configChanges = "locale | orientación"

Udhay
fuente
2
Si seguro. Puedo proporcionar el extracto de la página web. Donde necesito proporcionar, hágamelo saber. Gracias.
Udhay
3
Asegúrese de agregar finish () para que no tenga dos copias de su actividad en la pila de navegación.
Joel Teply
6
finish()necesita ser llamado antes startActivity(refresh). De lo contrario, la aplicación puede cerrarse en lugar de reiniciar la actividad.
Mohammed Ali
10
Hola, lo hice, funciona, pero cuando reinicio la aplicación, vuelve al idioma predeterminado ..
Sofiane Hassaini
5
Configuración config = nueva configuración (newConfig); config.locale = locale; En mi caso recibiendo este mensaje. configuración regional obsoleta en el nivel de API 25
Milon
9

Las buenas soluciones se explican bastante bien aquí. Pero aquí hay uno más.

Cree su propia CustomContextWrapperextensión de clase ContextWrappery utilícela para cambiar la configuración regional para la aplicación completa. Aquí hay un GIST con uso.

Y luego llame al CustomContextWrappercon el identificador de configuración regional guardado, 'hi'por ejemplo, para el idioma hindi en el método del ciclo de vida de la actividad attachBaseContext. Uso aquí:

@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
fuente
Gracias por el enlace que está trabajando pero que no entendía algunas cosas, acabo de llamar a la MyContextWrapper.warpen onAttachde un solo fragmento de mi aplicación, pero el idioma se cambió para toda la aplicación, pero los títulos de actividad no ha cambiado, creo que es porque los títulos del manifiesto tienen prioridad, pero si llamo al mismo método en onAttachBaseContexmi subclase de aplicación, los títulos de la actividad también cambian al idioma seleccionado, pero luego los cambios solo se aplican al fragmento que llamé en el método warp, ¿por qué ?
Abhinav Chauhan
@AbhinavChauhan No estoy seguro de que esto sea cierto. Necesito comprobar ese. Nunca me he enfrentado a este problema cuando implementé esta solución. Sin embargo, ha pasado mucho tiempo y puede haber algunos cambios en la implementación de Android para las versiones más nuevas. Alternativamente, pruebe algunas de las respuestas más recientes en esta publicación.
sud007
Intenté muchas soluciones pero ninguna de ellas funcionó o tal vez las implementé incorrectamente, puede que su clase funcione bien con actividades, lo estoy usando warpen onAttachel fragmento, anteriormente dije que solo necesitaba hacerlo con el fragmento de actividad principal y el idioma cambiado en toda la aplicación es cierto, pero para todos los demás fragmentos, el idioma cambia al inglés en el cambio de configuración, por lo que necesito onattachingresar todos los fragmentos y, en lugar de manifiesto, configuré los títulos de la barra de acciones en el código, ahora la aplicación funciona como se esperaba. gracias
Abhinav Chauhan
¡Bueno! Estoy seguro de que no tiene que hacer esto para cada pantalla, solo la primera actividad que se inicia y solo dentro de la attachBaseContextfunción. Y eso lo hace para todas las pantallas. ¿Ha creado una "BaseActivity" para todas las actividades en su aplicación?
sud007
No, estaba tratando de hacerlo en mi subclase de aplicación pensando que se aplicará a toda la aplicación, luego a todos los fragmentos, pero resulta que el wrap()código debe ejecutarse en cada cambio de configuración, así que lo puse en el Actividad abstracta de la que se extienden todas las demás actividades, ahora está funcionando
Abhinav Chauhan
6

Debes eliminar android:configChanges="locale"del manifiesto, lo que provocará que la actividad se recargue, o anular el onConfigurationChangedmétodo:

@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
fuente
Eliminar android: configChanges = "locale" del manifiesto no evita que la aplicación se reinicie. Se reiniciará independientemente de si se agrega al manifiesto o no.
portfoliobuilder
No estoy diciendo que eliminar android: configChanges = "locale" del manifiesto evita que la aplicación se reinicie, estoy diciendo exactamente lo contrario. Ahora, para el caso en el que tenemos android: configChanges = "locale" en el manifiesto, solía evitar que la aplicación se recargara en el momento en que escribí esta respuesta, no puedo decir con certeza que sea el caso ahora.
Frane Poljak
6

todo el código anterior de @ Uday es perfecto, pero solo falta una cosa (configuración predeterminada en 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); 

}

El mío no funcionaba solo porque los idiomas no se mencionaron en el archivo de configuración (build.gradle)

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

después de eso, todos los idiomas comenzaron a funcionar

Lokesh Tiwari
fuente
3
NO FUNCIONA
Krunal Shah
¿Es realmente necesario?
JCarlosR
1
@JCarlosR sí. cuando agregué idiomas en el archivo de configuración, el código de Udhay comenzó a ejecutarse
Lokesh Tiwari
3

Aquellos que obtienen el problema de la versión prueban este código.

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
fuente
2

El código de muestra de Udhay funciona bien. Salvo la pregunta de Sofiane Hassaini y Chirag SolankI, para el reingreso, no funciona. Intento llamar al código de Udhay sin reiniciar la actividad en onCreate (), antes de super.onCreate (SavedInstanceState) ;. ¡Entonces está bien! Solo un pequeño problema, las cadenas del menú aún no han cambiado a la configuración regional establecida.

    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();
    } 
Pescador
fuente
mismo problema con las cadenas de menú. ¿Resuelve el problema?
AlexS
@AlexS, no encontré formas de solucionar el problema en la cadena del menú. Pero si sale de la aplicación y luego vuelve a ingresar, las cadenas del menú normalmente se pueden cambiar a la nueva configuración regional.
Fisher
te refieres Intent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?
AlexS
2
@AlexS, ¡No! agregar el nuevo Intent () y startActivity () puede hacer que vuelva al idioma predeterminado cuando reinicie la aplicación. Lo que quiero decir es que si los usuarios salen de la aplicación y vuelven a ingresar a la aplicación, las cadenas del menú se pueden cambiar a la nueva configuración regional.
Fisher