Preferencias de idioma de las apps

Idiomas de las apps en la configuración del sistema

En muchos casos, los usuarios multilingües configuran un idioma para su sistema, como el inglés, pero desean seleccionar otros para apps específicas, como el chino, el hindi o el holandés. Con el fin de ayudar a que las apps brinden una mejor experiencia para estos usuarios, Android 13 presenta las siguientes funciones en las apps que admiten varios idiomas:

  • Configuración del sistema: Una ubicación centralizada en la que los usuarios pueden seleccionar un idioma preferido para cada app.

    Puedes configurar tu app para que genere automáticamente los archivos necesarios para admitir las preferencias de idioma de la app y mostrarlos en la configuración del sistema. Si quieres obtener más información, consulta las instrucciones para habilitar la compatibilidad automática de idioma de las apps.

  • APIs adicionales: Estas APIs públicas, como los métodos setApplicationLocales y getApplicationLocales en LocaleManager, permiten que las apps configuren un idioma diferente del idioma del sistema en el tiempo de ejecución.

    Estas APIs se sincronizan automáticamente con la configuración del sistema. Por lo tanto, las apps que las usan para crear selectores de idioma personalizados integrados en la app garantizarán que los usuarios tengan una experiencia del usuario coherente, sin importar dónde seleccionen sus preferencias de idioma. Las APIs públicas también ayudan a reducir la cantidad de código estándar, admiten APKs divididos y copias de seguridad automáticas para apps con el objetivo de almacenar los parámetros de configuración de idiomas del usuario en el nivel de app.

    Para ofrecer retrocompatibilidad con versiones anteriores de Android, las APIs equivalentes también están disponibles en AndroidX. Sin embargo, las APIs retrocompatibles funcionan con el contexto AppCompatActivity, no el contexto de la aplicación, para Android 12 (nivel de API 32) y versiones anteriores. Accede a las APIs retrocompatibles con Appcompat 1.6.0 o versiones posteriores.

Descripción general de la implementación de esta función

En la siguiente tabla, se muestran implementaciones recomendadas, según diferentes casos de uso.

Caso de uso Implementación recomendada
Tu app no tiene un selector de idioma integrado
  1. Habilita la compatibilidad automática de idioma de las apps para generar un archivo LocaleConfig y agregar los idiomas de tu app a la configuración del sistema.
  2. De manera opcional, si deseas agregar un selector de idioma integrado en la app, implementa uno en Compose o usa la biblioteca de AndroidX y habilita nuestra implementación de API para admitir la retrocompatibilidad a través de autoStoreLocales.
Tu app ya incluye un selector de idioma integrado
  1. Habilita la compatibilidad automática de idioma de las apps para generar un archivo LocaleConfig y agregar los idiomas de tu app a la configuración del sistema.
  2. Migra la lógica personalizada de tu app para usar Compose o las APIs públicas y garantizar que los usuarios disfruten una experiencia coherente.
  3. Controla los siguientes casos límite:
    1. Llama a AppCompatDelegate.setApplicationLocales la primera vez que se ejecute tu app en un dispositivo con Android 13.
    2. Llama a AppCompatDelegate.setApplicationLocales para proporcionarle al sistema los parámetros preexistentes de configuración regional que solicitó el usuario en los siguientes casos:

Configuración del sistema para usuarios

A partir de Android 13, el sistema operativo incluye una ubicación centralizada en la configuración del sistema para preferencias de idioma de las apps. Para asegurarte de que se puedan configurar los idiomas en los parámetros de configuración del sistema en dispositivos que ejecutan Android 13 o versiones posteriores, habilita la compatibilidad automática de idioma de las apps (recomendado) o configura la compatibilidad de forma manual.

Cómo habilitar la compatibilidad automática de idioma de las apps

Esta es la forma recomendada de agregar compatibilidad con el idioma por app a tus apps, ya que no requiere modificaciones en XML.

A partir de Android Studio Giraffe y AGP 8.1, puedes configurar tu app para que admita automáticamente las preferencias de idioma de las apps. En función de los recursos de tu proyecto, AGP genera el archivo LocaleConfig y le agrega una referencia en el archivo de manifiesto final, por lo que ya no tienes que hacerlo de forma manual. AGP usa los recursos de las carpetas res de los módulos de tu app y las dependencias de módulos de biblioteca para determinar las configuraciones regionales que se incluirán en el archivo LocaleConfig. Esto significa que, si agregas recursos para un idioma nuevo a tu app, no tendrás que preocuparte por actualizar el archivo LocaleConfig.

Ten en cuenta que la función automática de idioma de las apps admite apps que ejecutan Android 13 (nivel de API 33) o versiones posteriores. Para usar la función, debes establecer compileSdkVersion en 33 o un valor superior. Para configurar las preferencias de idioma de las apps en versiones anteriores de Android, debes usar las APIs y los selectores de idioma integrados en la app.

Para habilitar la compatibilidad automática de idioma de las apps, sigue estos pasos:

  1. Para activar la función, usa el parámetro de configuración generateLocaleConfig en el bloque androidResources {} del archivo build.gradle.kts a nivel del módulo (archivo build.gradle si usas Groovy). La función está desactivada de forma predeterminada.

Kotlin

    android {
      androidResources {
        generateLocaleConfig = true
      }
    }

Groovy

  android {
    androidResources {
      generateLocaleConfig true
    }
  }
  1. Especifica una configuración regional predeterminada:
    1. En la carpeta res del módulo de la app, crea un archivo nuevo llamado resources.properties.
    2. En el archivo resources.properties, establece la configuración regional predeterminada con la etiqueta unqualifiedResLocale. Para dar formato a los nombres de configuración regional, consulta Cómo formar nombres de configuración regional.

AGP agrega esta configuración regional predeterminada y todas las configuraciones regionales alternativas que especificaste, con directorios values-* en la carpeta res, al archivo LocaleConfig generado automáticamente.

Cómo formar nombres de configuración regional

Para formar nombres de configuración regional, combina el código de idioma con la secuencia de comandos opcional y los códigos regionales, y separa cada uno con un guion:

  • Idioma: Usa el código ISO 639-2 de dos o tres letras.
  • Secuencia de comandos (opcional): Usa el código ISO 15924.
  • Región (opcional): Usa el código ISO 3166-1-alpha-2 de dos letras o el código UN_M.49 de tres dígitos.

Por ejemplo, si tu configuración regional predeterminada es Inglés (Estados Unidos):

unqualifiedResLocale=en-US

Usa android:localeConfig para agregar los idiomas compatibles a la configuración del sistema

Puedes configurar la app de forma manual para asegurarte de que los idiomas se puedan establecer en la configuración del sistema en dispositivos que ejecutan Android 13 o versiones posteriores. Para ello, crea un archivo en formato XML locale_config y agrégalo al manifiesto de tu app con el atributo android:localeConfig. Si omites los indicadores de entrada del manifiesto android:localeConfig, los usuarios no podrán configurar un idioma de tu app diferente del idioma del sistema en la configuración del sistema.

Para agregar de forma manual los idiomas compatibles de la app a la configuración del sistema del usuario, haz lo siguiente:

  1. Crea un archivo llamado res/xml/locale_config.xml y especifica los idiomas de tu app, incluida la configuración regional de resguardo final, que es la configuración regional especificada en res/values/strings.xml.

    Consulta Cómo formar nombres de configuración regional para conocer los requisitos de formato. Consulta también el archivo locale_config.xml de muestra para obtener una lista de las configuraciones regionales de uso frecuente.

    Por ejemplo, da formato al archivo locale_config.xml de esta manera para una app que admite los siguientes idiomas:

    • Inglés (Estados Unidos) como la última configuración regional de resguardo
    • Inglés (Reino Unido)
    • Francés
    • Japonés
    • Chino (simplificado, Macao)
    • Chino (tradicional, Macao)
    <?xml version="1.0" encoding="utf-8"?>
    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
       <locale android:name="en-US"/>
       <locale android:name="en-GB"/>
       <locale android:name="fr"/>
       <locale android:name="ja"/>
       <locale android:name="zh-Hans-MO"/>
       <locale android:name="zh-Hant-MO"/>
    </locale-config>
    
  2. En el manifiesto, agrega una línea que dirija a este archivo nuevo:

    <manifest>
        ...
        <application
            ...
            android:localeConfig="@xml/locale_config">
        </application>
    </manifest>
    

Puedes actualizar de forma dinámica el localeConfig de tu app con LocaleManager.setOverrideLocaleConfig para personalizar el conjunto de idiomas que se muestra en la lista de idiomas por app en la Configuración de Android. Esto te permite personalizar la lista de idiomas por región, ejecutar experimentos A/B y proporcionar configuraciones regionales actualizadas si tu app usa envíos de localización del servidor, como se muestra en el siguiente ejemplo:

//For setOverrideLocaleConfig
val localeManager = applicationContext
    .getSystemService(LocaleManager::class.java)
localeManager.overrideLocaleConfig = LocaleConfig(
LocaleList.forLanguageTags("en-US,ja-JP,zh-Hans-SG")
)

//For getOverrideLocaleConfig
// The app calls the API to get the override LocaleConfig
val overrideLocaleConfig = localeManager.overrideLocaleConfig
// If the returned overrideLocaleConfig isn't equal to NULL, then the app calls the API to get the supported Locales
val supportedLocales = overrideLocaleConfig.supportedLocales()

Además, los IME ahora pueden usar LocaleManager.getApplicationLocales para conocer el idioma de la IU de la app actual y actualizar el idioma del teclado, como se muestra a continuación:

val currentAppLocales: LocaleList = applicationContext.getSystemService(LocaleManager::class.java).getApplicationLocales(appPackageName)

Especifica los idiomas compatibles en Gradle

Si aún no está presente, especifica los mismos idiomas con la propiedad resourceConfigurations en el archivo build.gradle a nivel de módulo de tu app:

android {
  ...
  defaultConfig {
    resourceConfigurations += ["en", "en-rGB", "fr", "ja", "b+zh+Hans+MO", "b+zh+Hant+MO"]
  }
}

Cuando la propiedad resourceConfigurations está presente, el sistema de compilación solo incluye recursos de idiomas en el APK para los idiomas que se especifican, lo que evita que se incluyan cadenas traducidas de otras bibliotecas de idiomas que tu app podría no admitir. Para obtener más información, consulta Cómo especificar los idiomas que admite tu app.

Cómo los usuarios seleccionan el idioma de una app en la configuración del sistema

Los usuarios pueden seleccionar el idioma de su preferencia para cada app con la configuración del sistema. Pueden acceder a esta configuración de dos maneras diferentes:

  • Acceder a través de la configuración del sistema

    Configuración > Sistema > Idiomas y entradas > Idiomas de las apps > (selecciona una app)

  • Acceder a través de la configuración de Apps

    Configuración > Apps > (selecciona una app) > Idioma

Controla los selectores de idiomas integrados en la app

En el caso de las apps que ya tienen un selector de idioma integrado en la app o que quieren utilizar uno, usa las APIs públicas en lugar de la lógica personalizada de la app a fin de controlar la configuración y obtener el idioma preferido del usuario para tu app. Si usas las APIs públicas para el selector de idioma integrado en la app, la configuración del sistema del dispositivo se actualizará automáticamente para que coincida con el idioma que el usuario seleccione a través de la experiencia integrada en la app.

Implementación con Jetpack Compose

En el caso de las apps creadas completamente con Jetpack Compose, el sistema controla automáticamente las actualizaciones de la IU cuando cambia la configuración regional de la app. Llamar a la API para establecer un nuevo idioma activa un cambio de configuración. Compose reacciona recomponiendo tu IU y resolviendo automáticamente cualquier llamada a stringResource con la nueva configuración regional.

Para ofrecer retrocompatibilidad con Android 12 (nivel de API 32) y versiones anteriores, recomendamos usar la biblioteca de compatibilidad de AndroidX (AppCompatDelegate) cuando implementes un selector de idioma integrado en la app. Si usas este enfoque, la actividad que aloja tu IU de Compose debe extender AppCompatActivity. Sin embargo, también puedes implementar las APIs del framework directamente si es necesario.

En el siguiente fragmento de código, se muestra un ejemplo de cómo leer la configuración regional actual de la app y establecer una nueva dentro de una función de componibilidad:

import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.core.os.LocaleListCompat

@Composable
fun LanguageSelector() {
    // Retrieve the currently configured app locale.
    // If no app-specific locale is set, LocaleListCompat.get(0) returns null,
    // so we safely fall back to a default (e.g., "en").
    val appLocales = AppCompatDelegate.getApplicationLocales()
    val currentLocaleTag = appLocales.get(0)?.toLanguageTag() ?: "en"

    // Example UI: A button to toggle between English and Spanish
    Button(
        onClick = {
            val newLanguageTag = if (currentLocaleTag == "en") "es" else "en"
            val localeList = LocaleListCompat.forLanguageTags(newLanguageTag)

            // Setting the locale re-creates the Activity by default,
            // which automatically applies the new configuration to Compose.
            AppCompatDelegate.setApplicationLocales(localeList)
        }
    ) {
        Text(
            text = if (currentLocaleTag == "en") "Switch to Spanish" else "Switch to English"
        )
    }
}

Para configurar el idioma de preferencia de un usuario, se le solicita seleccionar una configuración regional en el selector de idioma y establecer ese valor en el sistema:

val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY")
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale)

Ten en cuenta que, cuando se llama a setApplicationLocales, se recrea tu Activity, a menos que tu app controle los cambios de configuración regional por su cuenta.

Usa AppCompatDelegate.getApplicationLocales para recuperar la configuración regional preferida del usuario. Es posible que el usuario haya seleccionado la configuración regional de la app desde la configuración del sistema o desde el selector de idioma de la app.

Compatibilidad con Android 12 y versiones anteriores

Para admitir dispositivos que ejecutan Android 12 (nivel de API 32) y versiones anteriores, indícale a AndroidX que controle el almacenamiento de la configuración regional estableciendo un valor autoStoreLocales en true y android:enabled en false en la entrada de manifiesto del servicio AppLocalesMetadataHolderService de tu app, como se muestra en el siguiente fragmento de código:

<application
  ...
  <service
    android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
    android:enabled="false"
    android:exported="false">
    <meta-data
      android:name="autoStoreLocales"
      android:value="true" />
  </service>
  ...
</application>

Ten en cuenta que establecer un valor autoStoreLocales en true provoca un bloqueo de lectura en el subproceso principal y puede causar un incumplimiento de StrictMode diskRead y diskWrite si registras incumplimientos de subprocesos. Consulta AppCompatDelegate.setApplicationLocales para obtener más información.

Control de almacenamiento personalizado

Omitir la entrada del manifiesto o la configuración de autoStoreLocales en false indica que controlas tu propio almacenamiento. En este caso, debes proporcionar los parámetros de configuración regional almacenados antes de onCreate en el ciclo de vida de la actividad y las llamadas de puerta a AppCompatDelegate.setApplicationLocales en Android 12 (nivel de API 32) o versiones anteriores.

Si tu app tiene una ubicación de almacenamiento de configuración regional personalizada, se recomienda usar una transferencia única entre la solución de almacenamiento de configuración regional personalizada y autoStoreLocales, para que los usuarios continúen disfrutando de la app en el idioma que prefieran. Esto se aplica especialmente cuando la app se ejecuta por primera vez después de que un dispositivo se actualizó a Android 13. En este caso, puedes proporcionar parámetros preexistentes de configuración regional que solicitó el usuario. Para ello, debes recuperar estos parámetros de tu almacenamiento personalizado y pasarlos a AppCompatDelegate.setApplicationLocales.

Implementación con las APIs del framework de Android

Si bien te recomendamos que uses la biblioteca de compatibilidad de AndroidX para implementar selectores de idiomas integrados en la app, también puedes usar los métodos setApplicationLocales y getApplicationLocales en el framework de Android para dispositivos que ejecutan Android 13.

En el siguiente fragmento de código, se muestra cómo establecer y obtener el idioma preferido del usuario con el servicio del sistema LocaleManager:

import android.app.LocaleManager
import android.content.Context
import android.os.Build
import android.os.LocaleList
import androidx.annotation.RequiresApi
import java.util.Locale

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun setAppLanguage(context: Context, languageTag: String) {
    // 1. Retrieve the system service
    val localeManager = context.getSystemService(LocaleManager::class.java)

    // 2. Create a LocaleList from the language tag (e.g., "es-ES" or "ja")
    val localeList = LocaleList(Locale.forLanguageTag(languageTag))

    // 3. Set the locale. The system automatically updates the locale and
    // restarts the app, including any necessary configuration updates.
    localeManager.applicationLocales = localeList
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun getAppLanguage(context: Context): String {
    val localeManager = context.getSystemService(LocaleManager::class.java)
    val currentLocales = localeManager.applicationLocales

    // Return the primary app locale, or fall back to the system default
    return if (!currentLocales.isEmpty) {
        currentLocales.get(0).toLanguageTag()
    } else {
        Locale.getDefault().toLanguageTag()
    }
}

Prácticas recomendadas adicionales

Toma nota de las siguientes prácticas recomendadas.

Ten en cuenta el idioma cuando invoques un intent en otra app

Es posible que los intents centrados en el idioma te permitan especificar el idioma en el que deseas que esté la app invocada. Un ejemplo es la función EXTRA_LANGUAGE de la API de Speech Recognizer.

Ten en cuenta el encabezado Accept-Language para la pestaña personalizada de Chrome

Te recomendamos que agregues el encabezado Accept-Language a través de Browser.EXTRA_HEADERS para abrir una página web en el idioma de tu app cuando invoques una pestaña personalizada de Chrome.

Si quitas las preferencias de idioma de las apps en la configuración del sistema, restablece la configuración regional de tu app a la del sistema.

Si quitas las preferencias de idioma de la app de la configuración del sistema (es decir, si quitas android:localeConfig del archivo AndroidManifest.xml de tu app), los usuarios no podrán restablecer fácilmente el idioma de la app a la configuración predeterminada del sistema.

Por este motivo, si quitas android:localeConfig, considera restablecer la configuración regional de la app a la configuración regional del sistema con LocaleListCompat.getEmptyLocaleList o LocaleList.getEmptyLocaleList, como se ve en el siguiente fragmento de código:

// Use the AndroidX APIs to reset to the system locale for backward and forward compatibility
AppCompatDelegate.setApplicationLocales(
  LocaleListCompat.getEmptyLocaleList()
)

// Or use the Framework APIs for Android 13 and above to reset to the system locale
val context = LocalContext.current
context.getSystemService(LocaleManager::class.java)
  .applicationLocales = LocaleList.getEmptyLocaleList()

Ejemplo de archivo locale_config.xml

De forma predeterminada, Android incluye traducciones a nivel del sistema en el Proyecto de código abierto de Android (AOSP) para un conjunto estándar de las configuraciones regionales de uso general. El archivo locale_config.xml de muestra que se incluye en esta sección muestra el formato sugerido para cada una de estas configuraciones regionales. Consulta este archivo de muestra para ayudarte a crear tu propio archivo locale_config.xml para el conjunto de lenguajes que admite tu app.

<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
   <locale android:name="af"/> <!-- Afrikaans -->
   <locale android:name="am"/> <!-- Amharic -->
   <locale android:name="ar"/> <!-- Arabic -->
   <locale android:name="as"/> <!-- Assamese -->
   <locale android:name="az"/> <!-- Azerbaijani -->
   <locale android:name="be"/> <!-- Belarusian -->
   <locale android:name="bg"/> <!-- Bulgarian -->
   <locale android:name="bn"/> <!-- Bengali -->
   <locale android:name="bs"/> <!-- Bosnian -->
   <locale android:name="ca"/> <!-- Catalan -->
   <locale android:name="cs"/> <!-- Czech -->
   <locale android:name="da"/> <!-- Danish -->
   <locale android:name="de"/> <!-- German -->
   <locale android:name="el"/> <!-- Greek -->
   <locale android:name="en-AU"/> <!-- English (Australia) -->
   <locale android:name="en-CA"/> <!-- English (Canada) -->
   <locale android:name="en-GB"/> <!-- English (United Kingdom) -->
   <locale android:name="en-IN"/> <!-- English (India) -->
   <locale android:name="en-US"/> <!-- English (United States) -->
   <locale android:name="es"/> <!-- Spanish (Spain) -->
   <locale android:name="es-US"/> <!-- Spanish (United States) -->
   <locale android:name="et"/> <!-- Estonian -->
   <locale android:name="eu"/> <!-- Basque -->
   <locale android:name="fa"/> <!-- Farsi -->
   <locale android:name="fi"/> <!-- Finnish -->
   <locale android:name="fil"/> <!-- Filipino -->
   <locale android:name="fr"/> <!-- French (France) -->
   <locale android:name="fr-CA"/> <!-- French (Canada) -->
   <locale android:name="gl"/> <!-- Galician -->
   <locale android:name="gu"/> <!-- Gujarati -->
   <locale android:name="hi"/> <!-- Hindi -->
   <locale android:name="hr"/> <!-- Croatian -->
   <locale android:name="hu"/> <!-- Hungarian -->
   <locale android:name="hy"/> <!-- Armenian -->
   <locale android:name="in"/> <!-- Indonesian -->
   <locale android:name="is"/> <!-- Icelandic -->
   <locale android:name="it"/> <!-- Italian -->
   <locale android:name="iw"/> <!-- Hebrew -->
   <locale android:name="ja"/> <!-- Japanese -->
   <locale android:name="ka"/> <!-- Georgian -->
   <locale android:name="kk"/> <!-- Kazakh -->
   <locale android:name="km"/> <!-- Khmer -->
   <locale android:name="kn"/> <!-- Kannada -->
   <locale android:name="ko"/> <!-- Korean -->
   <locale android:name="ky"/> <!-- Kyrgyz -->
   <locale android:name="lo"/> <!-- Lao -->
   <locale android:name="lt"/> <!-- Lithuanian -->
   <locale android:name="lv"/> <!-- Latvian -->
   <locale android:name="mk"/> <!-- Macedonian -->
   <locale android:name="ml"/> <!-- Malayalam -->
   <locale android:name="mn"/> <!-- Mongolian -->
   <locale android:name="mr"/> <!-- Marathi -->
   <locale android:name="ms"/> <!-- Malay -->
   <locale android:name="my"/> <!-- Burmese -->
   <locale android:name="nb"/> <!-- Norwegian -->
   <locale android:name="ne"/> <!-- Nepali -->
   <locale android:name="nl"/> <!-- Dutch -->
   <locale android:name="or"/> <!-- Odia -->
   <locale android:name="pa"/> <!-- Punjabi -->
   <locale android:name="pl"/> <!-- Polish -->
   <locale android:name="pt-BR"/> <!-- Portuguese (Brazil) -->
   <locale android:name="pt-PT"/> <!-- Portuguese (Portugal) -->
   <locale android:name="ro"/> <!-- Romanian -->
   <locale android:name="ru"/> <!-- Russian -->
   <locale android:name="si"/> <!-- Sinhala -->
   <locale android:name="sk"/> <!-- Slovak -->
   <locale android:name="sl"/> <!-- Slovenian -->
   <locale android:name="sq"/> <!-- Albanian -->
   <locale android:name="sr"/> <!-- Serbian (Cyrillic) -->
   <locale android:name="sr-Latn"/> <!-- Serbian (Latin) -->
   <locale android:name="sv"/> <!-- Swedish -->
   <locale android:name="sw"/> <!-- Swahili -->
   <locale android:name="ta"/> <!-- Tamil -->
   <locale android:name="te"/> <!-- Telugu -->
   <locale android:name="th"/> <!-- Thai -->
   <locale android:name="tr"/> <!-- Turkish -->
   <locale android:name="uk"/> <!-- Ukrainian -->
   <locale android:name="ur"/> <!-- Urdu -->
   <locale android:name="uz"/> <!-- Uzbek -->
   <locale android:name="vi"/> <!-- Vietnamese -->
   <locale android:name="zh-Hans"/> <!-- Chinese (Simplified) -->
   <locale android:name="zh-Hant"/> <!-- Chinese (Traditional) -->
   <locale android:name="zu"/> <!-- Zulu -->
</locale-config>

Recursos adicionales

Consulta nuestras muestras de código, artículos de blog y videos para obtener información adicional.