Cómo cambiar el idioma sobre la marcha en Android

Mientras desarrolla una aplicación en Android, a veces es posible que deba cambiar el idioma sobre la marcha. Sin embargo, Android no proporciona una forma directa de implementar el lenguaje, por lo que debe adaptar un enfoque diferente.

De manera predeterminada, Android usa la configuración regional del dispositivo para seleccionar los recursos apropiados que dependen del idioma.

Mientras buscaba una solución, me encontré con el siguiente blog de Guhan Sabcar, que explica muy bien cómo cambiar el idioma de manera pragmática.

Cambiar idioma mediante programación en Android

Pero esto abordó una parte de nuestro problema, la otra es que la Actividad necesita ser recreada o que todas las Vistas de Texto visibles deben restablecerse.

Así que ideé una forma basada en la solución de Guhan, para que todas las vistas de texto visibles se notifiquen de inmediato cuando cambia la configuración regional, y ellos mismos cambian su propio texto.

Después de la clase que he usado y modificado desde el blog de Guhan:

LocalHelper

paquete com.gunhansancar.android.sdk.helper;

importar android.content.Context;
importar android.content.SharedPreferences;
importar android.content.res.Configuration;
importar android.content.res.Resources;
importar android.preference.PreferenceManager;

import java.util.Locale;

/ **
* Esta clase se usa para cambiar la configuración regional de su aplicación y persistir este cambio para la próxima vez
* que tu aplicación va a ser utilizada.
*

* También puede cambiar la configuración regional de su aplicación sobre la marcha utilizando el método setLocale.
*

* Creado por gunhansancar el 07/10/15.
* /
clase pública LocaleHelper {

Private static final String SELECTED_LANGUAGE = “Locale.Helper.Selected.Language”;

public static void onCreate (contexto de contexto) {
Cadena lang = getPersistedData (context, Locale.getDefault (). GetLanguage ());
setLocale (contexto, lang);
}

public static void onCreate (contexto de contexto, String defaultLanguage) {
String lang = getPersistedData (context, defaultLanguage);
setLocale (contexto, lang);
}

Cadena estática pública getLanguage (contexto de contexto) {
return getPersistedData (context, Locale.getDefault (). getLanguage ());
}

public static void setLocale (contexto de contexto, lenguaje de cadena) {
persistir (contexto, lenguaje);
updateResources (contexto, idioma);
}

String getPersistedData privado estático (contexto de contexto, String defaultLanguage) {
SharedPreferences preferencias = PreferenceManager.getDefaultSharedPreferences (contexto);
return options.getString (SELECTED_LANGUAGE, defaultLanguage);
}

el vacío estático privado persiste (contexto de contexto, lenguaje de cadena) {
SharedPreferences preferencias = PreferenceManager.getDefaultSharedPreferences (contexto);
SharedPreferences.Editor editor = preferencias.edit ();

editor.putString (SELECTED_LANGUAGE, idioma);
editor.apply ();
}

Actualización de vacío estática privada Recursos (contexto de contexto, lenguaje de cadena) {
Locale locale = nuevo Locale (idioma);
Locale.setDefault (locale);

Recursos resources = context.getResources ();

Configuración configuración = resources.getConfiguration ();
configuration.locale = locale;

resources.updateConfiguration (configuración, resources.getDisplayMetrics ());
}
}

Necesitamos hacer 5 cosas aquí

  1. Cree un TextView personalizado que necesitemos usar en todas partes
  2. Cree un atributo personalizado para ese TextView en XML
  3. Cree un BroadcastReceiver en TextView como una clase interna que capturará la transmisión del cambio de configuración regional
  4. Cambie la clase LocaleHelper mencionada anteriormente para enviar una transmisión cada vez que cambie la configuración regional.
  5. Utilice el TextView personalizado en todos los diseños y establezca sus atributos personalizados.

Veamos cada paso en detalle:

Crear una vista de texto personalizada

Esto se hace simplemente extendiendo el TextView, nuestro nuevo TextView personalizado reemplazará todos los TextViews en todos los diseños.

Lo nombramos como LocaleTextView

clase pública LocaleTextView extiende TextView {

OnLocaleChangeReceiver onLocaleChangeReceiver;
String stringResId;

public LocaleTextView (contexto de contexto) {
super (contexto);
}
public LocaleTextView (Contexto contextual, @Nullable AttributeSet attrs) {
super (contexto, atributos);
TypedArray ta = context.obtainStyledAttributes (attrs, R.styleable.LocaleTextView, 0, 0);
tratar {
stringResId = ta.getString (0);
} finalmente {
ta.recycle ();
}
}
}

Crear atributo personalizado para nuestro TextView personalizado

Este atributo personalizado contendrá el nombre del recurso de cadena que se establece en TextView

Necesitamos crear el archivo attrs.xml en la carpeta res / values ​​y agregarle el siguiente código.

Ahora modificamos nuestro TextView personalizado, es decir, LocaleTextView para acomodar este nuevo atributo llamado stringResId

Agregamos la variable de instancia stringResId en nuestro LocalTextView y modificamos el constructor para establecer su valor.

También agregamos métodos getter y setter para stringResId.

clase pública LocaleTextView extiende TextView {

String stringResId;
public LocaleTextView (contexto de contexto) {
super (contexto);
}
public LocaleTextView (Contexto contextual, @Nullable AttributeSet attrs) {
super (contexto, atributos);
TypedArray ta = context.obtainStyledAttributes (attrs, R.styleable.LocaleTextView, 0, 0);
tratar {
stringResId = ta.getString (0);
} finalmente {
ta.recycle ();
}
}

public String getStringResId () {
return stringResId;
}

public void setStringResId (String id) {
this.stringResId = id;
}

}

Crear un BroadcastReceiver dentro de LocaleTextView como clase interna estática para capturar el evento de cambio de configuración regional

Creamos una clase interna estática llamada OnLocaleChangeReceiver dentro de nuestro LocaleTextView, esta clase que extiende un BroadcastReceiver se usa para recibir difusión cada vez que se cambia el entorno local.

La clase estática pública OnLocaleChangeReceiver extiende BroadcastReceiver {

com.hypersoft.walletapp.ui.customviews.LocaleTextView v;
public void setTextView (com.hypersoft.walletapp.ui.customviews.LocaleTextView v) {
this.v = v;
}
@Anular
public void onReceive (contexto de contexto, intento de intención) {
//Utility.debugger(“onReceive llamado “+ v);

if (v! = null && v.getStringResId ()! = null &&! v.getStringResId (). equalsIgnoreCase (“”)) {
Utility.debugger (“String” + context.getResources (). GetString (v.getResources (). GetIdentifier (v.getStringResId (), “string”, context.getPackageName ())));
v.setText (v.getResources (). getIdentifier (v.getStringResId (), “cadena”, context.getPackageName ()));
}más{
if (v! = null) {
v.invalidate ();
}
}

}
}

Registrar y anular el registro de la instancia OnLocaleChangeReceiver de los métodos de ciclo de vida de LocaleTextView

Nosotros registre y anule el registro del receptor dentro de onAttachedToWindow () y onDetachToWindow () de LocaleTextView respectivamente.

@Anular
vacío protegido enAttachedToWindow () {
super.onAttachedToWindow ();
onLocaleChangeReceiver = nuevo OnLocaleChangeReceiver ();
onLocaleChangeReceiver.setTextView (this);
Utility.debugger (“onAttached llamado”);
IntentFilter intentFilter = new IntentFilter ();
intentFilter.addAction (“com.locale.change”);
getContext (). registerReceiver (onLocaleChangeReceiver, intentFilter);

}

@Anular
nulo protegido enDetachedFromWindow () {
super.onDetachedFromWindow ();
Utility.debugger (“onDettached llamado”);
getContext (). unregisterReceiver (onLocaleChangeReceiver);
}

Código completo final de LocaleTextView

clase pública LocaleTextView extiende TextView {

OnLocaleChangeReceiver onLocaleChangeReceiver;
String stringResId;

public LocaleTextView (contexto de contexto) {
super (contexto);
}
public LocaleTextView (Contexto contextual, @Nullable AttributeSet attrs) {
super (contexto, atributos);
TypedArray ta = context.obtainStyledAttributes (attrs, R.styleable.LocaleTextView, 0, 0);
tratar {
stringResId = ta.getString (0);
} finalmente {
ta.recycle ();
}
}

La clase estática pública OnLocaleChangeReceiver extiende BroadcastReceiver {

com.hypersoft.walletapp.ui.customviews.LocaleTextView v;
public void setTextView (com.hypersoft.walletapp.ui.customviews.LocaleTextView v) {
this.v = v;
}
@Anular
public void onReceive (contexto de contexto, intento de intención) {
//Utility.debugger(“onReceive llamado “+ v);

if (v! = null && v.getStringResId ()! = null &&! v.getStringResId (). equalsIgnoreCase (“”)) {
Utility.debugger (“String” + context.getResources (). GetString (v.getResources (). GetIdentifier (v.getStringResId (), “string”, context.getPackageName ())));
v.setText (v.getResources (). getIdentifier (v.getStringResId (), “cadena”, context.getPackageName ()));
}más{
if (v! = null) {
v.invalidate ();
}
}

}
}

public String getStringResId () {
return stringResId;
}

public void setStringResId (String id) {
this.stringResId = id;
}

@Anular
vacío protegido enAttachedToWindow () {
super.onAttachedToWindow ();
onLocaleChangeReceiver = nuevo OnLocaleChangeReceiver ();
onLocaleChangeReceiver.setTextView (this);
Utility.debugger (“onAttached llamado”);
IntentFilter intentFilter = new IntentFilter ();
intentFilter.addAction (“com.locale.change”);
getContext (). registerReceiver (onLocaleChangeReceiver, intentFilter);

}

@Anular
nulo protegido enDetachedFromWindow () {
super.onDetachedFromWindow ();
Utility.debugger (“onDettached llamado”);
getContext (). unregisterReceiver (onLocaleChangeReceiver);
}

}

Finalmente, usando el LocaleTextView personalizado en diseños

<com.example.LocaleTextView
xmlns: customNS = “http://schemas.android.com/apk/res/com.example”
customNS: stringResId = “lbl_temp_john_smith”
android: layout_width = “wrap_content”
android: layout_height = “wrap_content”
android: text = “@ string / lbl_temp_john_smith”
android: textColor = “@ color / orangeDark”
android: minHeight = “0dp”
android: paddingTop = “1dp”
android: paddingBottom = “1dp”
android: layout_marginLeft = “@ dimen / margin_15”
android: layout_marginTop = “@ dimen / margin_10” />
John Smith

Ahora, cuando cambie el idioma de forma pragmática, todas las vistas de texto que estén visibles se actualizarán según el nuevo idioma.