Publish your translations faster and simpler than ever before. Stop waiting for the next deployment and start publishing all your translations in real-time directly in Phrase Strings.
Head over to the Phrase Help Center to learn about this feature and how to use it in your apps: https://support.phrase.com/hc/en-us/articles/5804059067804
With the SDK, the app regularly checks for updated translations and downloads them in the background.
Mac Catalyst is also supported.
The SDK can be installed manually or via Swift Package Manager, Carthage or Cocoa Pods.
Example app
Add the public repository URL (https://github.com/phrase/ios-sdk/). Xcode automatically handles the rest of the installation.
Add the following line into your Cartfile:
binary "https://raw.githubusercontent.com/phrase/ios-sdk/master/PhraseSDK.json" ~> 5.0.0
Run carthage update --use-xcframeworks
and add the PhraseSDK.xcframework
to your project as described in the Carthage documentation.
Add the following line into your Podfile:
pod 'PhraseSDK'
Run pod install
. If new to CocoaPods, see their documentation.
- Download the latest release.
- Add
PhraseSDK.xcframework
in Xcode as the linked binary to the target.
- Import PhraseSDK
import PhraseSDK
- Initialize the SDK
Phrase.shared.setup(
distributionID: <Distribution ID>,
environmentSecret: <Environment Secret>
)
- Update translations
To update localization files call Phrase.shared.updateTranslation()
. This method will raises an exception if SDK is not correctly setup.
To configure OTA to use the US data center, set the host before calling PhraseApp.shared.updateTranslation()
with Phrase.shared.configuration.apiHost = .us.
Calling both functions within the AppDelegate
in the applicationDidFinishLaunchingWithOptions
method is recommended.
Integrate the SDK into the Objective-C application:
@import PhraseSDK;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[Phrase shared] setDebugMode:true]; // Optional
[[Phrase shared] setupWithDistributionID:@"Your Distribution ID"
environmentSecret:@"Your Environment Secret"];
// OR:
//
// [[Phrase shared] setupWithDistributionID:@"Your Distribution ID"
// environmentSecret:@"Your Environment Secret"
// timeout:10];
// Update translations using callback block:
[[Phrase shared] updateTranslationsWithCompletionHandler:^(BOOL updated, NSError* error){
NSLog(@"Updated: %@", updated ? @"true" : @"false");
if (error) {
NSLog(@"Domain: %@ Code: %ld Message: %@", error.domain, (long)error.code, error.localizedDescription);
} else {
NSLog(@"No error");
}
// Translate via bundle proxy:
NSString *translation = NSLocalizedString(@"layouts.application.about", @"");
NSLog(@"NSLocalizedString via bundle proxy: %@", translation);
// OR:
//
// Translate using fallback method:
NSString *otherTranslation = [[Phrase shared]
localizedStringForKey:@"layouts.application.about" value:NULL table:NULL];
NSLog(@"Phrase.shared localizedStringForKey: %@", otherTranslation);
}];
// OR:
//
// [[Phrase shared] updateTranslationsWithCompletionHandler:NULL]; // ignore result and errors (not recommended)
// [...] Your other code
return YES;
}
To disable swizzling, set PhraseSDKMainBundleProxyDisabled
to YES in the Info.plist
file.
When swizzling is disabled, updated translations are no longer be displayed. The translation will still be synced if updateTranslation
is called and can be accessed with the Phrase.localizedString()
method.
To determine which release should be returned the SDK requires a semantic version of the app so translations are updated.
The SDK attempts to get a semantic version the following way:
CFBundleShortVersionString
is used if semantic.- If not,
CFBundleVersion
is used if semantic. - If both are not semantic, a combination of (
CFBundleShortVersionString.CFBundleVersion
) is used.
If CFBundleShortVersionString
is missing or unable to be created with a semantic version together with CFBundleVersion
, the SDK throws the PhraseSetupError.appVersionNotSemantic
message.
To prevent OTA from translating any tables in the main iOS bundle other than the default Localizable
table, set the following option:
Phrase.shared.configuration.ignoreOtherTables = true
Attach a callback handler to handle successful translation updates:
do {
let updated = try await Phrase.shared.updateTranslation()
} catch error {
...
}
If further information is required, enable the debug mode to get additional logging of the PhraseSDK.framework
into the console:
Phrase.shared.configuration.debugMode = true
Set a timeout for the requests against Phrase by calling:
Phrase.shared.configuration.timeout = TimeInterval(20)
The default timeout is 10 seconds and connections taking longer than 10 seconds will be closed.
If not using the system language as the locale, a different locale can be set in the init call. The locale code needs to be present in a release from Phrase:
Phrase.shared.configuration.localeOverride = "en-US"
In case new translations cannot be fetched from Phrase via the SDK, the latest translation files that the installation received are used. If the App never received new files from Phrase, it uses the compiled translation files of app. This prevents errors in case of any technical difficulties or networking errors. Keeping your translation files that are compiled into the app up to date with every release is recommended.
If translations are not being updated:
- Ensure distribution id and environment secret are correct.
- Ensure a release was created on for the current app version.
If the wrong version of a translation is being used, ensure a release with the latest translations and the current app version is available.
The SDK is closed source and can not be viewed or modified. If it is an organization requirement, audits can be provided. Contact us for more details if required.
Here’s what you need to know before updating to SDK 5.x.x
:
- The minimum supported iOS version for SDK
5.x.x
is iOS 15.0. - SDK
5.x.x
requires Swift 6.0 or later.
In version 4.x.x
, the updateTranslation
function was implemented using a callback-based approach.
do {
try Phrase.shared.updateTranslation { result in
switch result {
case let .success(translationChanged):
if translationChanged {
logger.info("Translations changed")
} else {
logger.debug("Translations remain unchanged")
}
case let .failure(error):
logger.error("An error occurred: \(error)")
}
}
} catch {
logger.error("Unexpected error: \(error)")
}
In version 5.x.x
, this method has been updated to leverage Swift's modern concurrency model and is now implemented using async/await
.
Task {
do {
let updated = try await Phrase.shared.updateTranslation()
if updated {
logger.info("Translations changed")
} else {
logger.debug("Translations remain unchanged")
}
} catch {
logger.error("An error occurred: \(error)")
}
}