# ML Kit 离线 OCR + 翻译：做一个无需联网的“拍照翻译”App（一次下载，离线可用）

[TOC]

> 本文首发地址 <https://h89.cn/archives/440.html>  

## 一、背景与目标
- 目标：做一个“拍照翻译”App，在弱网/无网环境下也能工作。离线识别图片中的中文/英文等文字，并把识别结果翻译成中文。
- 方案：
  - 使用 Google ML Kit Text Recognition v2 实现离线 OCR（中文优先，Latin 回退）。
  - 使用 ML Kit On‑device Translation 实现离线翻译（首次联网下载语言包，下载完成后完全离线）。

## 二、技术选型与依赖
- 离线 OCR（中文 + Latin）：ML Kit Text Recognition v2。
- 设备端翻译：ML Kit Translate（On‑device Translation）。
- 语言识别：ML Kit Language Identification（自动识别待翻译文本源语言）。

工程中关键依赖（app/build.gradle）：
```gradle
dependencies {
    // ML Kit Text Recognition v2（Latin + Chinese）
    implementation 'com.google.mlkit:text-recognition:16.0.1'
    implementation 'com.google.mlkit:text-recognition-chinese:16.0.1'

    // On‑device Translation
    implementation 'com.google.mlkit:translate:17.0.3'

    // Language Identification
    implementation 'com.google.mlkit:language-id:17.0.6'

    // CameraX（相机/拍照）
    implementation 'androidx.camera:camera-core:1.3.4'
    implementation 'androidx.camera:camera-camera2:1.3.4'
    implementation 'androidx.camera:camera-lifecycle:1.3.4'
    implementation 'androidx.camera:camera-view:1.3.4'
}
```

## 三、项目结构与关键文件
- GitHub 仓库：[mlkit-offline-ocr-translate](https://github.com/chenjim/mlkit-offline-ocr-translate)
- 关键文件：
  - 工程与模块配置：
    - [settings.gradle](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/settings.gradle)
    - [build.gradle（Project）](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/build.gradle)
    - [app/build.gradle](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/app/build.gradle)
  - 清单/资源：
    - [AndroidManifest.xml](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/app/src/main/AndroidManifest.xml)
    - [activity_main.xml](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/app/src/main/res/layout/activity_main.xml)
  - 核心代码：
    - [MainActivity.kt](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/app/src/main/java/com/example/mlkitocr/MainActivity.kt)

## 四、功能实现概览（拍照 + OCR + 翻译）
- UI：CameraX 预览 + 两个按钮（拍照识别、相册选图）+ 两个文本区域（OCR 结果、翻译结果）。
- 主流程：
  1) 打开相机 → 拍照保存到缓存 → 使用 ML Kit OCR 识别文字（优先中文，失败回退 Latin）。
  2) 自动语言识别（Language Identification），将识别文本映射到翻译源语言。
  3) 使用设备端翻译，将文本翻译为中文（首次会下载模型，之后可完全离线）。
  4) 识别与翻译结果在页面底部实时显示。

核心实现位于 [MainActivity.kt](https://github.com/chenjim/mlkit-offline-ocr-translate/blob/main/app/src/main/java/com/example/mlkitocr/MainActivity.kt)：
```kotlin
// 1) 识别（优先中文，回退 Latin）
private fun recognizeText(image: InputImage) {
    val zh = TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
    zh.process(image)
        .addOnSuccessListener { text ->
            val raw = text.text
            if (raw.isNotBlank()) {
                tvOcr.text = raw
                autoDetectAndTranslate(raw)
            } else {
                recognizeLatin(image)
            }
        }
        .addOnFailureListener { recognizeLatin(image) }
}

private fun recognizeLatin(image: InputImage) {
    val latin = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
    latin.process(image)
        .addOnSuccessListener { text ->
            val raw = text.text
            tvOcr.text = raw
            autoDetectAndTranslate(raw)
        }
        .addOnFailureListener { e -> toast("OCR 失败: ${e.message}") }
}

// 2) 自动语言识别 + 3) 设备端翻译（首次下载模型，之后离线）
private fun autoDetectAndTranslate(text: String) {
    if (text.isBlank()) return
    val identifier = languageIdentifier ?: return
    identifier.identifyLanguage(text)
        .addOnSuccessListener { code ->
            val source = if (code == "und") TranslateLanguage.CHINESE else mapLang(code)
            val target = TranslateLanguage.CHINESE
            setupTranslatorAndTranslate(source, target, text)
        }
        .addOnFailureListener {
            setupTranslatorAndTranslate(TranslateLanguage.ENGLISH, TranslateLanguage.CHINESE, text)
        }
}

private fun setupTranslatorAndTranslate(source: String, target: String, text: String) {
    translator?.close()
    val options = TranslatorOptions.Builder()
        .setSourceLanguage(source)
        .setTargetLanguage(target)
        .build()
    translator = Translation.getClient(options)

    val conditions = DownloadConditions.Builder().build()
    translator!!.downloadModelIfNeeded(conditions)
        .addOnSuccessListener {
            translator!!.translate(text)
                .addOnSuccessListener { out -> tvTrans.text = out }
                .addOnFailureListener { e -> toast("翻译失败: ${e.message}") }
        }
        .addOnFailureListener { e ->
            toast("翻译模型下载失败（需联网一次）: ${e.message}")
        }
}
```

## 五、为什么能“离线”？
- OCR：Text Recognition v2 随 App 打包模型，识别完全在设备端执行，不依赖网络。
- 翻译：On‑device Translation 在首次联网下载语言包后，翻译过程在设备端执行，不上传文本，可离线运行。
- 自动识别语言：Language Identification 可随 App 打包使用，设备端执行。

## 六、本地运行与安装

### 克隆项目
```bash
git clone https://github.com/chenjim/mlkit-offline-ocr-translate.git
cd mlkit-offline-ocr-translate
```

### 构建与安装
- 用 Android Studio 直接打开项目，等待依赖同步完成。
- 连接真机（建议 Android 8.0+），开启 USB 调试。
- 运行方式：
  - Android Studio 直接 Run 'app'。
  - 或在终端执行（推荐）：
    - Windows：`.\gradlew.bat installDebug`
    - macOS/Linux：`./gradlew installDebug`
- 首次使用翻译功能时会自动下载翻译模型，下载完成后即可离线翻译。

## 七、项目特色与技术亮点

### 离线优先设计
- **OCR 模型**：Text Recognition v2 模型随应用打包，无需网络即可识别文字。
- **翻译模型**：首次联网下载后，完全在设备端执行翻译，保护用户隐私。
- **语言识别**：自动检测文本语言，智能选择翻译源语言。

### 技术实现细节
- **中文优先策略**：优先使用中文 OCR 模型，识别失败时自动回退到 Latin 模型。
- **资源管理**：合理管理翻译器生命周期，避免内存泄漏。
- **错误处理**：完善的异常处理机制，提供用户友好的错误提示。

### 项目源码
完整源码已开源至 GitHub：[mlkit-offline-ocr-translate](https://github.com/chenjim/mlkit-offline-ocr-translate)

体验 [APK地址](https://github.com/chenjim/mlkit-offline-ocr-translate/raw/refs/heads/main/apk/app-debug.apk)

## 八、常见问题（FAQ）
- 真能“完全离线”吗？
  - OCR：可以，模型随 App 打包。
  - 翻译：首次需联网下载语言包，下载完成后可完全离线使用。
- 如何更换翻译目标语言？
  - 在 `setupTranslatorAndTranslate()` 中将 `target` 更改为 `TranslateLanguage.XXXX` 即可。
- 能否限制仅 Wi‑Fi 下载翻译模型？
  - 可以，将 `DownloadConditions.Builder().requireWifi()`。
- 模型体积会很大吗？
  - OCR 模型随应用体积增加；翻译模型按需下载并按语言存储在设备端，体积视语言而定。

## 九、结语
本文以最小可用实现构建了“拍照翻译”离线 App：拍照/选图 → OCR（中文优先）→ 自动识别语言 → 设备端翻译为中文。首次联网下载翻译模型后，即可在无网环境稳定工作。将工程推送到你的 GitHub 仓库（如：`github.com/chenjim/mlkit-offline-ocr-translate`），即可在博客中引用源码细节，方便读者学习与复现。