A Swift SDK for integrating Lingohub's over-the-air localization services in iOS applications. This SDK allows you to update your app's localizations without requiring a new app release.
- 🚀 Over-The-Air (OTA) localization updates
- 🔄 Runtime language switching
- 📱 Support for
.strings
and.stringsdict
files - đź› Method swizzling for seamless integration
- đź”’ Robust error handling
- 📝 Optional debug logging
- iOS 14.0+
Add the following dependency to your Package.swift
file:
dependencies: [
.package(url: "https://github.com/lingohub/ios-cdn-sdk.git", from: "1.0.0")
]
Or add it directly in Xcode via File > Add Packages > "https://github.com/lingohub/ios-cdn-sdk.git"
import Lingohub
Swift UI: Initialize in your main App
:
@main
struct YourApp: App {
@SwiftUI.Environment(\.scenePhase) private var scenePhase
init() {
// Configure the SDK with your API key
LingohubSDK.shared.configure(
withApiKey: "YOUR-API-KEY",
)
// Enable method swizzling for automatic localization
LingohubSDK.shared.swizzleMainBundle()
}
//...
}
For UIKit Initialize the SDK in your AppDelegate
or SceneDelegate
:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Configure the SDK with your API key
LingohubSDK.shared.configure(
withApiKey: "YOUR-API-KEY",
)
// Enable method swizzling for automatic localization
LingohubSDK.shared.swizzleMainBundle()
return true
}
For Swift UI add the following code to you main App
file:
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { oldPhase, newPhase in
if newPhase == .active {
// Check for updates when app becomes active
LingohubSDK.shared.update()
}
}
}
For UIKit add the following code where appropriate (e.g., when your app becomes active):
func applicationDidBecomeActive(_ application: UIApplication) {
Task {
LingohubSDK.shared.update()
}
}
Use NSLocalizedString as usual, LingohubSDK will take care of the rest:
NSLocalizedString("id", comment: "description of string")
Initialize the Lingohub SDK with optional parameters:
Parameter | Example Value | Description | Default |
---|---|---|---|
appVersion | "1.0.0" | The version of your app | Value from Info.plist |
environment | .production | Environment to use (.production, .staging, .development, .test) | .production |
logLevel | .none | Control debug logging output (.none or .full) | .none |
@main
struct YourApp: App {
@SwiftUI.Environment(\.scenePhase) private var scenePhase
init() {
// Configure the SDK with your API key
LingohubSDK.shared.configure(
withApiKey: "YOUR-API-KEY",
environment: .production,
logLevel: .full // Enable detailed logging (not recommmended for production)
)
// Enable method swizzling for automatic localization
LingohubSDK.shared.swizzleMainBundle()
}
//...
}
Change the app's language at runtime:
// Set to a specific language
LingohubSDK.shared.setLanguage("de")
Same optional parameters for UIKit in your AppDelegate
or SceneDelegate
:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Configure the SDK with your API key
LingohubSDK.shared.configure(
withApiKey: "YOUR-API-KEY",
environment: .production,
logLevel: .full // Enable detailed logging (not recommmended for production)
)
// Enable method swizzling for automatic localization
LingohubSDK.shared.swizzleMainBundle()
return true
}
If you prefer not to use method swizzling:
func getLocalizedString(for key: String, tableName: String? = nil) -> String {
if let localizedString = LingohubSDK.shared.localizedString(forKey: key, tableName: tableName) {
return localizedString
}
return NSLocalizedString(key, tableName: tableName, comment: "")
}
Get notified of localization updates via Observer:
NotificationCenter.default.addObserver(
forName: .LingohubDidUpdateLocalization,
object: nil,
queue: .main
) { [weak self] _ in
self?.updateUI()
}
Get notified via callback
LingohubSDK.shared.update { result in
switch result {
case .success(let value):
if value {
cacheManager.updateLastFetchTime()
}
}
}
Available environments:
- Production (
.production
): The default environment for released apps - Development (
.development
): For development and testing - Staging (
.staging
): For pre-production testing - Test (
.test
): For running automated tests
The SDK provides detailed error information through LingohubSDKError
:
LingohubSDK.shared.update { result in
switch result {
case .success(let updated):
// Handle successful update
case .failure(let error as LingohubSDKError):
switch error {
case .invalidApiKey:
print("API key is missing")
case .invalidAppVersion:
print("App version is missing")
case .invalidSdkVersion:
print("SDK version is missing")
case .apiError(let statusCode, let message):
print("API error: \(statusCode), \(message ?? "No message")")
case .unknown:
print("Unknown error occurred")
}
}
}
Optional caching is possible to reduce network requests, you can implement a simple CacheManager:
import Foundation
class CacheManager {
private let userDefaults = UserDefaults.standard
private let lastFetchKey = "last_fetch_time"
private let oneDayInSeconds: TimeInterval = 24 * 60 * 60
func shouldFetchStrings() -> Bool {
let lastFetchTime = userDefaults.double(forKey: lastFetchKey)
let currentTime = Date().timeIntervalSince1970
return currentTime - lastFetchTime >= oneDayInSeconds
}
func updateLastFetchTime() {
let currentTime = Date().timeIntervalSince1970
userDefaults.set(currentTime, forKey: lastFetchKey)
}
}
Then use it when checking for updates:
@main
struct YourApp: App {
@SwiftUI.Environment(\.scenePhase) private var scenePhase
private let cacheManager = CacheManager()
// ... existing init code ...
var body: some Scene {
WindowGroup {
//SwiftUI View
}
.onChange(of: scenePhase) { oldPhase, newPhase in
if newPhase == .active {
// Only fetch if needed
if cacheManager.shouldFetchStrings() {
LingohubSDK.shared.update { result in
switch result {
case .success(let value):
if value {
cacheManager.updateLastFetchTime()
}
}
}
}
}
}
}
}
For bug reports and feature requests, please open an issue on GitHub.
Apache License Version 2.0, January 2004. More infos in the LICENSE
file.