AI Real-Time Text Translation in Mobile Applications
Переклад «в реальному часі» означає різне залежно від сценарію. Для чата — відправити сообщение та отримати переклад за 200–400 мс, непомітно для користувача. Для текстового поля з live-перекладом — реагувати на кожні N символів без спаму запитами. Для документа — пакет з прогрес-баром. Кожен сценарій потребує своєї архітектури.
Три варіанти стека та коли що вибирати
Google Translate API (Cloud Translation v3) — стандарт для продакшену. Підтримує 130+ мов, нейросетевий переклад (NMT), формальні/неформальні регістри для ряду мов. REST або gRPC. Для мобільного клієнта — REST через HTTPS, ключ приховуємо за власний бекенд.
DeepL API — найкраще якість для європейських мов, особливо німецької, французької, польської. Для російської — зіставимо з Google. Ліміт Free-плану 500K символів/місяць.
On-device: ML Kit Translate — Google ML Kit з локальними моделями. Модель ~15 МБ на мовну пару, скачується один раз. Повний офлайн, нульова затримка мережі, але якість менша за cloud-версії. Підтримує 58 мов. Підходить для мессенджерів з офлайн-вимогами.
Debounce та управління запитами
Головна помилка live-перекладу — відправляти запрос на кожне натиснення клавіші. На швидкості печаті 200 символів/хвилину це 3–4 запити в секунду, з яких 90% уйдуть у мусор до відповіді.
Правильний паттерн на iOS (Combine):
@Published var inputText: String = ""
inputText
.publisher
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.removeDuplicates()
.filter { $0.count >= 3 }
.flatMap(maxPublishers: .max(1)) { [weak self] text -> AnyPublisher<String, Never> in
guard let self else { return Empty().eraseToAnyPublisher() }
return self.translationService.translate(text)
.replaceError(with: "")
.eraseToAnyPublisher()
}
.receive(on: RunLoop.main)
.assign(to: &$translatedText)
.flatMap(maxPublishers: .max(1)) — ключовий момент. Це switchMap: при новому вводі скасовує попередній незавершений запрос. Без цього старі відповіді можуть прийти пізніше нових та перезаписати актуальний переклад.
На Android з Kotlin Flow:
val translatedText: StateFlow<String> = inputText
.debounce(500)
.filter { it.length >= 3 }
.distinctUntilChanged()
.flatMapLatest { text ->
flow { emit(translationRepo.translate(text)) }
.catch { emit("") }
}
.stateIn(viewModelScope, SharingStarted.Lazily, "")
flatMapLatest — еквівалент switchMap, скасовує попередній coroutine.
Інтеграція з Google Cloud Translation v3
suspend fun translate(text: String, targetLang: String = "ru"): String {
val body = JSONObject().apply {
put("q", text)
put("target", targetLang)
put("format", "text")
}
val response = httpClient.post("https://translation.googleapis.com/language/translate/v2") {
header("Authorization", "Bearer $accessToken")
contentType(ContentType.Application.Json)
setBody(body.toString())
}
return response.body<TranslationResponse>().data.translations[0].translatedText
}
Для access_token у продакшені — сервісний аккаунт GCP, JWT-підпис на бекенді. Мобільний клієнт отримує краткосрочний токен через власний /api/translate-token endpoint. API-ключ GCP в APK/IPA — ні.
ML Kit для офлайн-сценаріїв
// iOS: Google ML Kit Translate
let options = TranslatorOptions(sourceLanguage: .english, targetLanguage: .russian)
let translator = Translator.translator(options: options)
translator.downloadModelIfNeeded { error in
guard error == nil else { return }
translator.translate("Hello world") { result, error in
print(result ?? "")
}
}
Модель скачується один раз через Wi-Fi (бажано). Далі — робота без мережі. Затримка на пристрої — 20–50 мс на фразу. Ідеально для мессенджерів, субтитрів у офлайн-відео, туристичних додатків.
Кешування перекладів
Повторні запити одного та того ж тексту — деньги в мусор. Кеш на рівні SQLite (Room/CoreData) з ключем sha256(source_text + target_lang). TTL 7 днів для звичайного контенту, без TTL для статичних строк UI.
На рівні HTTP — Cache-Control для GET-запитів. Google Translate підтримує GET з параметрами, що дозволяє кешувати на рівні URLCache / OkHttp Cache.
Приклад з практики
В додатку для медичного туризму (iOS + Android) перекладали описи клінік та відгуки пацієнтів (en→ru, ru→en, de→ru). Cloud-переклад для контенту при завантаженні, ML Kit офлайн для інтерфейсу консультації. Debounce 700 мс для поискової строки. Кеш перекладу в Room знизив кількість API-запитів на 73% в течение першого тижня після запуску.
Сроки
Базова інтеграція одного провайдера з debounce — 3–5 днів. Додавання ML Kit офлайн, кешу, автодетекції мови — ще 4–6 днів. Обробка форматованого тексту (HTML, Markdown) — окрема задача.







