AzureCommunicationUI/sdk/AzureCommunicationUIChat/Sources/ChatCompositeOptions/BaseLocalizationProviderProtocol.swift (116 lines of code) (raw):

// // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // import Foundation protocol BaseLocalizationProviderProtocol { var isRightToLeft: Bool { get } func apply(localeConfig: LocalizationOptions) func getLocalizedString<Key: RawRepresentable>(_ key: Key) -> String where Key.RawValue == String func getLocalizedString<Key: RawRepresentable>(_ key: Key, _ args: CVarArg...) -> String where Key.RawValue == String } class BaseLocalizationProvider: BaseLocalizationProviderProtocol { private let logger: Logger private var languageIdentifier: String = "en" private var languageCode: String = "en" private var localizableFilename: String = "" private(set) var isRightToLeft = false private var bundle: Bundle var supportedLocales: [String] init(logger: Logger, bundleClass: AnyClass) { self.bundle = Bundle(for: bundleClass) self.supportedLocales = self.bundle.localizations self.logger = logger self.detectSystemLanguage() } func detectSystemLanguage() { guard let preferredLanguageId = Locale.preferredLanguages.first else { return } let preferredLanguageCode = removeRegionCode(preferredLanguageId) if self.isLanguageSupportedByApp(preferredLanguageId) { self.languageIdentifier = preferredLanguageId self.languageCode = preferredLanguageCode } else if self.isLanguageSupportedByApp(preferredLanguageCode) { self.languageIdentifier = preferredLanguageCode self.languageCode = preferredLanguageCode } else if let systemLanguageCode = Locale.current.languageCode, self.isLanguageSupportedByApp(systemLanguageCode) { self.languageIdentifier = systemLanguageCode self.languageCode = systemLanguageCode } } func apply(localeConfig: LocalizationOptions) { if !supportedLocales.contains(localeConfig.languageCode) { let warningMessage = "Locale not supported by default for " + "`\(localeConfig.languageCode)`, if string for AzureCommunicationUI " + "localization keys not provided in custom Localizable.strings " + "or customString, strings will default to `en`" logger.warning(warningMessage) } languageIdentifier = localeConfig.languageCode languageCode = removeRegionCode(localeConfig.languageCode) localizableFilename = localeConfig.localizableFilename isRightToLeft = localeConfig.layoutDirection == .rightToLeft } func getLocalizedString<Key>(_ key: Key) -> String where Key: RawRepresentable, Key.RawValue == String { if let path = Bundle.main .path(forResource: languageIdentifier, ofType: "lproj"), let bundle = Bundle(path: path) { let customLocalizableString = NSLocalizedString(key.rawValue, tableName: localizableFilename, bundle: bundle, value: "localize_key_not_found", comment: key.rawValue) if customLocalizableString != "localize_key_not_found" { return customLocalizableString } } return getPredefinedLocalizedString(key.rawValue) } func getLocalizedString<Key>(_ key: Key, _ args: CVarArg...) -> String where Key: RawRepresentable, Key.RawValue == String { let stringFormat = getLocalizedString(key) return String(format: stringFormat, arguments: args) } private func getPredefinedLocalizedString(_ key: String) -> String { if let predefinedTranslation = findPredefinedLocalizedString(languageIdentifier, key) { return predefinedTranslation } if let predefinedTranslation = findPredefinedLocalizedString(languageCode, key) { return predefinedTranslation } return NSLocalizedString(key, bundle: bundle, value: key, comment: key) } private func findPredefinedLocalizedString(_ languageCode: String, _ key: String) -> String? { guard let path = bundle.path(forResource: languageCode, ofType: "lproj") else { return nil } guard let bundle = Bundle(path: path) else { return nil } let predefinedTranslation = NSLocalizedString(key, bundle: bundle, value: "localize_key_not_found", comment: key) if predefinedTranslation != "localize_key_not_found" { return predefinedTranslation } return nil } private func removeRegionCode(_ languageId: String) -> String { let languageComponents = languageId .replacingOccurrences(of: "_", with: "-") .components(separatedBy: "-") return languageComponents.count == 1 ? languageId : languageComponents[..<(languageComponents.count - 1)] .joined(separator: "-") } private func isLanguageSupportedByApp(_ languageId: String) -> Bool { return Bundle.main.localizations.contains(languageId) } }