Translation Framework in Xojo
Since macOS 26 (and iOS 26) you can use the Translate framework to perform on-device translation services. You can use this with the upcoming MBS Xojo Plugins, currently in beta test.
One of the key things in the Translation framework is, that all functions are implemented by Apple to be asynchronously. They do not want to block the main thread with the user interface. For Xojo we implemented these with delegates. The plugin dispatches a task to run on a background thread to perform the asynchronous operation and then calls back to Xojo on the main thread via the delegate. This way anything taking longer would not block the main thread.
For simpler usability for the beginner developers, we have also synchronous versions of the calls. These wait (potentially long) for whatever operation needs to finish.
Available?
First you may check with the Available property on whether the translation services are available. This basically checks only for whether you have macOS or iOS in version 26.
Supported Languages
Next you could ask for the list of supported language. Currently this list contains: vi, pt, uk, it, zh-TW, ko, en-GB, de, zh, ja, id, nl, fr, th, es, tr, pl, ar-AE, ru, en, and hi. This list may change with future updates as Apple adds more languages. To query this list, we have two variants. First you can call SupportedLanguages and pass a delegate to get the answer later when available. Or you call the synchronous variant where the plugin waits for it and returns the answer right away:
Just because the language is supported, it may not yet be available or downloaded. For offline usage, the user needs to go to system preferences in the languages section and click download on a few language sets. You can call Status method with either the delegate for asynchronous answering or call our synchronous method to get the result with waiting. You pass the language identifiers and the framework will answer. The answer is a text with installed, supported, unsupported, unknown or an error. You get the value installed, if the local data is installed:
Start a session
Once you decided for a language pair to translate, you can call the Constructor and start a new TranslationSessionMBS. If the second language is empty, the system will pick the best available language from the list. Like if an user in Norway has Norwegian and English in their languages list, they will get English as Norwegian is unavailable.
The isReady function lets us check the status to make sure calling translate later doesn't raise an error. If ready, we can start translations.
Translations
Next you may want to translate. We have quick translateString function to return the translation directly like this:
Better may be to call the asynchronous version, which provides translations without blocking the main thread. Running the translation with the machine learning or LLM in the background may take a while for longer texts. Also we recommend to keep the session object around for multiple translations.
You can also translate a batch of texts:
- method translateBatch(Requests() as TranslationRequestMBS, completedOne as TranslateStringCompletedMBS, completed as TranslationsCompletedMBS, Tag as Variant = nil)
This will translate the requests and trigger the completedOne delegate if one of the texts is done and later trigger the completed delegate when all are done. This allows to update the GUI for each text to show them as quick as possible although the order is not guaranteed.
- method translateString(text as String) as TranslationResponseMBS
Translates one text and returns it after waiting for translation.
- method translateString(text as String, completed as TranslateStringCompletedMBS, Tag as Variant = nil)
Translates one text and calls delegate later when the translation is done.
- method translations(Requests() as TranslationRequestMBS) as TranslationResponseMBS()
This sends a batch of requests into the translation engine and returns the translations all at once back in order when the function finishes.
- method translations(Requests() as TranslationRequestMBS, completed as TranslationsCompletedMBS, Tag as Variant = nil)
Same, but calls the delegate after some time to report back the results.
Please try the new classes with Xojo on macOS and iOS 26 and see what you can do with automatic translation.