Usar localizaciones y códigos de idioma en el SDK de Kotlin Multiplatform
Por qué esto es importante
Los códigos de idioma entran en juego cuando Adapty selecciona la localización para un flow 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 lo que Adapty se basa en un estándar interno único para todas las plataformas que admite. Entender ese estándar te ayuda a predecir qué localización recibirá un 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 está formado por 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
Cuando Adapty busca la localización que coincide con el idioma de un usuario, ocurre lo siguiente:
- La cadena de idioma se convierte a minúsculas y todos los guiones bajos (
_) se reemplazan por guiones (-) - Adapty busca la localización con el código de idioma exactamente coincidente
- Si no se encuentra ninguna coincidencia, Adapty toma la subcadena antes del primer guion (
ptparapt-br) y busca la localización correspondiente - Si tampoco se encuentra ninguna coincidencia, Adapty devuelve la localización predeterminada
en
De esta forma, 'pt_BR', pt-BR y pt-br se resuelven en la misma localización.
Implementación de localizaciones
En el SDK v4, no es necesario pasar un código de idioma al obtener un flow.
- Paywalls del Flow Builder y del Paywall Builder: Adapty resuelve la localización automáticamente a partir del dispositivo y las localizaciones que configuraste en el builder. Renderiza el flow con
createFlowView— no se necesita ningún código de idioma. - Paywalls personalizados (Remote Config):
getFlowdevuelve todas las localizaciones configuradas enflow.remoteConfigs. Cada entrada es unAdaptyRemoteConfigcon un códigolocaley undataMap. Selecciona la entrada que corresponda al usuario, con tu propio fallback:
Adapty.getFlow("YOUR_PLACEMENT_ID")
.onSuccess { flow ->
val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
?: flow.remoteConfigs.firstOrNull()
// read your values from config?.dataMap
}
.onError { error ->
// handle the error
}Las reglas de coincidencia de códigos de idioma descritas anteriormente explican cómo Adapty normaliza los códigos locale almacenados en cada Remote Config.
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 complicados 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 exactamente qué le estás enviando a nuestro servidor para obtener la localización correcta y qué ocurre después — así siempre recibirás 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ódigos de idioma
Cuando Adapty recibe una llamada del SDK con el código de idioma y empieza a buscar la localización correspondiente de un paywall, ocurre lo siguiente:
- La cadena de idioma recibida se convierte a minúsculas y todos los guiones bajos (
_) se reemplazan por guiones (-) - Se busca la localización cuyo código de idioma coincida exactamente
- Si no se encuentra ninguna coincidencia, se toma la subcadena antes del primer guión (
pten el caso dept-br) y se busca la localización correspondiente - Si tampoco se encuentra coincidencia, se devuelve la localización predeterminada
enDe este modo, un dispositivo iOS que envió'pt_BR', un dispositivo Android que enviópt-BR, y otro dispositivo que enviópt-brobtendrán el mismo resultado.
Implementación de localizaciones: forma recomendada
Si te estás preguntando sobre las localizaciones, lo más probable es que ya estés gestionando recursos de cadenas localizadas en tu proyecto. Si ese es el caso, te recomendamos incluir un par clave-valor con el código de locale de Adapty correspondiente en cada uno de tus archivos de recursos para las localizaciones que uses. Luego, extrae el valor de esa clave al llamar a nuestro SDK, así:
// 1. Add the Adapty locale code to your Compose Multiplatform resources
/*
composeResources/values/strings.xml (default — English)
*/
<string name="adapty_paywalls_locale">en</string>
/*
composeResources/values-es/strings.xml (Spanish)
*/
<string name="adapty_paywalls_locale">es</string>
/*
composeResources/values-pt-rBR/strings.xml (Portuguese — Brazil)
*/
<string name="adapty_paywalls_locale">pt-br</string>
// 2. Extract and use the locale code
suspend fun fetchPaywall() {
val locale = getString(Res.string.adapty_paywalls_locale)
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = locale
).onSuccess { paywall ->
// el paywall solicitado
}.onError { error ->
// gestionar el error
}
}De este modo, tienes control total sobre qué localización se recuperará para cada usuario de tu app.
Si no usas recursos de Compose Multiplatform, la misma idea aplica a cualquier biblioteca de localización que uses (por ejemplo, moko-resources): guarda el código de idioma de Adapty como una cadena en el bundle de recursos de cada idioma y léelo antes de llamar al SDK.
Otra forma de implementar las localizaciones
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 directamente del dispositivo, lo que requiere declaraciones expect/actual, ya que no existe una API de idioma compartida en commonMain:
// commonMain
expect fun currentLocaleTag(): String
// androidMain
actual fun currentLocaleTag(): String = Locale.getDefault().toLanguageTag()
// iosMain
actual fun currentLocaleTag(): String = NSLocale.currentLocale.localeIdentifier
// commonMain — pass the locale code to Adapty
suspend fun fetchPaywall() {
Adapty.getPaywall(
placementId = "YOUR_PLACEMENT_ID",
locale = currentLocaleTag()
).onSuccess { paywall ->
// the requested paywall
}.onError { error ->
// handle the error
}
}Ten en cuenta que no recomendamos este enfoque por varias razones:
- En iOS, el idioma preferido del usuario y el locale regional del dispositivo no son idénticos.
NSLocale.currentLocale.localeIdentifierdevuelve el locale regional, que puede diferir del idioma en que los usuarios leen tu app. Las apps iOS que usan archivos de cadenas localizadas dependen de la lógica de resolución de Apple para combinar ambos, lo que funciona de forma automática con el enfoque recomendado anteriormente. - Es difícil predecir exactamente qué devolverá el dispositivo y si coincide con una localización de Adapty. El locale del dispositivo puede incluir extensiones o códigos regionales que no hayas configurado en Adapty; en ese caso, el SDK recurre a la coincidencia del primer subtag o, en último término, a
en. Should you decide to use this approach anyway — make sure you’ve covered all the relevant use cases.