import Foundation #if os(macOS) import PostboxMac import SwiftSignalKitMac #else import Postbox import SwiftSignalKit #endif //config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int revoke_pm_inbox:flags.6?true rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int phonecalls_enabled:flags.1?true call_receive_timeout_ms:int preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int default_p2p_contacts:flags.3?true me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config; public func 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 suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map { Optional($0) } } else { return .single(nil) } } } } public func suggestedLocalizationInfo(network: Network, languageCode: String, extractKeys: [String]) -> Signal { return combineLatest(network.request(Api.functions.langpack.getLanguages()), network.request(Api.functions.langpack.getStrings(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: "")) } } var infos: [LocalizationInfo] = [] for language in languages { switch language { case let .langPackLanguage(name, nativeName, langCode): infos.append(LocalizationInfo(languageCode: langCode, title: name, localizedTitle: nativeName)) } } return SuggestedLocalizationInfo(languageCode: languageCode, extractedEntries: entries, availableLocalizations: infos) } } final class CachedLocalizationInfos: PostboxCoding { let list: [LocalizationInfo] init(list: [LocalizationInfo]) { self.list = list } init(decoder: PostboxDecoder) { self.list = decoder.decodeObjectArrayWithDecoderForKey("l") } func encode(_ encoder: PostboxEncoder) { encoder.encodeObjectArray(self.list, forKey: "l") } } public func availableLocalizations(postbox: Postbox, network: Network, allowCached: Bool) -> Signal<[LocalizationInfo], NoError> { let cached: Signal<[LocalizationInfo], NoError> if allowCached { cached = postbox.modify { modifier -> Signal<[LocalizationInfo], NoError> in if let entry = modifier.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0))) as? CachedLocalizationInfos { return .single(entry.list) } return .complete() } |> switchToLatest } else { cached = .complete() } let remote = network.request(Api.functions.langpack.getLanguages()) |> retryRequest |> mapToSignal { languages -> Signal<[LocalizationInfo], NoError> in var infos: [LocalizationInfo] = [] for language in languages { switch language { case let .langPackLanguage(name, nativeName, langCode): infos.append(LocalizationInfo(languageCode: langCode, title: name, localizedTitle: nativeName)) } } return postbox.modify { modifier -> [LocalizationInfo] in modifier.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: CachedLocalizationInfos(list: infos), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) return infos } } return cached |> then(remote) } public func downloadLocalization(network: Network, languageCode: String) -> Signal { return network.request(Api.functions.langpack.getLangPack(langCode: languageCode)) |> retryRequest |> 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 func downoadAndApplyLocalization(postbox: Postbox, network: Network, languageCode: String) -> Signal { return downloadLocalization(network: network, languageCode: languageCode) |> mapToSignal { language -> Signal in return postbox.modify { modifier -> Signal in modifier.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in return LocalizationSettings(languageCode: languageCode, localization: language) }) network.context.updateApiEnvironment { current in return current?.withUpdatedLangPackCode(languageCode) } return network.request(Api.functions.help.test()) |> `catch` { _ -> Signal in return .complete() } |> mapToSignal { _ -> Signal in return .complete() } } |> switchToLatest } }