Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change localization interpolation #161

Merged
merged 5 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions Sources/HTMLKit/Abstraction/Elements/BodyElements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1720,8 +1720,8 @@ extension Heading1: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute

extension Heading1: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -1997,8 +1997,8 @@ extension Heading2: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute

extension Heading2: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -2274,8 +2274,8 @@ extension Heading3: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute

extension Heading3: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -2551,8 +2551,8 @@ extension Heading4: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute

extension Heading4: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -2828,8 +2828,8 @@ extension Heading5: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute

extension Heading5: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -3105,8 +3105,8 @@ extension Heading6: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribute

extension Heading6: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -4462,8 +4462,8 @@ extension Paragraph: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribut

extension Paragraph: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -5278,8 +5278,8 @@ extension Blockquote: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribu

extension Blockquote: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -6857,8 +6857,8 @@ extension Anchor: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes,

extension Anchor: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -7674,8 +7674,8 @@ extension Small: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes {

extension Small: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -7875,8 +7875,8 @@ extension StrikeThrough: GlobalAttributes, GlobalEventAttributes {

extension StrikeThrough: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -12387,8 +12387,8 @@ extension Italic: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes

extension Italic: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -12664,8 +12664,8 @@ extension Bold: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes {

extension Bold: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -12941,8 +12941,8 @@ extension Underline: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribut

extension Underline: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/HTMLKit/Abstraction/Elements/FormElements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,8 @@ extension Label: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes,

extension Label: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down Expand Up @@ -1524,8 +1524,8 @@ extension Button: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttributes,

extension Button: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/HTMLKit/Abstraction/Elements/TableElements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2428,7 +2428,7 @@ extension HeaderCell: GlobalAttributes, GlobalEventAttributes, GlobalAriaAttribu

extension HeaderCell: Localizable {

public init(_ localizedKey: String, tableName: String? = nil, interpolation: Any...) {
self.content = [LocalizedStringKey(key: localizedKey, table: tableName, interpolation: interpolation)]
public init(_ localizedKey: LocalizedStringKey, tableName: String? = nil) {
self.content = [LocalizedString(key: localizedKey, table: tableName)]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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 "%lld"

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

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

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

case .date(_):
return "%@"
}
}
}
3 changes: 1 addition & 2 deletions Sources/HTMLKit/Framework/Localization/Localizable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ public protocol Localizable {
/// - Parameters:
/// - localizedKey: The string key to be translated
/// - tableName: The name of the translation table
/// - interpolation: A variadic list of values used to replace placeholders within the translation string
init(_ localizedKey: String, tableName: String?, interpolation: Any...)
init(_ localizedKey: LocalizedStringKey, tableName: String?)
}
73 changes: 39 additions & 34 deletions Sources/HTMLKit/Framework/Localization/Localization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,46 +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:
replace(placeholder: argument.placeholder, with: String(float), on: &translation)

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

default:
break
let formatter = DateFormatter()
formatter.dateFormat = locale.dateFormat

replace(placeholder: argument.placeholder, with: formatter.string(from: date), on: &translation)
}
}
}
Expand All @@ -188,7 +194,7 @@ public class Localization {
/// - locale: The locale to use when retrieving the translation
///
/// - Returns: The translation
public func localize(key: LocalizedStringKey, for locale: Locale? = nil) throws -> String {
public func localize(string: LocalizedString, for locale: Locale? = nil) throws -> String {

guard let fallback = self.locale else {
throw Errors.noFallback
Expand All @@ -204,17 +210,17 @@ public class Localization {
throw Errors.missingTable(currentLocale.tag)
}

if let table = key.table {
if let table = string.table {

guard let translationTable = translationTables.first(where: { $0.name == table }) else {
throw Errors.unknownTable(table, currentLocale.tag)
}

guard var translation = translationTable.retrieve(for: key.key) else {
throw Errors.missingKey(key.key, currentLocale.tag)
guard var translation = translationTable.retrieve(for: string.key.value) else {
throw Errors.missingKey(string.key.value, currentLocale.tag)
}

if let interpolation = key.interpolation {
if let interpolation = string.key.interpolation {
interpolate(arguments: interpolation, to: &translation, for: currentLocale)
}

Expand All @@ -224,17 +230,16 @@ public class Localization {

for translationTable in translationTables {

if var translation = translationTable.retrieve(for: key.key) {
if var translation = translationTable.retrieve(for: string.key.value) {

if let interpolation = key.interpolation {
if let interpolation = string.key.interpolation {
interpolate(arguments: interpolation, to: &translation, for: currentLocale)
}

return translation
}
}

throw Errors.missingKey(key.key, currentLocale.tag)
throw Errors.missingKey(string.key.value, currentLocale.tag)
}
}

23 changes: 23 additions & 0 deletions Sources/HTMLKit/Framework/Localization/LocalizedString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Foundation

/// A type thats holds the information for the localization
@_documentation(visibility: internal)
public struct LocalizedString: Content {

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

/// The name of the translation table
internal let table: String?

/// Initializes a localized string with context
///
/// - Parameters:
/// - key: The string key to be translated
/// - table: The table where the string key should be looked up. Default is nil.
public init(key: LocalizedStringKey, table: String? = nil) {

self.key = key
self.table = table
}
}
Loading
Loading