import Foundation import Postbox import TelegramApi import SwiftSignalKit func _internal_currentlySuggestedLocalization(network: Network, extractKeys: [String]) -> Signal { return network.request(Api.functions.help.getConfig()) |> retryRequest |> mapToSignal { result -> Signal in switch result { case let .config(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, suggestedLangCode, _, _): if let suggestedLangCode = suggestedLangCode { return _internal_suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map(Optional.init) } else { return .single(nil) } } } } func _internal_suggestedLocalizationInfo(network: Network, languageCode: String, extractKeys: [String]) -> Signal { return combineLatest(network.request(Api.functions.langpack.getLanguages(langPack: "")), network.request(Api.functions.langpack.getStrings(langPack: "", langCode: languageCode, keys: extractKeys))) |> retryRequest |> map { languages, strings -> SuggestedLocalizationInfo in var entries: [LocalizationEntry] = [] for string in strings { switch string { case let .langPackString(key, value): entries.append(.string(key: key, value: value)) case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue): entries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue)) case let .langPackStringDeleted(key): entries.append(.string(key: key, value: "")) } } let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:)) return SuggestedLocalizationInfo(languageCode: languageCode, extractedEntries: entries, availableLocalizations: infos) } } func _internal_availableLocalizations(postbox: Postbox, network: Network, allowCached: Bool) -> Signal<[LocalizationInfo], NoError> { let cached: Signal<[LocalizationInfo], NoError> if allowCached { cached = postbox.transaction { transaction -> Signal<[LocalizationInfo], NoError> in if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)))?.get(CachedLocalizationInfos.self) { return .single(entry.list) } return .complete() } |> switchToLatest } else { cached = .complete() } let remote = network.request(Api.functions.langpack.getLanguages(langPack: "")) |> retryRequest |> mapToSignal { languages -> Signal<[LocalizationInfo], NoError> in let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:)) return postbox.transaction { transaction -> [LocalizationInfo] in if let entry = CodableEntry(CachedLocalizationInfos(list: infos)) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: entry) } return infos } } return cached |> then(remote) } public enum DownloadLocalizationError { case generic } func _internal_downloadLocalization(network: Network, languageCode: String) -> Signal { return network.request(Api.functions.langpack.getLangPack(langPack: "", langCode: languageCode)) |> mapError { _ -> DownloadLocalizationError in return .generic } |> map { result -> Localization in let version: Int32 var entries: [LocalizationEntry] = [] switch result { case let .langPackDifference(_, _, versionValue, strings): version = versionValue for string in strings { switch string { case let .langPackString(key, value): entries.append(.string(key: key, value: value)) case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue): entries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue)) case let .langPackStringDeleted(key): entries.append(.string(key: key, value: "")) } } } return Localization(version: version, entries: entries) } } public enum DownloadAndApplyLocalizationError { case generic } func _internal_downloadAndApplyLocalization(accountManager: AccountManager, postbox: Postbox, network: Network, languageCode: String) -> Signal { return _internal_requestLocalizationPreview(network: network, identifier: languageCode) |> mapError { _ -> DownloadAndApplyLocalizationError in return .generic } |> mapToSignal { preview -> Signal in var primaryAndSecondaryLocalizations: [Signal] = [] primaryAndSecondaryLocalizations.append(_internal_downloadLocalization(network: network, languageCode: preview.languageCode)) if let secondaryCode = preview.baseLanguageCode { primaryAndSecondaryLocalizations.append(_internal_downloadLocalization(network: network, languageCode: secondaryCode)) } return combineLatest(primaryAndSecondaryLocalizations) |> mapError { _ -> DownloadAndApplyLocalizationError in return .generic } |> mapToSignal { components -> Signal in guard let primaryLocalization = components.first else { return .fail(.generic) } var secondaryComponent: LocalizationComponent? if let secondaryCode = preview.baseLanguageCode, components.count > 1 { secondaryComponent = LocalizationComponent(languageCode: secondaryCode, localizedName: "", localization: components[1], customPluralizationCode: nil) } return accountManager.transaction { transaction -> Signal in transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in return PreferencesEntry(LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: preview.languageCode, localizedName: preview.localizedTitle, localization: primaryLocalization, customPluralizationCode: preview.customPluralizationCode), secondaryComponent: secondaryComponent)) }) return postbox.transaction { transaction -> Signal in updateLocalizationListStateInteractively(transaction: transaction, { state in var state = state for i in 0 ..< state.availableSavedLocalizations.count { if state.availableSavedLocalizations[i].languageCode == preview.languageCode { state.availableSavedLocalizations.remove(at: i) break } } state.availableSavedLocalizations.insert(preview, at: 0) return state }) network.context.updateApiEnvironment { current in return current?.withUpdatedLangPackCode(preview.languageCode) } return network.request(Api.functions.help.test()) |> `catch` { _ -> Signal in return .complete() } |> mapToSignal { _ -> Signal in return .complete() } |> castError(DownloadAndApplyLocalizationError.self) } |> castError(DownloadAndApplyLocalizationError.self) |> switchToLatest } |> castError(DownloadAndApplyLocalizationError.self) |> switchToLatest } } }