Launch your app in English, let Gemini translate it into 100+ languages for global reach.

5 min readMar 23, 2025

Written by Georgios Soloupis, AI and Android GDE.

This image shows a logo of the Gemini model.
Logo

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.

This is an image an android app showing how the file system is structured to handle the different languages. In this example we see a folder in english and a lot of folders below where each one is responsible to handle translations for different languages.
Typical structure of string.xml file folders inside android.

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.

This is a screenshot of the mobile app showing a dialog asking the user to select their preferred language.
Zolup app screenshot.

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!

This is a screenshot of the app that is demonstrated in this article showing the menu that has already been translated in greek language.
Menu of Zolup app.

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

  1. Jetpack Compose - The UI framework used for building the app.
  2. Firebase APIs - Backend services supporting AI integration.
  3. Vertex AI - Encapsulates the Gemini 2.0 Flash model for AI-powered text generation.
  4. JSON Schema & Structured Output - Ensures translations are formatted correctly for Android.
  5. LiveData & ViewModel - Manages app state and updates translations dynamically.
  6. Internal Storage - Stores translated strings for quick access and offline use.

How Translation Works

  1. User selects a language during onboarding.
  2. The Gemini API generates translations in structured JSON format.
  3. The app parses the JSON, extracts the translated strings, and saves them internally.
  4. 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.

--

--

Georgios Soloupis
Georgios Soloupis

Written by Georgios Soloupis

Pharmacist turned Android and AI Google Developer Expert. Right now I am rocking with Envision and working on accessibility at the Zolup browser.

No responses yet