Usar localizaciones y códigos de idioma en el SDK de Android

Por qué esto es importante

Los códigos de idioma entran en juego cuando Adapty elige la localización para un flow o un onboarding, y cuando lees un Remote Config para un paywall personalizado.

Los códigos de idioma son complejos y pueden variar de una plataforma a otra, por eso Adapty utiliza un único estándar interno en todas las plataformas que admite. Entender ese estándar te ayuda a predecir qué localización recibirá cada usuario.

Estándar de códigos de idioma en Adapty

Para los códigos de idioma, Adapty utiliza una versión ligeramente modificada del estándar BCP 47: cada código se compone de subetiquetas en minúsculas separadas por guiones. Algunos ejemplos: en (inglés), pt-br (portugués de Brasil), zh (chino simplificado), zh-hant (chino tradicional).

Coincidencia de códigos de idioma

En SDK v4, los flows y onboardings hacen coincidir los códigos de idioma de manera diferente: los flows son localizados por el SDK en el dispositivo, los onboardings por el servidor de Adapty.

Flows y paywalls del Paywall Builder

Un paywall creado en el Paywall Builder se entrega como un flow en SDK v4, por lo que la regla siguiente aplica a ambos.

La coincidencia es exacta. El SDK compara el código que pasas con los códigos de localización del flow carácter a carácter: no cambia las mayúsculas/minúsculas, no reemplaza los guiones bajos (_) por guiones (-) y no recurre al subtag de idioma. Para un flow con localización pt-br, solo pt-br coincide: pt-BR, pt_BR y pt-PT no coinciden.

Cuando el código no coincide con ninguna localización, el flow se renderiza silenciosamente en su configuración regional predeterminada — el SDK no devuelve ningún error ni registra ninguna advertencia.

Cuando el código coincide, Adapty fusiona la localización con la predeterminada: las cadenas y los recursos que la localización coincidente no define se obtienen de la localización predeterminada.

Omitir el código de idioma no es lo mismo que solicitar la localización predeterminada del flow: el SDK sustituye un en fijo. Un flow cuya localización predeterminada sea de se sigue renderizando en en si tiene una localización en, y solo recurre a de cuando no la tiene. Esto se aplica a Android SDK 4.0.1 y versiones posteriores — en 4.0.0, omitir el código renderiza la localización predeterminada del flow.

Warning

Pasa el código de idioma exactamente como está configurado en el dashboard: subtags en minúsculas separadas por guiones. No pases un identificador de idioma del sistema tal como está: Locale.getDefault().toLanguageTag() devuelve pt-BR y Locale.getDefault().toString() devuelve pt_BR, y ambos recurren a la localización predeterminada. Convierte el valor en tu app antes de pasarlo.

Onboardings

Los onboardings se localizan en el servidor, y las reglas del servidor toleran otros formatos. Cuando pasas un locale a getOnboarding:

  1. La cadena de locale se convierte a minúsculas y todos los guiones bajos (_) se reemplazan por guiones (-)
  2. Adapty busca la localización con el código de locale que coincida exactamente
  3. Si no se encuentra ninguna coincidencia, Adapty toma la subcadena antes del primer guión (pt para pt-br) y busca la localización correspondiente
  4. Si tampoco se encuentra ninguna coincidencia, Adapty devuelve el contenido para el locale predeterminado del onboarding

Esta forma, pt_BR, pt-BR, y pt-br se resuelven en la misma localización del onboarding.

Implementación de localizaciones

En SDK v4, no necesitas pasar un código de idioma al obtener un flow — getFlow devuelve el flow con todas sus localizaciones.

  • Flows creados en el builder: el SDK no lee la configuración regional del dispositivo, así que resuélvela en tu app y pásala como argumento locale de AdaptyUI.getFlowConfiguration. El argumento es opcional: omítelo y el flow se renderizará en en, o en su configuración regional predeterminada cuando el flow no tenga localización en.
  • Paywalls personalizados (Remote Config): getFlow devuelve todas las localizaciones configuradas en flow.remoteConfigs. Cada entrada tiene un código locale y el contenido de configuración (jsonString o el dataMap ya procesado). Selecciona la entrada que corresponda al usuario con tu propia lógica de respaldo:
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
    when (result) {
        is AdaptyResult.Success -> {
            val flow = result.value
            val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
                ?: flow.remoteConfigs.firstOrNull()
            // read your values from config?.dataMap
        }
        is AdaptyResult.Error -> {
            // handle the error
        }
    }
}

Adapty almacena esos códigos de locale en el formato descrito en Estándar de código de locale en Adapty. El SDK no compara los Remote Configs con un locale, por lo que es tu aplicación la que decide qué entrada aplicar.

Por qué esto es importante

Hay algunos escenarios en los que los códigos de idioma entran en juego; por ejemplo, cuando intentas obtener el paywall correcto para la localización actual de tu app.

Como los códigos de idioma son complejos y pueden variar de una plataforma a otra, nos basamos en un estándar interno para todas las plataformas que soportamos. Sin embargo, precisamente por esa complejidad, es muy importante que entiendas qué estás enviando exactamente a nuestro servidor para obtener la localización correcta y qué ocurre después, para que siempre recibas lo que esperas.

Estándar de códigos de idioma en Adapty

Para los códigos de idioma, Adapty utiliza una versión ligeramente modificada del estándar BCP 47: cada código se compone de subetiquetas en minúsculas separadas por guiones. Algunos ejemplos: en (inglés), pt-br (portugués (Brasil)), zh (chino simplificado), zh-hant (chino tradicional).

Coincidencia de código de idioma

Cuando Adapty recibe una llamada del SDK con el código de idioma y comienza a buscar la localización correspondiente de un paywall, ocurre lo siguiente:

  1. La cadena de idioma entrante se convierte a minúsculas y todos los guiones bajos (_) se reemplazan por guiones (-)
  2. A continuación, buscamos la localización con el código de idioma que coincida exactamente
  3. Si no se encuentra ninguna coincidencia, tomamos la subcadena antes del primer guión (pt para pt-br) y buscamos la localización correspondiente
  4. Si tampoco se encuentra ninguna coincidencia, devolvemos el contenido del idioma predeterminado del paywall

De este modo, un dispositivo iOS que envíe 'pt_BR', un dispositivo Android que envíe pt-BR y otro dispositivo que envíe pt-br obtendrán el mismo resultado.

Si te estás preguntando sobre las localizaciones, probablemente ya estés trabajando con los archivos de cadenas localizadas de tu proyecto. En ese caso, te recomendamos añadir un par clave-valor con el código de idioma de Adapty correspondiente en cada uno de esos archivos. Luego, extrae el valor de esa clave al llamar a nuestro SDK, así:

// 1. Modify your strings.xml files

/*
strings.xml - Spanish
*/
<string name="adapty_paywalls_locale">es</string>

/*
strings.xml - Portuguese (Brazil)
*/
<string name="adapty_paywalls_locale">pt-br</string>

// 2. Extract and use the locale code

val localeCode = context.getString(R.string.adapty_paywalls_locale)
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

Así te aseguras de tener un control total sobre qué localización se recuperará para cada usuario de tu app.

Implementar localizaciones: la otra forma

Puedes obtener resultados similares (aunque no idénticos) sin definir explícitamente códigos de idioma para cada localización. Esto implica extraer el código de idioma de otros objetos que proporciona tu plataforma, así:

val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
    context.resources.configuration.locales[0]
else
    context.resources.configuration.locale

val localeCode = locale.toLanguageTag()
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

Ten en cuenta que no recomendamos este enfoque, ya que es difícil predecir exactamente qué recibirá el servidor de Adapty.

Si decides utilizarlo de todas formas, asegúrate de haber cubierto todos los casos de uso relevantes.