Skip to content

Commit

Permalink
Avoid type casting by using a type erasure
Browse files Browse the repository at this point in the history
  • Loading branch information
mattesmohr committed Nov 9, 2024
1 parent 7948b65 commit 9017033
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 46 deletions.
44 changes: 44 additions & 0 deletions Sources/HTMLKit/Framework/Localization/InterpolationArgument.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Foundation

/// An enum that represents the data types of arguments used in interpolation.
///
/// Each case corresponds to a specific data type and provides a placeholder
/// that can be used for replacing values in the localized string.
@_documentation(visibility: internal)
public enum InterpolationArgument {

/// Holds an integer value
case int(Int)

/// Holds a string value
case string(String)

/// Holds a double value
case double(Double)

/// Holds a float value
case float(Float)

/// Holds a date value
case date(Date)

/// The placeholder used for string interpolation
internal var placeholder: String {
switch self {
case .int(_):
return "%in"

case .string(_):
return "%st"

case .double(_):
return "%do"

case .float(_):
return "%do"

case .date(_):
return "%dt"
}
}
}
61 changes: 30 additions & 31 deletions Sources/HTMLKit/Framework/Localization/Localization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,52 +137,52 @@ public class Localization {
return localizationTables
}

/// Replace the value with the placeholder
///
/// - Parameters:
/// - placeholder: The placeholder to be replaced in
/// - value: The value to replace the placeholder with
/// - translation: The string in which the replacement will occur
private func replace(placeholder: String, with value: String, on translation: inout String) {

if let range = translation.range(of: placeholder) {
translation = translation.replacingCharacters(in: range, with: value)
}
}

/// Apply interpolation values to the translation for the given locale
///
/// - Parameters:
/// - arguments: An array of values used to replace placeholders within the translation string
/// - translation: The translation string
/// - locale: The locale
private func interpolate(arguments: [Any], to translation: inout String, for locale: Locale) {
/// - arguments: The arguments to replace the placeholders with
/// - translation: The string in which the interpolation will occur
/// - locale: The locale to respect during interpolation
private func interpolate(arguments: [InterpolationArgument], to translation: inout String, for locale: Locale) {

for argument in arguments {

switch argument {
case let stringValue as String:
case .int(let int):

if let range = translation.range(of: "%st") {
translation = translation.replacingCharacters(in: range, with: stringValue)
}
replace(placeholder: argument.placeholder, with: String(int), on: &translation)

case let dateValue as Date:
case .string(let string):

let formatter = DateFormatter()
formatter.dateFormat = locale.dateFormat
replace(placeholder: argument.placeholder, with: string, on: &translation)

if let range = translation.range(of: "%dt") {
translation = translation.replacingCharacters(in: range, with: formatter.string(from: dateValue))
}
case .double(let double):

case let doubleValue as Double:
replace(placeholder: argument.placeholder, with: String(double), on: &translation)

if let range = translation.range(of: "%do") {
translation = translation.replacingCharacters(in: range, with: String(doubleValue))
}
case .float(let float):

case let intValue as Int:

if let range = translation.range(of: "%in") {
translation = translation.replacingCharacters(in: range, with: String(intValue))
}
replace(placeholder: argument.placeholder, with: String(float), on: &translation)

case let floatValue as Float:
case .date(let date):

if let range = translation.range(of: "%do") {
translation = translation.replacingCharacters(in: range, with: String(floatValue))
}
let formatter = DateFormatter()
formatter.dateFormat = locale.dateFormat

default:
break
replace(placeholder: argument.placeholder, with: formatter.string(from: date), on: &translation)
}
}
}
Expand Down Expand Up @@ -243,4 +243,3 @@ public class Localization {
throw Errors.missingKey(string.key.value, currentLocale.tag)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Foundation
public struct LocalizedString: Content {

/// The key of the translation value
public let key: LocalizedStringKey
internal let key: LocalizedStringKey

/// The name of the translation table
internal let table: String?
Expand Down
38 changes: 24 additions & 14 deletions Sources/HTMLKit/Framework/Localization/LocalizedStringKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import Foundation
public struct LocalizedStringKey {

/// The actual key value
public let value: String
internal let value: String

/// The arguments for the interpolation
public var interpolation: [Any]?
internal var interpolation: [InterpolationArgument]?

/// Initializes a string key for localization
///
/// - Parameters:
/// - value: The key value
/// - interpolation: An array of values that will replace placeholders within the translation string.
public init(value: String, interpolation: [Any]? = nil) {
public init(value: String, interpolation: [InterpolationArgument]? = nil) {

self.value = value
self.interpolation = interpolation
Expand All @@ -35,7 +35,7 @@ extension LocalizedStringKey: ExpressibleByStringLiteral, ExpressibleByStringInt

var key: String = ""

var arguments: [Any] = []
var arguments: [InterpolationArgument] = []

public init(literalCapacity: Int, interpolationCount: Int) {

Expand All @@ -50,37 +50,47 @@ extension LocalizedStringKey: ExpressibleByStringLiteral, ExpressibleByStringInt

public mutating func appendInterpolation(_ value: String) {

key += "%st"
let argument = InterpolationArgument.string(value)

arguments.append(value)
key += argument.placeholder

arguments.append(argument)
}

public mutating func appendInterpolation(_ value: Int) {

key += "%in"
let argument = InterpolationArgument.int(value)

key += argument.placeholder

arguments.append(value)
arguments.append(argument)
}

public mutating func appendInterpolation(_ value: Double) {

key += "%do"
let argument = InterpolationArgument.double(value)

key += argument.placeholder

arguments.append(value)
arguments.append(argument)
}

public mutating func appendInterpolation(_ value: Float) {

key += "%do"
let argument = InterpolationArgument.float(value)

arguments.append(value)
key += argument.placeholder

arguments.append(.float(value))
}

public mutating func appendInterpolation(_ value: Date) {

key += "%dt"
let argument = InterpolationArgument.date(value)

key += argument.placeholder

arguments.append(value)
arguments.append(argument)
}
}
}

0 comments on commit 9017033

Please sign in to comment.