
Guía completa para localizar aplicaciones Android
Desde strings.xml hasta los metadatos de Play Store: localice su aplicación Android con Kotlin, Jetpack Compose, Fastlane y traducción automatizada mediante IA.
Preparar su proyecto Android para la localización
Android utiliza una convención basada en carpetas para la localización. Las cadenas predeterminadas residen en res/values/strings.xml y las traducidas van en carpetas específicas, como res/values-de/ o res/values-ja/.
// Android project structure for localization:
// res/
// ├── values/ ← Default (fallback) locale
// │ └── strings.xml
// ├── values-de/ ← German
// │ └── strings.xml
// ├── values-ja/ ← Japanese
// │ └── strings.xml
// └── values-es/ ← Spanish
// └── strings.xml
//
// Folder naming: values-{language} or values-{language}-r{Region}
// Examples: values-pt-rBR, values-zh-rCN, values-zh-rTWCrear strings.xml
Los recursos de cadenas de Android utilizan XML con elementos '<string>' dentro de una raíz '<resources>'. Utilice %s para marcadores de cadenas, %d para enteros y %1$s/%2$s para argumentos posicionales que los traductores puedan reordenar.
<!-- res/values/strings.xml -->
<resources>
<string name="welcome_title">Welcome to MyApp</string>
<string name="login_button">Sign In</string>
<string name="settings_label">Settings</string>
<string name="greeting">Hello, %s!</string> <!-- %s = string -->
<string name="item_count">%d items</string> <!-- %d = integer -->
<string name="app_name" translatable="false">MyApp</string>
</resources><!-- ❌ Common mistakes in strings.xml: -->
<!-- Unescaped apostrophe — crashes XML parser silently -->
<string name="message">It's a great day</string>
<!-- Missing from default values/strings.xml — app crashes -->
<!-- (only exists in values-de/strings.xml) -->
<!-- ✅ Correct versions: -->
<string name="message">It\'s a great day</string>
<!-- Or wrap in double quotes: -->
<string name="message">"It's a great day"</string>Gestionar plurales
Android utiliza elementos '<plurals>' con atributos quantity: zero, one, two, few, many y other. Cada idioma de destino puede necesitar categorías distintas: el árabe utiliza las 6, el ruso necesita few/many y el japonés solo utiliza other.
<!-- res/values/strings.xml -->
<resources>
<plurals name="items_count">
<item quantity="zero">No items</item>
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals>
</resources>
<!-- Usage in Kotlin: -->
<!-- val text = resources.getQuantityString(
R.plurals.items_count,
count, // selects plural form
count // format argument
) -->Utilizarlo en el código: Kotlin y Jetpack Compose
Android tradicional utiliza getString(R.string.key) y resources.getQuantityString(). Jetpack Compose utiliza stringResource(R.string.key) y pluralStringResource(). Ambos resuelven durante la ejecución la traducción correcta según la configuración regional del dispositivo.
// Traditional Android (Activity/Fragment)
val title = getString(R.string.welcome_title)
val greeting = getString(R.string.greeting, userName)
val items = resources.getQuantityString(
R.plurals.items_count, count, count
)
// Jetpack Compose
@Composable
fun WelcomeScreen(userName: String, itemCount: Int) {
// ✅ stringResource — Compose-aware, triggers recomposition
Text(text = stringResource(R.string.welcome_title))
// ✅ With format arguments
Text(text = stringResource(R.string.greeting, userName))
// ✅ Plurals — count passed TWICE
Text(text = pluralStringResource(
R.plurals.items_count,
itemCount, // selects plural form
itemCount // format argument
))
}Matrices de cadenas y cadenas con formato
Utilice '<string-array>' para listas ordenadas —por ejemplo, opciones de desplegables o pasos de incorporación—. Use argumentos de formato posicionales (%1$s, %2$d) en las cadenas con formato para que los traductores puedan reordenar las palabras sin romper la estructura de la frase.
<!-- res/values/strings.xml -->
<resources>
<!-- String array for dropdown/list -->
<string-array name="sort_options">
<item>Most Recent</item>
<item>Most Popular</item>
<item>Price: Low to High</item>
<item>Price: High to Low</item>
</string-array>
<!-- Positional format args for reordering -->
<string name="welcome_message">
Hello %1$s, you have %2$d new messages
</string>
<!-- Translators can reorder: -->
<!-- %2$d neue Nachrichten für %1$s -->
</resources>Localizar los metadatos de Google Play con Fastlane
Utilice el comando supply de Fastlane para gestionar los metadatos de Play Store —título, descripción breve, descripción completa y registros de cambios— como archivos de texto sin formato organizados por configuración regional en su repositorio.
# Install Fastlane
$ gem install fastlane
# Initialize supply for Play Store metadata
$ fastlane supply init
# Directory structure created:
# fastlane/metadata/android/
# ├── en-US/
# │ ├── title.txt # App name (50 chars)
# │ ├── short_description.txt # Short desc (80 chars)
# │ ├── full_description.txt # Full desc (4000 chars)
# │ └── changelogs/
# │ └── default.txt # What's New
# ├── de-DE/
# │ └── ...
# └── ja-JP/
# └── ...
# Push metadata to Play Store:
$ fastlane supplyAutomatice la localización de su ficha de Play Store
Evite copiar y pegar manualmente. Traduzca el título, la descripción y las notas de la versión de Play Store a más de 175 configuraciones regionales teniendo en cuenta los límites de caracteres.
Explorar la integración con Google PlayProbar su localización
Realice pruebas cambiando la configuración regional del emulador, con vistas previas de Compose que utilicen una LocaleList personalizada y con pseudoconfiguraciones regionales en Opciones para desarrolladores. Utilice resConfigs en Gradle para eliminar los recursos regionales no deseados de bibliotecas de terceros.
// 1. Emulator: Settings > System > Language > Add language
// 2. Compose Preview with locale:
@Preview
@Composable
fun WelcomePreview() {
val config = Configuration(resources.configuration).apply {
setLocale(Locale("de"))
}
val localContext = LocalContext.current
val localizedContext = localContext.createConfigurationContext(config)
CompositionLocalProvider(
LocalContext provides localizedContext
) {
WelcomeScreen()
}
}
// 3. Restrict library locales in build.gradle.kts:
android {
defaultConfig {
// Only include locales you actually translate
resourceConfigurations += listOf("en", "de", "ja", "es", "fr")
}
}
// 4. Enable pseudolocales in Developer Options:
// en-XA (accented) — detects hardcoded strings
// ar-XB (RTL) — tests layout mirroringAutomatizar la calidad de la traducción
Automatizar traducciones
Traduzca strings.xml, plurales, matrices de cadenas y metadatos de Fastlane Supply con IA. Automatice tanto las cadenas de la aplicación como los metadatos de Play Store para ofrecer una presencia completamente localizada.
# Translate strings.xml files
> Translate res/values/strings.xml
to Japanese, German, and Spanish
# Translate Play Store metadata too
> Translate fastlane/metadata/android/en-US/
to de-DE, ja-JP, es-ES
✓ 6 files translated in 3.2sPlugin para Android Studio disponible
Traduzca recursos XML de Android directamente desde su IDE con el plugin de i18n Agent para IntelliJ / Android Studio.
Extra: respaldo inteligente de configuraciones regionales con LocaleChain
El respaldo de recursos de Android está controlado por el sistema operativo. Cuando faltan traducciones pt-BR, Android omite por completo pt-PT y muestra inglés. LocaleChain intercepta las búsquedas de cadenas y recorre una cadena de respaldo configurable, de modo que los usuarios regionales ven la traducción disponible más próxima.
LocaleChain para Android es una biblioteca Kotlin de código abierto. Ver en GitHub
// build.gradle.kts (app module)
dependencies {
implementation("com.i18nagent:locale-chain-android:0.1.0")
}// 1. Application.onCreate() — configure chains once
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
LocaleChain.configure()
}
}
// 2. BaseActivity — wrap context per Activity
open class BaseActivity : AppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleChain.wrap(newBase))
}
}
// pt-BR user with only pt-PT translations?
// → Shows Portuguese instead of falling back to English
// Custom overrides for your specific locales:
LocaleChain.configure(
overrides = mapOf("es-MX" to listOf("es-419", "es"))
)Errores habituales
La ausencia de cadenas predeterminadas provoca bloqueos
La división por idiomas de App Bundle rompe el cambio dentro de la aplicación
Los diseños RTL se rompen
Contaminación de recursos de bibliotecas
Estructura de archivos recomendada
MyApp/
├── app/
│ └── src/main/
│ ├── res/
│ │ ├── values/
│ │ │ ├── strings.xml # Default (source) strings
│ │ │ └── plurals.xml # Plural rules
│ │ ├── values-de/
│ │ │ └── strings.xml
│ │ ├── values-ja/
│ │ │ └── strings.xml
│ │ └── values-es/
│ │ └── strings.xml
│ ├── java/com/example/myapp/
│ └── AndroidManifest.xml
├── fastlane/
│ └── metadata/android/
│ ├── en-US/
│ │ ├── title.txt
│ │ ├── short_description.txt
│ │ ├── full_description.txt
│ │ └── changelogs/default.txt
│ ├── de-DE/
│ └── ja-JP/
├── build.gradle.kts
└── settings.gradle.ktsTambién puede traducir:
Pruebe i18n Agent ahora
Arrastre y suelte aquí su archivo de traducción
JSON, YAML, PO, XML, CSV, Markdown, Properties
o haga clic para seleccionar
Idiomas de destino
Respaldo de configuraciones regionales con locale-chain-android
Cuando falta una clave de traducción en una configuración regional como pt-BR, Android pasa directamente a la carpeta de recursos predeterminada en vez de comprobar primero la configuración principal pt.
implementation("com.i18nagent:locale-chain-android:0.1.0")import com.i18nagent.localechain.LocaleChain
LocaleChain.configure(
overrides = mapOf(
"pt-BR" to listOf("pt", "en"),
"zh-Hant-HK" to listOf("zh-Hant", "zh", "en"),
)
)Consulte nuestra guía de respaldo de configuraciones regionales para ver todos los frameworks admitidos y las 75 cadenas integradas. Learn more →