Swiftgram/submodules/SyncCore/Sources/Localization.swift
2019-11-01 17:11:12 +04:00

221 lines
8.5 KiB
Swift

import Foundation
import Postbox
public enum LocalizationEntry: Equatable {
case string(key: String, value: String)
case pluralizedString(key: String, zero: String?, one: String?, two: String?, few: String?, many: String?, other: String)
public var key: String {
switch self {
case let .string(key, _):
return key
case let .pluralizedString(key, _, _, _, _, _, _):
return key
}
}
}
private struct LocalizationEntryFlags: OptionSet {
var rawValue: Int8
init(rawValue: Int8) {
self.rawValue = rawValue
}
init() {
self.rawValue = 0
}
static let pluralized = LocalizationEntryFlags(rawValue: (1 << 0))
static let hasZero = LocalizationEntryFlags(rawValue: (1 << 1))
static let hasOne = LocalizationEntryFlags(rawValue: (1 << 2))
static let hasTwo = LocalizationEntryFlags(rawValue: (1 << 3))
static let hasFew = LocalizationEntryFlags(rawValue: (1 << 4))
static let hasMany = LocalizationEntryFlags(rawValue: (1 << 5))
}
private func writeString(_ buffer: WriteBuffer, _ string: String) {
if let data = string.data(using: .utf8) {
var length: Int32 = Int32(data.count)
buffer.write(&length, offset: 0, length: 4)
buffer.write(data)
} else {
var length: Int32 = 0
buffer.write(&length, offset: 0, length: 4)
}
}
public final class Localization: PostboxCoding, Equatable {
public let version: Int32
public let entries: [LocalizationEntry]
public init(version: Int32, entries: [LocalizationEntry]) {
self.version = version
self.entries = entries
}
public init(decoder: PostboxDecoder) {
self.version = decoder.decodeInt32ForKey("v", orElse: 0)
let count = decoder.decodeInt32ForKey("c", orElse: 0)
var entries: [LocalizationEntry] = []
if let data = decoder.decodeBytesForKey("d") {
for _ in 0 ..< count {
var flagsValue: Int8 = 0
data.read(&flagsValue, offset: 0, length: 1)
let flags = LocalizationEntryFlags(rawValue: flagsValue)
var length: Int32 = 0
data.read(&length, offset: 0, length: 4)
let keyData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let key = String(data: keyData, encoding: .utf8)
data.skip(Int(length))
if flags.contains(.pluralized) {
var zero: String?
var one: String?
var two: String?
var few: String?
var many: String?
var other: String?
if flags.contains(.hasZero) {
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
zero = value
}
if flags.contains(.hasOne) {
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
one = value
}
if flags.contains(.hasTwo) {
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
two = value
}
if flags.contains(.hasFew) {
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
few = value
}
if flags.contains(.hasMany) {
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
many = value
}
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
other = value
if let key = key, let other = other {
entries.append(.pluralizedString(key: key, zero: zero, one: one, two: two, few: few, many: many, other: other))
}
} else {
length = 0
data.read(&length, offset: 0, length: 4)
let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length))
let value = String(data: valueData, encoding: .utf8)
data.skip(Int(length))
if let key = key, let value = value {
entries.append(.string(key: key, value: value))
}
}
}
}
self.entries = entries
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.version, forKey: "v")
encoder.encodeInt32(Int32(self.entries.count), forKey: "c")
let buffer = WriteBuffer()
for entry in self.entries {
var flags: LocalizationEntryFlags = []
switch entry {
case .string:
flags = []
case let .pluralizedString(_, zero, one, two, few, many, _):
flags.insert(.pluralized)
if zero != nil {
flags.insert(.hasZero)
}
if one != nil {
flags.insert(.hasOne)
}
if two != nil {
flags.insert(.hasTwo)
}
if few != nil {
flags.insert(.hasFew)
}
if many != nil {
flags.insert(.hasMany)
}
}
var flagsValue: Int8 = flags.rawValue
buffer.write(&flagsValue, offset: 0, length: 1)
switch entry {
case let .string(key, value):
writeString(buffer, key)
writeString(buffer, value)
case let .pluralizedString(key, zero, one, two, few, many, other):
writeString(buffer, key)
if let zero = zero {
writeString(buffer, zero)
}
if let one = one {
writeString(buffer, one)
}
if let two = two {
writeString(buffer, two)
}
if let few = few {
writeString(buffer, few)
}
if let many = many {
writeString(buffer, many)
}
writeString(buffer, other)
}
}
encoder.encodeBytes(buffer, forKey: "d")
}
public static func ==(lhs: Localization, rhs: Localization) -> Bool {
if lhs === rhs {
return true
}
if lhs.entries == rhs.entries {
return true
}
return false
}
}