Launch your app in English, let Gemini translate it into 100+ languages for global reach.
Written by Georgios Soloupis, AI and Android GDE.
Managing translations in a mobile app can be challenging, especially with frequent updates, evolving instructions, and support for multiple languages. Traditional translation methods require constant manual updates, slowing down development and increasing costs. AI-powered solutions like Gemini eliminate this hassle by translating content during onboarding, ensuring that every update, instruction, or new feature is instantly available in 100+ languages. With Gemini, user guidance remain seamless across different regions, allowing developers to focus on innovation while AI handles accurate, up-to-date translations effortlessly.
In Android, translations are managed using string resources stored in XML files within the res/values
directory. Each language has its own strings.xml
file inside a language-specific folder (e.g., res/values-fr/
for French). The system determines the appropriate language using the LocaleManager, which checks the device's locale settings and loads the corresponding resource files. Adding a new language requires creating a new values
folder with the appropriate language code and translating all necessary strings. However, maintaining multiple translations can be challenging and if a string value changes, developers must update it across all language-specific XML files manually. This process is time-consuming and prone to inconsistencies, especially for frequently updated apps with evolving content.
Proposed solution: Launch your app in English and let Gemini automatically translate content during user onboarding. This can be achieved with the structured output Gemini offers.
By default, the API returns responses as unstructured text. However, some scenarios require structured formats like JSON. For example, if you’re building a chatbot that extracts user preferences, a structured JSON response ensures seamless integration with downstream systems that rely on a predefined data schema. This can be also handy in mobile apps!
Example: We will showcase the Zolup browser android app, designed with accessibility in mind. Since version 30.0, the app has been uploaded to Google Play exclusively in English. However, during onboarding, users can choose from over 100 languages supported by Gemini.
When users select their preferred language, Gemini Flash 2.0 translates the app’s strings and stores them in internal memory. Within seconds, the entire app is seamlessly displayed in the chosen language.
Code: Let’s take a closer look at the code to see what’s happening behind the scenes.
Zolup Browser is built with accessibility at its core and fully developed using Jetpack Compose. It leverages various Firebase APIs, including Vertex AI, which powers the app with the Gemini 2.0 Flash model for seamless AI-driven experiences.
First we have to define the JSON schema that we are expecting from the model.
private val jsonSchema = Schema.obj(
mapOf(
"with_certificate_info" to Schema.string(),
"no_certificate" to Schema.string(),
"no_certificate_info" to Schema.string(),
"tap_to_share" to Schema.string(),
"tap_to_hear_the_summary" to Schema.string(),
.....
)
Then we need to initialize the Vertex AI service and the generative model.
val generativeModel = Firebase.vertexAI.generativeModel(
modelName = "gemini-2.0-flash",
// In the generation config, set the `responseMimeType` to `application/json`
// and pass the JSON schema object into `responseSchema`.
generationConfig = generationConfig {
responseMimeType = "application/json"
responseSchema = jsonSchema
})
After that, we create the prompt that is holding the english strings we want to translate also in a JSON format.
private fun createEnglishStringsJsonObject(): JSONObject {
val jsonObject = JSONObject()
jsonObject.put(
"with_certificate_info",
context.getString(R.string.with_certificate_info)
)
jsonObject.put(
"no_certificate",
context.getString(R.string.no_certificate)
)
jsonObject.put(
"no_certificate_info",
context.getString(R.string.no_certificate_info)
)
jsonObject.put("tap_to_share", context.getString(R.string.tap_to_share))
jsonObject.put(
"tap_to_hear_the_summary",
context.getString(R.string.tap_to_hear_the_summary)
)
...
return jsonObject
}
fun generateTranslation(request: String) {
viewModelScope.launch {
_appIsTranslated.value = AppTranslation.Translatting
val jsonObject = createEnglishStringsJsonObject()
val prompt =
"Translate the following English strings to $request language. Keep the formatting so I can use them inside android. Respond with a JSON object. Use the same keys as in the input." +
"Input JSON: $jsonObject"
try {
val response = generativeModel.generateContent(prompt)
val translatedJsonObject = JSONObject(response.text ?: "{}")
Helper.saveTranslationStrings(
context,
translatedJsonObject.toString()
)
// Update live data to render everything inside app.
updateStringsLiveData()
_appIsTranslated.value = AppTranslation.Success
} catch (e: Exception) {
_appIsTranslated.value = AppTranslation.Failure(e.message ?: "")
}
}
}
IMPORTANT: The prompt contains ALL the strings! That results in the generation of more accurate and nuanced translations!
The response from the model is delivered in JSON and then we populate an object with that information.
@Keep
data class StringResources(
val with_certificate_info: String,
val no_certificate: String,
val no_certificate_info: String,
val tap_to_share: String,
val tap_to_hear_the_summary: String,
...
)
private fun updateStringsLiveData() {
try {
val retrievedJson = Helper.loadTranslationStrings(context)
updateRetrievedStringResources(retrievedJson.let {
Gson().fromJson(
it,
StringResources::class.java
)
})
} catch (e: Exception) {
...
}
}
Immediately the app uses the newest translations!
Want to give it a try? Here’s the link to the Zolup app, which uses Gemini to seamlessly translate this Android application.
Overview
The Zolup Browser was developed with accessibility in mind and fully built using Jetpack Compose. It leverages Firebase APIs and Vertex AI, which integrates the Gemini 2.0 Flash model to provide seamless, real-time language translation. Instead of manually handling multiple localized string files, the app ships only in English and translates dynamically during onboarding, allowing users to experience the interface in their preferred language.
Key APIs & Components
- Jetpack Compose - The UI framework used for building the app.
- Firebase APIs - Backend services supporting AI integration.
- Vertex AI - Encapsulates the Gemini 2.0 Flash model for AI-powered text generation.
- JSON Schema & Structured Output - Ensures translations are formatted correctly for Android.
- LiveData & ViewModel - Manages app state and updates translations dynamically.
- Internal Storage - Stores translated strings for quick access and offline use.
How Translation Works
- User selects a language during onboarding.
- The Gemini API generates translations in structured JSON format.
- The app parses the JSON, extracts the translated strings, and saves them internally.
- The UI updates in real-time using LiveData to reflect the new language.
Benefits of This Approach
- No need for pre-translated XML files, reducing maintenance overhead.
- Automatic updates, new app features or UI changes are translated upon onboarding or app version update.
- Supports 100+ languages without manual effort.
- Faster localization compared to traditional static translation methods.
- Translations are generated with the context of all strings’ data as all these information are sent to Gemini in a unified JSON string object. That results in more accurate and nuanced translations.
- Reach more audience worldwide.
Conclusion
By leveraging Gemini 2.0 Flash, Firebase, and Jetpack Compose, Zolup browser app that was created with accessibility in mind delivers a seamless, AI-powered translation experience that simplifies multilingual support in Android apps. Instead of maintaining multiple language files, translations happen dynamically, ensuring an up-to-date, accessible experience for users worldwide.