Skip to content

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lingvanex Offline Translation SDK for iOS & macOS

platform architecture SPM license

On-device machine translation with no network connection and no data leaving the device. Powered by an int8-quantized neural engine built on CTranslate2.

  • Fully offline — translation runs on device; nothing is sent anywhere.
  • Fast — int8 inference with hand-tuned NEON kernels on Apple Silicon and modern iPhones.
  • Private — no tracking, no analytics, no data collection (see PrivacyInfo.xcprivacy).
  • Any-to-any translation — language pairs pivot through English automatically.

Requirements

  • iOS 13+ / macOS 10.15+
  • Xcode 14+
  • A language pack (see Language packs)

Installation

Swift Package Manager

In Xcode: File → Add Package Dependencies… and enter:

https://github.com/lingvanex-mt/offline-translation-apple-sdk

Select Up to Next Major Version starting from 3.1.0.

Or in Package.swift:

dependencies: [
    .package(url: "https://github.com/lingvanex-mt/offline-translation-apple-sdk", from: "3.1.0")
]

Language packs

Translation models ship separately as .zip language packs (one pack per language, each translates to and from English; English itself is built in).

High-quality offline models are available for 110 languages. To request a demo pack for the languages you need, write to info@lingvanex.com.

A sample Portuguese pack (English ↔ Portuguese, 87 MB) is ready to try right away: download pt.zip. Drag it into your project (Copy If Needed + your target checked) — the Example/ apps expect exactly that.

Both directions come from our current mobile model generation (46.9 MB each, int8). Measured through this SDK on FLORES-200 devtest, 1012 sentences, beam 2, Apple M1 Pro:

English → Portuguese Portuguese → English
BLEU 52.31 47.27
chrF2 71.56 69.45
COMET-DA 0.899 0.886
Speed 78 ms/sentence 77 ms/sentence

Quick start

Works out of the box with the sample Portuguese pack added to your project as pt.zip:

import OfflineTranslator

// 1. Install a language pack bundled with your app. Installation happens once per
//    `version`: every launch after the first reports `versionAlreadyInstalled`,
//    which means "already on disk" — log it and carry on, do not bail out.
PackageManager.install(id: "pt", zip: "pt", version: "1.0.0") { error in // bump `version` to reinstall an updated pack
    if let error = error {
        print("Install: \(error.localizedDescription)")
    }

    // 2. Pick the language pair. English is built in — use .english for it.
    //    A missing package is the failure that matters here: with no pair loaded
    //    the translator hands your input straight back (see Translator below).
    guard let pt = PackageManager.packageWithId("pt") else {
        print("Portuguese pack is not installed")
        return
    }
    try? Translator.shared.setup(fromPackage: .english, toPackage: pt)

    // 3. Translate.
    Translator.shared.translateWithString("Hello world! How are you today?") { result in
        switch result {
        case .success(let translation):
            print(translation) // "Olá mundo! Como estás hoje?"
        case .failure(let error):
            print("Translate error: \(error)")
        }
    }
}

Packs can also be downloaded by your app at runtime — fetch the zip with URLSession and pass its file path to PackageManager.install(id:path:version:). That call deletes the zip once it has been installed, so pass a downloaded temporary file, not a file you still need.

Non-English pairs work the same way — the SDK pivots through English internally:

guard
    let de = PackageManager.packageWithId("de"),
    let pt = PackageManager.packageWithId("pt")
else { return }
try? Translator.shared.setup(fromPackage: de, toPackage: pt)

Where packs are stored

Installed packs are unpacked into the caches directory, under Packages. Two consequences are worth planning for:

  • iOS may evict the caches directory when the device runs low on storage, taking installed packs with it. Ask packageWithId(_:) on every launch rather than remembering "installed" in your own settings, and reinstall if the pack is gone.
  • A non-sandboxed macOS app shares ~/Library/Caches/Packages with every other non-sandboxed app on the machine, so PackageManager.installed can return packs your app never installed. Filter it by the ids you ship — the Example/ apps do exactly that. Sandboxed apps (including the macOS demo) get their own container and see only their own packs.

API

PackageManager

Method Description
install(id:zip:version:queue:installBlock:) Install a pack bundled in the app (zip is the resource name without extension).
install(id:path:version:queue:installBlock:) Install a pack from an arbitrary file path (e.g. downloaded at runtime).
uninstall(id:queue:uninstallBlock:) Remove an installed pack.
installed All installed packs.
packageWithId(_:) Look up an installed pack by id.

install is idempotent per version: replacing the zip without bumping version does not reinstall. It says so by calling back with PackageManagerError.versionAlreadyInstalled — the expected result on every launch after the first, not an error to abort on.

Translator

Method Description
setup(fromPackage:toPackage:) Load a language pair. Call again to switch pairs; loading is asynchronous and deduplicated. Translations requested right after it wait for the load — both run on the same serial queue — so there is nothing to await. Throws if the pack carries no model for the direction you asked for.
translateWithString(_:queue:translateBlock:) Translate a string. Result<String, Error> callback; an (String?, Error?) variant exists for Objective-C.
cancelCurrentTranslation() Cancel the in-flight translation at the next chunk boundary.
setBeamSize(_:) Decoder beam width. Default 2. 1 (greedy) is ~25% faster with near-identical quality — recommended on iPhone.
setChunkSize(_:) Sentences per inference batch. Default 4 — keeps cancellation responsive on mobile. On desktop set 0 (whole text in one batch) for up to 2× throughput on long texts.

translateWithString never reports a missing language pair. With no engine loaded — setup was not called, or it threw and you ignored the error — the text passes through untouched and arrives as .success. Handle the error from setup, and read "output identical to input" as "no model loaded", not as a translation.

Everything above is @objc and callable from Objective-C, except cancelCurrentTranslation(), which is Swift-only.

Memory guidance

Each loaded direction holds its model in memory. Mobile-sized packs like the Portuguese sample cost about 75 MB per direction (measured on an iPhone 12 simulator: 73 MB for the model, 210 MB for the whole app); our full-size packs cost around 330 MB. A non-English pair loads two models, so it doubles that. On devices with 4 GB RAM or less, prefer pairs involving English and unload by calling setup with .english → .english when the translation UI is dismissed.

Example

Example/ contains iOS and macOS demo apps. They ship without a language pack, so add one first:

  1. Download pt.zip (87 MB).
  2. Open Example/Example.xcodeproj and drag pt.zip into the project navigator.
  3. In the sheet Xcode shows, tick Copy items if needed and check the target you are going to run — Example-iOS, Example-macOS, or both.

Build and run — English ↔ Portuguese works immediately.

Example app, light appearance Example app, dark appearance

The apps install every .zip in their bundle and list what they find, so adding a second pack needs no code change: drop de.zip next to pt.zip and German appears in the pickers — including the non-English pairs, which the SDK pivots through English.

Getting more languages

Offline models are available for 110 languages. For a demo pack, pricing, or help picking the right model size for your app, write to info@lingvanex.com or visit lingvanex.com.

License

The SDK is released under the MIT license. Language packs are licensed separately — write to info@lingvanex.com.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages