swift 优雅地处理Swift中可本地化的字符串。注意:此代码在Swift 2中,需要在现代Swift中使用更新。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift 优雅地处理Swift中可本地化的字符串。注意:此代码在Swift 2中,需要在现代Swift中使用更新。相关的知识,希望对你有一定的参考价值。

//
//  LocalizableString.swift
//  Scoreboard
//
//  Created by Brent Royal-Gordon on 10/5/15.
//  Copyright © 2015 Architechies. All rights reserved.
//

import Foundation

public func localized(str: LocalizableString, withTable table: String? = nil, inBundle bundle: NSBundle = .mainBundle()) -> String {
    let format = str.formatString
    let localizedFormat = bundle.localizedStringForKey(format, value: format, table: table)
    return String(format: localizedFormat, arguments: str.formatArguments)
}

public extension CVarArgType {
    func formatted(string: String) -> LocalizableString {
        return LocalizableString(segments: [.Format (format: string, argument: self)])
    }
}

public struct LocalizableString {
    private enum Segment {
        case Literal (String)
        case Format (format: String, argument: CVarArgType)
        
        var format: String {
            switch self {
            case let .Literal(str):
                return str.stringByReplacingOccurrencesOfString("%", withString: "%%")
            case let .Format(format, _):
                return format
            }
        }
        
        var argument: CVarArgType? {
            if case let .Format(_, arg) = self {
                return arg
            }
            else {
                return nil
            }
        }
    }
    
    private var segments: [Segment]
    
    public init() {
        segments = []
    }
    
    private init(segments: [Segment]) {
        self.segments = segments
    }
    
    public init(_ string: String) {
        self.init(segments: [.Literal(string)])
    }
    
    public init(object: NSObject) {
        self.init(segments: [.Format(format: "%@", argument: object)])
    }
    
    public var formatString: String {
        return segments.map { $0.format }.reduce("", combine: +)
    }
    
    public var formatArguments: [CVarArgType] {
        return segments.map { $0.argument }.flatMap { $0 }
    }
}

extension LocalizableString: StringLiteralConvertible {
    public init(stringLiteral value: String) {
        self.init(value)
    }
    
    public init(unicodeScalarLiteral value: String) {
        self.init(value)
    }
    
    public init(extendedGraphemeClusterLiteral value: String) {
        self.init(value)
    }
}

extension LocalizableString: StringInterpolationConvertible {
    public init(stringInterpolation strings: LocalizableString...) {
        let fixedStrings = strings.enumerate().map { i, str -> LocalizableString in
            if i % 2 == 0 {
                // Evens are literals
                guard str.segments.count == 1, case let .Format (_, realStr) = str.segments.first! else {
                    fatalError("Interpolation sequence violation")
                }
                return LocalizableString(realStr as! String)
            }
            else {
                // Odds are interpolations
                return str
            }
        }
        self.init(segments: fixedStrings.flatMap { $0.segments })
    }
    
    public init<T>(stringInterpolationSegment expr: T) {
        switch expr {
        case let x as NSObject:
            self.init(object: x)
        case let x as String:
            self.init(object: x)
        case let x as LocalizableString:
            self.init(segments: x.segments)
        default:
            self.init(object: String(expr))
        }
    }
}

extension LocalizableString: CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
    public var description: String {
        return String(format: formatString, arguments: formatArguments)
    }
    
    public var debugDescription: String {
        return "localized(\"" + segments.map { $0.debugDescription }.reduce("", combine: +) + "\")"
    }
    
    public func customMirror() -> Mirror {
        return Mirror(self, children: ["formatString": formatString, "formatArguments": formatArguments])
    }
}

extension LocalizableString.Segment: CustomDebugStringConvertible {
    private var debugDescription: String {
        switch self {
        case let .Literal(str):
            return str.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
            
        case let .Format(format, argument):
            if format == "%@" {
                return "\\(" + String(reflecting: argument) + ")"
            }
            else {
                return "\\(" + String(reflecting: argument) + ".formatted(\"\(format)\"))"
            }
        }
    }
}

extension LocalizableString: Equatable {}

public func == (lhs: LocalizableString, rhs: LocalizableString) -> Bool {
    return lhs.formatString == rhs.formatString
}

public func += (inout lhs: LocalizableString, rhs: LocalizableString) {
    lhs.segments += rhs.segments
}

public func + (var lhs: LocalizableString, rhs: LocalizableString) -> LocalizableString {
    lhs += rhs
    return lhs
}
let color = "blue"
let num = 42

localized("Colorless green ideas sleep furiously.")
localized("Colorless \(color) ideas sleep furiously.")
localized("\(num.formatted("%05d")) colorless green ideas sleep furiously.")

以上是关于swift 优雅地处理Swift中可本地化的字符串。注意:此代码在Swift 2中,需要在现代Swift中使用更新。的主要内容,如果未能解决你的问题,请参考以下文章

阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON

如何在Swift中优雅地使用UIImage

Swift5.4 中可选的误报

Swift 中可选标识符中感叹号的含义? [复制]

如果在 swift 3.1 中可选绑定到 any 时如何使用 if let

为啥我们需要将 Swift 类标记为 `public` 或 `open` 以使其在 Objective-C 框架项目中可访问?