Cambiar el idioma de la aplicación mediante programación en Android

448

¿Es posible cambiar el idioma de una aplicación mediante programación mientras sigo utilizando recursos de Android?

Si no, ¿es posible solicitar un recurso en un idioma específico?

Me gustaría permitir que el usuario cambie el idioma de la aplicación desde la aplicación.

hpique
fuente
44
Puede usar la siguiente biblioteca, que proporciona la lista de idiomas, la preferencia para la pantalla de configuración y anula el idioma de su aplicación: github.com/delight-im/Android-Languages
caw
@MarcoW. ¿Sabes si Android-Languages ​​funciona con Android 5.0 Lollipop?
neu242
1
@ neu242 Sí, se ejecuta en Android 5.0 sin ningún problema.
caw
1
Puede usar la siguiente biblioteca: github.com/zeugma-solutions/locale-helper-android
josue.0
1
@ josue.0 esa biblioteca es realmente la solución más limpia para esto
amitavk

Respuestas:

376

Es posible. Puede establecer la configuración regional. Sin embargo, no recomendaría eso. Lo hemos intentado en las primeras etapas, básicamente está luchando contra el sistema.

Tenemos el mismo requisito para cambiar el idioma, pero decidimos conformarnos con el hecho de que la interfaz de usuario debe ser la misma que la del teléfono. Funcionaba a través de la configuración regional, pero tenía demasiados errores. Y tiene que configurarlo cada vez que ingresa a la actividad (cada actividad) desde mi experiencia. aquí hay un código si aún necesita esto (nuevamente, no lo recomiendo)

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

Si tiene contenido específico de idioma, puede cambiar esa base en la configuración.


actualización el 26 de marzo de 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());
    }
Alex Volovoy
fuente
328
No puedo creer que Android lo haga tan difícil. Realmente no veo por qué debería haber una asociación ESTRICTA entre la ubicación del teléfono y la de la aplicación. Siempre tengo mi teléfono en inglés, aunque no soy hablante nativo de inglés. La razón es que las palabras semi-técnicas traducidas se vuelven demasiado raras en mi propio idioma, por lo que el inglés es mucho más fácil. También me facilita seguir los consejos de la red. Pero eso no significa que quiera que CADA aplicación en mi teléfono use inglés (aunque está perfectamente bien, eso es lo predeterminado). ¡Quiero poder elegir!
Peter
99
Ah, parece Context.createConfigurationContext()que se introdujo el nivel 17 de API , que se puede usar para ajustar el contexto predeterminado con la configuración específica de la configuración regional y luego invocarlo getResourcessin tener que actualizar la configuración en los propios objetos de recursos.
JAB
8
Debe poner esto en onCreate () de cada actividad. De lo contrario, puede ser anulado por el sistema, por ejemplo, cuando gira su dispositivo a horizontal y su actividad se recrea con una nueva configuración (proporcionada por el sistema).
Zsolt Safrany
13
En caso de que establezca una configuración regional RTL como "ar" y desee que sus carpetas de recursos -ldrtl funcionen también, también llame a conf.setLayoutDirection (configuración regional);
Zsolt Safrany
3
@ZsoltSafrany: en lugar de agregar una llamada conf.setLayoutDirection(locale), puede reemplazar conf.locale = new Locale(...))con conf.setLocale(new Locale(...)). Se llamará internamente setLayoutDirection.
Ted Hopp
179

Este código realmente funciona:

fa = persa, en = inglés

Ingrese su código de idioma en languageToLoadvariable:

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
fuente
2
Quiero cambiar la configuración regional en tiempo de ejecución, en su código, coloque su código antes del método setContentView (). Entonces, su código no es útil para mí. Entonces, ¿cómo cambiar el idioma en tiempo de ejecución? En mi aplicación, hay dos botones de opción, para inglés y otro para árabe,
Dwivedi Ji
2
@Buffalo, es solo el segundo argumento para el Resources.updateConfigurationmétodo. He sangrado el código para hacerlo más claro.
Czechnology
55
Esto funciona bien para todas las actividades al establecerse en la actividad de lanzamiento. Pero, el título de la barra de acción parece no verse afectado y aún continúa mostrando el idioma predeterminado. ¿Alguna idea de lo que me podría haber perdido?
AndroidMechanic - Viral Patel
8
Config.locale está en desuso
Zoe
2
en lugar de "config.locale = locale;" use "if (Build.VERSION.SDK_INT> = 17) {config.setLocale (locale);} else {config.locale = locale;}
roghayeh hosseini
36

Estaba buscando una manera de cambiar el lenguaje del sistema mediante programación. Si bien entiendo completamente que una aplicación normal nunca debería hacer eso y en su lugar tampoco:

  • el usuario debe señalar (mediante un intento) a la configuración del sistema para cambiarlo manualmente
  • la aplicación debe manejar su localización por sí sola tal como se describe en la respuesta de Alex

era necesario cambiar realmente el lenguaje del sistema mediante programación.

¡Esta es una API no documentada y, por lo tanto, no debe usarse para aplicaciones de mercado / usuario final!

De todos modos, aquí está la solución que encontré:

  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
fuente
2
dar excepción invocación objetivo de excepción
Ravi
1
Bueno, depende de dónde se arroje la invocaciónTargetException. Entonces deberías saber la clase que fue cambiada.
icyerasor
1
@ Rat-a-tat-a-tat Ratatouille, a partir de Android 4.2 android.permission.CHANGE_CONFIGURATION, solo se puede otorgar mediante una aplicación firmada con la tecla de ejecución.
Yeung
3
Puse mi aplicación en / system / priv-app para solucionar el problema de Android 6.0. Detalles aquí .
weiyin
1
@Ravi Tuve que mover mi aplicación de / system / app a / system / priv-app para que funcionara
alexislg
31

Si desea mantener el idioma cambiado en toda su aplicación, debe hacer dos cosas.

Primero, cree una Actividad base y haga que todas sus actividades se extiendan a partir de esto:

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

Tenga en cuenta que guardo el nuevo idioma en una referencia compartida.

En segundo lugar, cree una extensión de aplicación como esta:

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

Tenga en cuenta que getLocale () es el mismo que el anterior.

¡Eso es todo! Espero que esto pueda ayudar a alguien.

Daniel S.
fuente
¿La actividad de la aplicación es una actividad principal, como una actividad principal? Por ejemplo, ¿puedo resolver esto en setLocale () en mi método onCreate ()?
Morozov
La aplicación es una extensión de la aplicación, no es una actividad. No entiendo lo que necesitas, lo siento. Tal vez puedas intentar explicarme otra vez :)
Daniel S.
1
para aquellos novatos de Android como yo, ven aquí para aprender qué Applicationes y cómo usarlo. mobomo.com/2011/05/how-to-use-application-object-of-android
Siwei Shen 申思维
2
configuration.locateestá en desuso, setLocale requiere API 17+ y updateConfiguration está en desuso
Zoe
19

De acuerdo con este artículo . Deberá descargar la LocaleHelper.javareferencia en ese artículo.

  1. Crea una MyApplicationclase que se extiendaApplication
  2. Anular attachBaseContext()para actualizar el idioma.
  3. Registre esta clase en manifiesto.

    public class MyApplication extends Application {
       @Override
       protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
       }
    }
    
    <application
         android:name="com.package.MyApplication"
         .../>
  4. Crear BaseActivityy anular onAttach()para actualizar el idioma. Necesario para Android 6+

    public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
  5. Haga que todas las actividades en su aplicación se extiendan desde 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
fuente
no puedo usar super.attachBaseContext (LocaleHelper.onAttach (newBase)) porque ya estoy usando super.attachBaseContext (CalligraphyContextWrapper.wrap (newBase))
Rasel
1
Puedes envolver uno con el otro. super.attachBaseContext (CalligraphyContextWrapper.wrap (LocaleHelper.onAttach (newBase)))
Yeahia2508
15

Solo agregué una pieza extra que me hizo tropezar.

Mientras que las otras respuestas funcionan bien con "de" por ejemplo

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

Lo anterior no funcionará con, por ejemplo, la "fr_BE"configuración regional, por lo que usaría la values-fr-rBEcarpeta o similar.

Necesita el siguiente ligero cambio para trabajar con "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());
triggs
fuente
1
Si desea aplicar el cambio a la configuración regional actual de la llamada actividad abiertaactivity.recreate()
Para Kra
Sé que llego tarde a la fiesta, ¡pero el nuevo Locale (lang, country) era todo lo que necesitaba!
Jacob Holloway
activity.recreate () cómo funciona o si calificamos esto, entonces String lang = "fr"; String country = "BE"; nunca anulará cómo correrá el tiempo
Amitsharma
¿Qué pasa con el uso en android.content.res.Configuration conf = res.getConfiguration();lugar de crear una nueva Configurationinstancia? ¿Hay algún beneficio por usar uno nuevo?
Bianca Daniciuc
14

He cambiado el idioma alemán para que mi aplicación se inicie por sí misma.

Aquí está mi código correcto. Alguien quiere usar esto igual para mí .. (Cómo cambiar el idioma en Android mediante programación)

mi código:

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
fuente
1
@harikrishnan No funciona para mí y el teclado no cambia al idioma especificado. ¿Cómo ha declarado la actividad en manifiesto?
Avadhani Y
13

Sé que es tarde para responder, pero encontré este artículo aquí . Lo que explica muy bien todo el proceso y le proporciona un código bien estructurado.

Clase de ayuda local:

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

Debe anular attachBaseContext y llamar a LocaleHelper.onAttach () para inicializar la configuración regional en su aplicación.

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

Todo lo que tienes que hacer es agregar

LocaleHelper.onCreate(this, "en");

donde quiera cambiar la configuración regional.

Anirudh Sharma
fuente
LocaleHelper es una clase del artículo. Cualquier enlace tiene el riesgo de ser eliminado. Por favor agregue el código en su respuesta.
Zoe
No quiero reiniciar mi aplicación porque la aplicación está haciendo alguna tarea, como la pantalla de grabación. entonces, sin reiniciar la aplicación, ¿hay alguna solución para Android 7.0?
PriyankaChauhan
1
@PriyankaChauhan Creo que el artículo cubre este caso: tiene dos opciones para actualizar el diseño actualmente visible: Primero , puede actualizar el texto o cualquier otro recurso dependiente del idioma uno por uno.
Maksim Turaev
gracias por agregar el nuevo createConfigurationContext, eso fue útil
jacoballenwood
1
onCreate o onAttach para llamar?
vanste25
12

Crear una clase Extiende Applicationy crea un método estático. Entonces puede llamar a este método en todas las actividades anteriores 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);
}

}

Uso en actividades:

@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
fuente
10

Para Android 7.0 Nougat (y versiones inferiores) sigue este artículo:

Cambiar idioma de forma programada en Android

Respuesta anterior
Esto incluye soporte 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
fuente
1
updateConfiguration está en desuso. El enlace es útil, agréguelo a su respuesta. (Las respuestas de solo enlace no son buenas, ya que el enlace puede eliminarse. Si eso sucede, esta respuesta es inútil)
Zoe
8

La única solución que funciona completamente para mí es una combinación del código de Alex Volovoy con el mecanismo de reinicio de la aplicación:

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);         
    }
}
Misha
fuente
2
después del cambio de ubicación también puede llamaractivity.recreate()
al Kra
1
No quiero reiniciar mi aplicación porque la aplicación está haciendo alguna tarea, como la pantalla de grabación. entonces, sin reiniciar la aplicación, ¿hay alguna solución para Android 7.0
PriyankaChauhan
7

Estaba enfrentando el mismo problema. En GitHub encontré la biblioteca Android-LocalizationActivity .

Esta biblioteca hace que sea muy simple cambiar el idioma de su aplicación en tiempo de ejecución, como puede ver en el ejemplo de código a continuación. Un proyecto de muestra que incluye el código de muestra a continuación y más información se puede encontrar en la página de github.

LocalizationActivity extiende AppCompatActivity, por lo que también puede usarlo cuando usa Fragmentos.

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

Tiempo para una debida actualización.

En primer lugar, la lista en desuso con la API en la que estaba en desuso:

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

Lo que ninguna pregunta contestada recientemente ha sido correcta es el uso del nuevo método .

createConfigurationContext es el nuevo método para updateConfiguration.

Algunos lo han usado de forma independiente así:

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

... pero eso no funciona. ¿Por qué? El método devuelve un contexto, que luego se utiliza para manejar las traducciones de Strings.xml y otros recursos localizados (imágenes, diseños, lo que sea).

El uso adecuado es así:

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

Si acaba de copiar y pegar eso en su IDE, puede ver una advertencia de que la API requiere que apunte a la API 17 o superior. Esto se puede solucionar poniéndolo en un método y agregando la anotación@TargetApi(17)

Pero espera. ¿Qué pasa con las API más antiguas?

Necesita crear otro método usando updateConfiguration sin la anotación 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);

No necesita devolver un contexto aquí.

Ahora, gestionarlos puede ser difícil. En API 17+ necesita el contexto creado (o los recursos del contexto creado) para obtener los recursos apropiados basados ​​en la localización. Como manejas esto?

Bueno, así es como lo hago:

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

Este código funciona al tener un método que realiza llamadas al método apropiado en función de qué API. Esto es algo que he hecho con muchas llamadas diferentes en desuso (incluido Html.fromHtml). Tiene un método que toma los argumentos necesarios, que luego lo divide en uno de dos (o tres o más) métodos y devuelve el resultado apropiado según el nivel de API. Es flexible ya que no tiene que verificarlo varias veces, el método de "entrada" lo hace por usted. El método de entrada aquí essetLanguage

POR FAVOR LEA ESTO ANTES DE USARLO

Debe usar el Contexto devuelto cuando obtiene recursos. ¿Por qué? He visto otras respuestas aquí que usan createConfigurationContext y no usan el contexto que devuelve. Para que funcione así, se debe llamar a updateConfiguration. Lo cual está en desuso. Use el contexto devuelto por el método para obtener recursos.

Ejemplo de uso :

Constructor o algún lugar similar:

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)

Y luego, donde quieras obtener los recursos que haces:

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

Usar cualquier otro contexto (en teoría) romperá esto.

AFAIK todavía tiene que usar un contexto de actividad para mostrar diálogos o tostadas. para eso puedes usar una instancia de una actividad (si estás afuera)


Y finalmente, use recreate()en la actividad para actualizar el contenido. Atajo para no tener que crear una intención de actualizar.

Zoe
fuente
1
Algunos pueden preguntarse si el contexto creado costará su memoria. Sin embargo, de acuerdo con la documentación oficial de Android: "Cada llamada a este método devuelve una nueva instancia de un objeto de contexto; los objetos de contexto no se comparten, sin embargo, el estado común (ClassLoader, otros recursos para la misma configuración) puede ser así que el contexto en sí puede ser bastante ligero." Así que creo que Android espera que uses un objeto de contexto separado para las cosas de la configuración regional.
Sira Lam
7

Si tú escribes

android:configChanges="locale"

En cada actividad (en el archivo de manifiesto), no es necesario configurarlo cada vez que ingrese Activity.

Brijesh Masrani
fuente
11
Si está en el manifiesto, ¿cómo constituye esto un cambio en tiempo de ejecución, que parecía ser lo que quería el OP?
user316117
1
@ user316117 Indica a Android que la aplicación manejará todos los asuntos relacionados con la configuración regional internamente, no que la configuración regional sea estática. Sin embargo, no estoy seguro de si eso evitaría que Android configure la configuración regional al cambiar entre Actividades, ya que solo he visto que se configChangesusa para un truco para preservar el estado de Actividad en rotaciones / etc.
JAB
¿Cómo configurar el idioma solo para inglés específico?
Kaveesh Kanwal
1
... hasta que Android mate tu actividad porque necesita más RAM
Louis CAD
@Brijesh Si hemos cambiado el idioma de la aplicación, entonces si tenemos alguna opción de búsqueda dentro de la aplicación, y si buscamos en eso, cómo la aplicación mostrará los datos, si desarrollamos una base de datos diferente para cada idioma o alguna configuración de código de Android, entonces Qué aplicación podría mostrar datos de acuerdo con la búsqueda?
Vishwa Pratap
5
Locale locale = new Locale("en");
Locale.setDefault(locale);

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

Actualización importante:

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

Tenga en cuenta que en SDK> = 21, debe llamar a 'Resources.updateConfiguration ()' ; de lo contrario, los recursos no se actualizarán.

Максим Петлюк
fuente
updateConfiguration está en desuso. AFAIK usa createConfigurationContext y aplica el contexto que tiene ( Context ctx = createConfigurationContext(args);y obtén recursos de eso
Zoe
Sé que está en desuso. Pero de todos modos, no conozco ninguna solución que pueda funcionar en Android 5 y superior.
Максим Петлюк
Entonces claramente no revisaste el javadoc. llamas al contexto creado desde createConfigurationContext
Zoe
Ok, pero de todos modos deberíamos llamar a updateConfiguration (), ¿verdad?
Максим Петлюк
1
No use la llamada en desuso. Esto significa que no hay actualización de llamadas.
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
fuente
55
no es necesario comenzar una nueva actividad, simplemente actualice la actualactivity.recreate()
Para Kra
4

Locale configurationdebe establecerse en cada uno activityantes de configurar el contenido:this.setContentView(R.layout.main);

cheskapac
fuente
Pero, ¿qué pasa si desea alternar sobre la marcha, después de que se haya llamado a setContentView ()?
IgorGanapolsky
2
después del cambio de localidad también puede llamaractivity.recreate()
Al Kra
4

Al principio cree multi string.xml para diferentes idiomas; luego use este bloque de código en el onCreate()método:

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
fuente
Gracias, este código funciona muy bien, probé en Android 5.xy 6.x sin ningún problema
innovaciones
4

Aquí hay un código que me funciona:

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

Fuente: aquí

Til Schweiger
fuente
3

Ninguna de las soluciones enumeradas aquí me ayudó.

El idioma no se activó en Android> = 7.0 si AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE_NIGHT_YES)

Este LocaleUtils funciona bien: 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());
    }
}
}

Agregó este código a la aplicación

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

Código en actividad

public class BaseActivity extends AppCompatActivity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}
Pavel Shirokov
fuente
2

La respuesta de Alex Volovoy solo funciona para mí si está en el método onCreate de la actividad.

La respuesta que funciona en todos los métodos está en otro hilo

Cambiar idioma mediante programación en Android

Aquí está la adaptación del código.



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

Espero que ayude.

gmauri21
fuente
19
Usted dijo: "La respuesta que funcione en todos los métodos es en otro hilo", pero sus puntos de enlace a este tema "!
user316117
1
config.locale está en desuso
Zoe
2
respuesta recursiva, posible de StackOverflow
tamtom
2

Tenga en cuenta que esta solución updateConfiguration ya no funcionará con el lanzamiento de Android M en unas pocas semanas. La nueva forma de hacer esto ahora es usar el applyOverrideConfigurationmétodo de ContextThemeWrapper ver API doc

Puede encontrar mi solución completa aquí ya que yo mismo enfrenté el problema: https://stackoverflow.com/a/31787201/2776572

Eric Labelle
fuente
Intento el código de configuración de actualización en Android 6.0.1 y funciona bien, no sé si Google solucionó esto, pero puedo usarlo sin problemas
innovaciones
1
Los métodos obsoletos de @innovaciones existen por un tiempo. Eventualmente, será eliminado. Lleva mucho tiempo, pero es mejor pasar a las nuevas API lo antes posible para evitar problemas en el futuro
Zoe
1

Hay algunos pasos que debes implementar

Primero, debe cambiar la configuración regional de su configuración

Resources resources = context.getResources();

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

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

En segundo lugar, si desea que sus cambios se apliquen directamente al diseño que está visible, puede actualizar las vistas directamente o simplemente puede llamar a activity.recreate () para reiniciar la actividad actual.

Y también debe persistir sus cambios porque después de que el usuario cierre su aplicación, perdería el cambio de idioma.

Le expliqué una solución más detallada en mi publicación de blog Cambiar idioma mediante programación en Android

Básicamente, simplemente llame a LocaleHelper.onCreate () en su clase de aplicación y si desea cambiar la configuración regional sobre la marcha puede llamar a LocaleHelper.setLocale ()

Gunhan
fuente
@LunarWatcher Sí, si realmente verifica el código en github o gist, ya está manejado.
Gunhan
1

Esto funciona cuando presiono el botón para cambiar el idioma de texto de mi TextView. (Strings.xml en la carpeta de valores)

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

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

En actividad o fragmento

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

Ahora SetText en cada texto

TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));
Baljinder Maan
fuente
0

similar a la versión aceptada pero respondida de 2017 y reinicio agregado (sin reiniciar, a veces la siguiente Actividad aún se presenta en inglés):

// 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
fuente
1) use finish () en su lugar 2) para reiniciar la aplicación, puede usar activity.recreate()3) el contexto devuelto creo que debe usarse para obtener los recursos
Zoe
No quiero reiniciar mi aplicación porque la aplicación está haciendo alguna tarea, como la pantalla de grabación. entonces, sin reiniciar la aplicación, ¿hay alguna solución para Android 7.0?
PriyankaChauhan
0

Primero cree valores de nombre de directorio: "Nombre de idioma" como hindi que escriba "hola" y copie el mismo nombre de archivo de cadena en este directorio y cambie el valor, no cambie el parámetro después de establecer el código siguiente en su acción como botón, etc.

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
fuente
1
conf.localeestá en desuso
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
fuente
1
No quiero reiniciar mi aplicación porque la aplicación está haciendo alguna tarea, como la pantalla de grabación. entonces, sin reiniciar la aplicación, ¿hay alguna solución para Android 7.0?
PriyankaChauhan
Sí, en 6.0 funciona bien para mí, sin reiniciar la aplicación, el idioma cambió, pero no lo probé en 7.0
Adeeb karim
0

En el ejemplo, establecemos el idioma inglés:

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

Recuerde que esto funciona solo si también se encuentra el idioma en el sistema del dispositivo, no solo en la aplicación

Pavel Pekki
fuente
0

Para soporte árabe / RTL

  1. Debe actualizar la configuración de idioma a través de - attachBaseContext ()
  2. Para la versión de Android N y superior, debe usar createConfigurationContext () y updateConfiguration (); de lo contrario, el diseño RTL no funciona correctamente

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